diff --git a/packages/core/src/data_sources/model/DataSource.ts b/packages/core/src/data_sources/model/DataSource.ts index a2e937285..4e816f429 100644 --- a/packages/core/src/data_sources/model/DataSource.ts +++ b/packages/core/src/data_sources/model/DataSource.ts @@ -38,7 +38,15 @@ import { SetOptions, } from '../../common'; import EditorModel from '../../editor/model/Editor'; -import { DataSourceTransformers, DataSourceType, DataSourceProps, DataRecordProps } from '../types'; +import { + DataFieldPrimitiveType, + DataFieldSchemaRelation, + DataRecordProps, + DataSourceProps, + DataSourceTransformers, + DataSourceType, +} from '../types'; +import { DEF_DATA_FIELD_ID } from '../utils'; import DataRecord from './DataRecord'; import DataRecords from './DataRecords'; import DataSources from './DataSources'; @@ -153,8 +161,8 @@ export default class DataSource | undefined} The data record, or `undefined` if no record is found with the given ID. * @name getRecord */ - getRecord(id: string | number) { - return this.records.get(id) as DataRecord | undefined; + getRecord(id: string | number): DataRecord | undefined { + return this.records.get(id); } /** @@ -168,6 +176,41 @@ export default class DataSource this.getRecord(record.id)!); } + /** + * Retrieves all records from the data source with resolved relations based on the schema. + */ + getResolvedRecords() { + const schemaEntries = Object.entries(this.schema); + const records = this.getRecords().map((record) => { + const result = { ...record.attributes }; + + if (schemaEntries.length === 0) return result; + + schemaEntries.forEach(([fieldName, schema]) => { + const fieldSchema = schema as DataFieldSchemaRelation; + if (fieldSchema?.type === DataFieldPrimitiveType.relation && fieldSchema.target) { + const relationValue = result[fieldName]; + + if (relationValue) { + const targetDs = this.em.DataSources.get(fieldSchema.target); + if (targetDs) { + const targetField = fieldSchema.targetField || DEF_DATA_FIELD_ID; + const relatedRecord = targetDs.records.find((r) => r.attributes[targetField] === relationValue); + + if (relatedRecord) { + result[fieldName] = relatedRecord.attributes; + } + } + } + } + }); + + return result; + }); + + return records; + } + /** * Removes a record from the data source by its ID. * diff --git a/packages/core/src/data_sources/utils.ts b/packages/core/src/data_sources/utils.ts index 583309245..005b2075f 100644 --- a/packages/core/src/data_sources/utils.ts +++ b/packages/core/src/data_sources/utils.ts @@ -10,6 +10,8 @@ import { DataConditionIfFalseType, DataConditionIfTrueType } from './model/condi import { getSymbolMain } from '../dom_components/model/SymbolUtils'; import Component from '../dom_components/model/Component'; +export const DEF_DATA_FIELD_ID = 'id'; + export function isDataResolverProps(value: any): value is DataResolverProps { return typeof value === 'object' && [DataVariableType, DataConditionType].includes(value?.type); } diff --git a/packages/core/test/specs/data_sources/model/DataSource.ts b/packages/core/test/specs/data_sources/model/DataSource.ts index f43e10ff8..0dc2c01ca 100644 --- a/packages/core/test/specs/data_sources/model/DataSource.ts +++ b/packages/core/test/specs/data_sources/model/DataSource.ts @@ -85,17 +85,17 @@ describe('DataSource', () => { describe('Relations', () => { const categoryRecords = [ - { id: 'cat1', name: 'Category 1' }, - { id: 'cat2', name: 'Category 2' }, + { id: 'cat1', uid: 'cat1-uid', name: 'Category 1' }, + { id: 'cat2', uid: 'cat2-uid', name: 'Category 2' }, ]; const userRecords = [ { id: 'user1', username: 'user_one' }, { id: 'user2', username: 'user_two' }, ]; const blogRecords = [ - { id: 'blog1', title: 'First Blog', author: 'user1', categories: ['cat1'] }, + { id: 'blog1', title: 'First Blog', author: 'user1', categories: ['cat1-uid'] }, { id: 'blog2', title: 'Second Blog', author: 'user2' }, - { id: 'blog3', title: 'Third Blog', categories: ['cat1', 'cat2'] }, + { id: 'blog3', title: 'Third Blog', categories: ['cat1-uid', 'cat2-uid'] }, ]; beforeEach(() => { @@ -128,9 +128,9 @@ describe('DataSource', () => { expect(serializeRecords(blogsDS.getRecords())).toEqual(blogRecords); }); - test('return resolved values', () => { + test('return 1:1 resolved values', () => { const blogsDS = dsm.get('blogs'); - const records = blogsDS.getRecords({ resolveRelations: true }); + const records = blogsDS.getResolvedRecords(); expect(records).toEqual([ { ...blogRecords[0], author: userRecords[0] }, { ...blogRecords[1], author: userRecords[1] },