fix(server): convert date and timestamp value to Date instance (#12867)

#### PR Dependency Tree


* **PR #12867** 👈
  * **PR #12863**
    * **PR #12837**
    * **PR #12866**

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Date fields in search results are now returned as JavaScript Date
objects instead of strings or numeric timestamps.
- **Bug Fixes**
- Improved consistency and correctness of date field types across
different search providers.
- **Tests**
- Added tests to verify that date fields are correctly returned as Date
objects.
- Updated existing test snapshots to reflect the new Date object format
for date fields.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
fengmk2
2025-06-20 17:21:29 +08:00
committed by GitHub
parent 13b64c6780
commit bebe4349a9
9 changed files with 153 additions and 15 deletions
@@ -5,7 +5,7 @@ import {
InvalidSearchProviderRequest,
} from '../../../base';
import { SearchProviderType } from '../config';
import { SearchTable, SearchTableUniqueId } from '../tables';
import { DateFieldNames, SearchTable, SearchTableUniqueId } from '../tables';
import {
AggregateQueryDSL,
AggregateResult,
@@ -161,8 +161,8 @@ export class ElasticsearchProvider extends SearchProvider {
nodes: data.hits.hits.map(hit => ({
_id: hit._id,
_score: hit._score,
_source: hit._source,
fields: hit.fields,
_source: this.formatDateFields(hit._source),
fields: this.formatDateFields(hit.fields),
highlights: hit.highlight,
})),
};
@@ -187,8 +187,8 @@ export class ElasticsearchProvider extends SearchProvider {
nodes: bucket.result.hits.hits.map(hit => ({
_id: hit._id,
_score: hit._score,
_source: hit._source,
fields: hit.fields,
_source: this.formatDateFields(hit._source),
fields: this.formatDateFields(hit.fields),
highlights: hit.highlight,
})),
},
@@ -196,6 +196,37 @@ export class ElasticsearchProvider extends SearchProvider {
};
}
protected formatDateFields<T extends Record<string, unknown[] | unknown>>(
fieldsOrSource: T
): T {
for (const fieldName of DateFieldNames) {
let values = fieldsOrSource[fieldName];
if (!values) {
continue;
}
if (Array.isArray(values)) {
// { created_at: ['2025-06-20T03:02:43.442Z'] } => { created_at: [new Date('2025-06-20T03:02:43.442Z')] }
values = values.map(this.formatDateValue);
} else {
// { created_at: '2025-06-20T03:02:43.442Z' } => { created_at: new Date('2025-06-20T03:02:43.442Z') }
values = this.formatDateValue(values);
}
// @ts-expect-error ignore type check
fieldsOrSource[fieldName] = values;
}
return fieldsOrSource;
}
/**
* elasticsearch return date value as string, we need to convert it to Date object
*/
protected formatDateValue(value: unknown) {
if (value && typeof value === 'string') {
return new Date(value);
}
return value;
}
protected async requestSearch(table: SearchTable, body: Record<string, any>) {
const url = `${this.config.provider.endpoint}/${table}/_search`;
const jsonBody = JSON.stringify(body);