@declaro/data 2.0.0-beta.115 → 2.0.0-beta.117
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.js +14 -14
- package/dist/browser/index.js.map +6 -6
- package/dist/node/index.cjs +66 -70
- package/dist/node/index.cjs.map +6 -6
- package/dist/node/index.js +66 -70
- package/dist/node/index.js.map +6 -6
- package/dist/ts/domain/events/event-types.d.ts +4 -0
- package/dist/ts/domain/events/event-types.d.ts.map +1 -1
- package/dist/ts/domain/services/base-model-service.d.ts +1 -0
- package/dist/ts/domain/services/base-model-service.d.ts.map +1 -1
- package/dist/ts/domain/services/model-service.d.ts +6 -2
- package/dist/ts/domain/services/model-service.d.ts.map +1 -1
- package/dist/ts/domain/services/model-service.normalization.test.d.ts +2 -0
- package/dist/ts/domain/services/model-service.normalization.test.d.ts.map +1 -0
- package/dist/ts/domain/services/read-only-model-service.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/domain/events/event-types.ts +4 -0
- package/src/domain/services/base-model-service.ts +4 -0
- package/src/domain/services/model-service.normalization.test.ts +704 -0
- package/src/domain/services/model-service.test.ts +2 -390
- package/src/domain/services/model-service.ts +91 -91
- package/src/domain/services/read-only-model-service.test.ts +42 -6
- package/src/domain/services/read-only-model-service.ts +0 -19
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AnyModelSchema } from '@declaro/core'
|
|
1
|
+
import type { ActionDescriptor, AnyModelSchema, IActionDescriptor } from '@declaro/core'
|
|
2
2
|
import type { InferDetail, InferInput, InferLookup, InferSummary } from '../../shared/utils/schema-inference'
|
|
3
3
|
import { ModelMutationAction, ModelQueryEvent } from '../events/event-types'
|
|
4
4
|
import { MutationEvent } from '../events/mutation-event'
|
|
@@ -9,6 +9,11 @@ import type { IActionOptions } from './base-model-service'
|
|
|
9
9
|
export interface ICreateOptions extends IActionOptions {}
|
|
10
10
|
export interface IUpdateOptions extends IActionOptions {}
|
|
11
11
|
|
|
12
|
+
export interface INormalizeInputArgs<TSchema extends AnyModelSchema> {
|
|
13
|
+
existing?: InferDetail<TSchema>
|
|
14
|
+
descriptor: ActionDescriptor
|
|
15
|
+
}
|
|
16
|
+
|
|
12
17
|
export class ModelService<TSchema extends AnyModelSchema> extends ReadOnlyModelService<TSchema> {
|
|
13
18
|
constructor(args: IModelServiceArgs<TSchema>) {
|
|
14
19
|
super(args)
|
|
@@ -21,7 +26,10 @@ export class ModelService<TSchema extends AnyModelSchema> extends ReadOnlyModelS
|
|
|
21
26
|
* @param input The input data to normalize.
|
|
22
27
|
* @returns The normalized input data.
|
|
23
28
|
*/
|
|
24
|
-
protected async normalizeInput(
|
|
29
|
+
protected async normalizeInput(
|
|
30
|
+
input: InferInput<TSchema>,
|
|
31
|
+
args: INormalizeInputArgs<TSchema>,
|
|
32
|
+
): Promise<InferInput<TSchema>> {
|
|
25
33
|
return input
|
|
26
34
|
}
|
|
27
35
|
|
|
@@ -82,7 +90,9 @@ export class ModelService<TSchema extends AnyModelSchema> extends ReadOnlyModelS
|
|
|
82
90
|
|
|
83
91
|
async create(input: InferInput<TSchema>, options?: ICreateOptions): Promise<InferDetail<TSchema>> {
|
|
84
92
|
// Normalize the input data
|
|
85
|
-
const normalizedInput = await this.normalizeInput(input
|
|
93
|
+
const normalizedInput = await this.normalizeInput(input, {
|
|
94
|
+
descriptor: this.getDescriptor(ModelMutationAction.Create),
|
|
95
|
+
})
|
|
86
96
|
|
|
87
97
|
// Emit the before create event
|
|
88
98
|
const beforeCreateEvent = new MutationEvent<InferDetail<TSchema>, InferInput<TSchema>>(
|
|
@@ -110,8 +120,12 @@ export class ModelService<TSchema extends AnyModelSchema> extends ReadOnlyModelS
|
|
|
110
120
|
input: InferInput<TSchema>,
|
|
111
121
|
options?: IUpdateOptions,
|
|
112
122
|
): Promise<InferDetail<TSchema>> {
|
|
123
|
+
const existing = await this.repository.load(lookup, options)
|
|
113
124
|
// Normalize the input data
|
|
114
|
-
const normalizedInput = await this.normalizeInput(input
|
|
125
|
+
const normalizedInput = await this.normalizeInput(input, {
|
|
126
|
+
existing,
|
|
127
|
+
descriptor: this.getDescriptor(ModelMutationAction.Update),
|
|
128
|
+
})
|
|
115
129
|
|
|
116
130
|
// Emit the before update event
|
|
117
131
|
const beforeUpdateEvent = new MutationEvent<InferDetail<TSchema>, InferInput<TSchema>>(
|
|
@@ -141,19 +155,19 @@ export class ModelService<TSchema extends AnyModelSchema> extends ReadOnlyModelS
|
|
|
141
155
|
* @returns The upserted record.
|
|
142
156
|
*/
|
|
143
157
|
async upsert(input: InferInput<TSchema>, options?: ICreateOptions | IUpdateOptions): Promise<InferDetail<TSchema>> {
|
|
144
|
-
|
|
145
|
-
const normalizedInput = await this.normalizeInput(input)
|
|
146
|
-
|
|
147
|
-
const primaryKeyValue = this.getPrimaryKeyValue(normalizedInput)
|
|
158
|
+
const primaryKeyValue = this.getPrimaryKeyValue(input)
|
|
148
159
|
|
|
160
|
+
let operation: ModelMutationAction
|
|
149
161
|
let beforeOperation: ModelMutationAction
|
|
150
162
|
let afterOperation: ModelMutationAction
|
|
163
|
+
let existingItem: InferDetail<TSchema> | undefined = undefined
|
|
151
164
|
|
|
152
165
|
if (primaryKeyValue === undefined) {
|
|
166
|
+
operation = ModelMutationAction.Create
|
|
153
167
|
beforeOperation = ModelMutationAction.BeforeCreate
|
|
154
168
|
afterOperation = ModelMutationAction.AfterCreate
|
|
155
169
|
} else {
|
|
156
|
-
|
|
170
|
+
existingItem = await this.load(
|
|
157
171
|
{
|
|
158
172
|
[this.entityMetadata.primaryKey]: primaryKeyValue,
|
|
159
173
|
} as InferLookup<TSchema>,
|
|
@@ -161,14 +175,22 @@ export class ModelService<TSchema extends AnyModelSchema> extends ReadOnlyModelS
|
|
|
161
175
|
)
|
|
162
176
|
|
|
163
177
|
if (existingItem) {
|
|
178
|
+
operation = ModelMutationAction.Update
|
|
164
179
|
beforeOperation = ModelMutationAction.BeforeUpdate
|
|
165
180
|
afterOperation = ModelMutationAction.AfterUpdate
|
|
166
181
|
} else {
|
|
182
|
+
operation = ModelMutationAction.Create
|
|
167
183
|
beforeOperation = ModelMutationAction.BeforeCreate
|
|
168
184
|
afterOperation = ModelMutationAction.AfterCreate
|
|
169
185
|
}
|
|
170
186
|
}
|
|
171
187
|
|
|
188
|
+
// Normalize the input data
|
|
189
|
+
const normalizedInput = await this.normalizeInput(input, {
|
|
190
|
+
descriptor: this.getDescriptor(operation),
|
|
191
|
+
existing: existingItem,
|
|
192
|
+
})
|
|
193
|
+
|
|
172
194
|
// Emit the before upsert event
|
|
173
195
|
const beforeUpsertEvent = new MutationEvent<InferDetail<TSchema>, InferInput<TSchema>>(
|
|
174
196
|
this.getDescriptor(beforeOperation),
|
|
@@ -204,82 +226,86 @@ export class ModelService<TSchema extends AnyModelSchema> extends ReadOnlyModelS
|
|
|
204
226
|
return []
|
|
205
227
|
}
|
|
206
228
|
|
|
207
|
-
//
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
// Build a map of primary key to input and lookup info
|
|
211
|
-
type EntityInfo = {
|
|
229
|
+
// Keep track of input metadata for each position (preserves order and duplicates)
|
|
230
|
+
type InputInfo = {
|
|
212
231
|
input: InferInput<TSchema>
|
|
213
|
-
|
|
214
|
-
primaryKeyValue
|
|
232
|
+
index: number
|
|
233
|
+
primaryKeyValue?: string | number
|
|
215
234
|
existingEntity?: InferDetail<TSchema>
|
|
216
235
|
operation?: ModelMutationAction
|
|
217
236
|
}
|
|
218
237
|
|
|
219
|
-
const
|
|
220
|
-
const
|
|
238
|
+
const inputInfos: InputInfo[] = []
|
|
239
|
+
const uniqueLookups = new Map<string | number, InferLookup<TSchema>>()
|
|
221
240
|
|
|
222
|
-
// Process each
|
|
223
|
-
for (
|
|
241
|
+
// Process each input and collect unique lookups
|
|
242
|
+
for (let i = 0; i < inputs.length; i++) {
|
|
243
|
+
const input = inputs[i]
|
|
224
244
|
const primaryKeyValue = this.getPrimaryKeyValue(input)
|
|
225
245
|
|
|
246
|
+
const inputInfo: InputInfo = {
|
|
247
|
+
input,
|
|
248
|
+
index: i,
|
|
249
|
+
primaryKeyValue,
|
|
250
|
+
}
|
|
251
|
+
inputInfos.push(inputInfo)
|
|
252
|
+
|
|
253
|
+
// Collect unique lookups for entities that have primary keys
|
|
226
254
|
if (primaryKeyValue !== undefined) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
lookup: {
|
|
231
|
-
[this.entityMetadata.primaryKey]: primaryKeyValue,
|
|
232
|
-
} as InferLookup<TSchema>,
|
|
233
|
-
}
|
|
234
|
-
entityInfoMap.set(primaryKeyValue, entityInfo)
|
|
235
|
-
} else {
|
|
236
|
-
// Inputs without primary keys are always creates
|
|
237
|
-
inputsWithoutPrimaryKey.push(input)
|
|
255
|
+
uniqueLookups.set(primaryKeyValue, {
|
|
256
|
+
[this.entityMetadata.primaryKey]: primaryKeyValue,
|
|
257
|
+
} as InferLookup<TSchema>)
|
|
238
258
|
}
|
|
239
259
|
}
|
|
240
260
|
|
|
241
|
-
//
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (lookups.length > 0) {
|
|
261
|
+
// Load existing entities for unique primary keys
|
|
262
|
+
const existingEntitiesMap = new Map<string | number, InferDetail<TSchema>>()
|
|
263
|
+
if (uniqueLookups.size > 0) {
|
|
264
|
+
const lookups = Array.from(uniqueLookups.values())
|
|
246
265
|
const existingEntities = await this.loadMany(lookups, options)
|
|
247
266
|
existingEntities.forEach((entity) => {
|
|
248
267
|
if (entity) {
|
|
249
268
|
const pkValue = this.getPrimaryKeyValue(entity)
|
|
250
|
-
if (pkValue !== undefined
|
|
251
|
-
|
|
252
|
-
entityInfo.existingEntity = entity
|
|
269
|
+
if (pkValue !== undefined) {
|
|
270
|
+
existingEntitiesMap.set(pkValue, entity)
|
|
253
271
|
}
|
|
254
272
|
}
|
|
255
273
|
})
|
|
256
274
|
}
|
|
257
275
|
|
|
258
|
-
//
|
|
259
|
-
const
|
|
276
|
+
// Normalize all inputs and determine operations in parallel
|
|
277
|
+
const normalizationPromises = inputInfos.map(async (inputInfo) => {
|
|
278
|
+
// Set existing entity if found
|
|
279
|
+
if (inputInfo.primaryKeyValue !== undefined) {
|
|
280
|
+
inputInfo.existingEntity = existingEntitiesMap.get(inputInfo.primaryKeyValue)
|
|
281
|
+
}
|
|
260
282
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const operation = entityInfo.existingEntity
|
|
283
|
+
// Determine operation type
|
|
284
|
+
inputInfo.operation = inputInfo.existingEntity
|
|
264
285
|
? ModelMutationAction.BeforeUpdate
|
|
265
286
|
: ModelMutationAction.BeforeCreate
|
|
266
287
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
entityInfo.input,
|
|
288
|
+
// Normalize the input
|
|
289
|
+
const normalizedInput = await this.normalizeInput(inputInfo.input, {
|
|
290
|
+
existing: inputInfo.existingEntity,
|
|
291
|
+
descriptor: this.getDescriptor(
|
|
292
|
+
inputInfo.existingEntity ? ModelMutationAction.Update : ModelMutationAction.Create,
|
|
273
293
|
),
|
|
274
|
-
)
|
|
275
|
-
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
inputInfo.input = normalizedInput
|
|
297
|
+
return normalizedInput
|
|
298
|
+
})
|
|
276
299
|
|
|
277
|
-
|
|
278
|
-
|
|
300
|
+
const normalizedInputs = await Promise.all(normalizationPromises)
|
|
301
|
+
|
|
302
|
+
// Create before events
|
|
303
|
+
const beforeEvents: MutationEvent<InferDetail<TSchema>, InferInput<TSchema>>[] = []
|
|
304
|
+
for (const inputInfo of inputInfos) {
|
|
279
305
|
beforeEvents.push(
|
|
280
306
|
new MutationEvent<InferDetail<TSchema>, InferInput<TSchema>>(
|
|
281
|
-
this.getDescriptor(
|
|
282
|
-
input,
|
|
307
|
+
this.getDescriptor(inputInfo.operation!),
|
|
308
|
+
inputInfo.input,
|
|
283
309
|
),
|
|
284
310
|
)
|
|
285
311
|
}
|
|
@@ -287,59 +313,33 @@ export class ModelService<TSchema extends AnyModelSchema> extends ReadOnlyModelS
|
|
|
287
313
|
// Emit all before events
|
|
288
314
|
await Promise.all(beforeEvents.map((event) => this.emitter.emitAsync(event)))
|
|
289
315
|
|
|
290
|
-
// Perform the bulk upsert operation with normalized inputs
|
|
316
|
+
// Perform the bulk upsert operation with all normalized inputs
|
|
291
317
|
const results = await this.repository.bulkUpsert(normalizedInputs, options)
|
|
292
318
|
|
|
293
|
-
// Create
|
|
294
|
-
const resultsByPrimaryKey = new Map<string | number, InferDetail<TSchema>>()
|
|
295
|
-
const resultsWithoutPrimaryKey: InferDetail<TSchema>[] = []
|
|
296
|
-
|
|
297
|
-
for (const result of results) {
|
|
298
|
-
const pkValue = this.getPrimaryKeyValue(result)
|
|
299
|
-
if (pkValue !== undefined) {
|
|
300
|
-
resultsByPrimaryKey.set(pkValue, result)
|
|
301
|
-
} else {
|
|
302
|
-
resultsWithoutPrimaryKey.push(result)
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Prepare after events by matching results back to original inputs
|
|
319
|
+
// Create after events and return results
|
|
307
320
|
const afterEvents: MutationEvent<InferDetail<TSchema>, InferInput<TSchema>>[] = []
|
|
308
|
-
let resultsWithoutPkIndex = 0
|
|
309
321
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
const
|
|
322
|
+
for (let i = 0; i < inputInfos.length; i++) {
|
|
323
|
+
const inputInfo = inputInfos[i]
|
|
324
|
+
const result = results[i]
|
|
313
325
|
|
|
314
326
|
const afterOperation =
|
|
315
|
-
|
|
327
|
+
inputInfo.operation === ModelMutationAction.BeforeCreate
|
|
316
328
|
? ModelMutationAction.AfterCreate
|
|
317
329
|
: ModelMutationAction.AfterUpdate
|
|
318
330
|
|
|
319
331
|
afterEvents.push(
|
|
320
332
|
new MutationEvent<InferDetail<TSchema>, InferInput<TSchema>>(
|
|
321
333
|
this.getDescriptor(afterOperation),
|
|
322
|
-
|
|
323
|
-
).setResult(
|
|
324
|
-
)
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Handle inputs without primary keys (always creates)
|
|
328
|
-
for (const input of inputsWithoutPrimaryKey) {
|
|
329
|
-
const matchedResult = resultsWithoutPrimaryKey[resultsWithoutPkIndex++]
|
|
330
|
-
|
|
331
|
-
afterEvents.push(
|
|
332
|
-
new MutationEvent<InferDetail<TSchema>, InferInput<TSchema>>(
|
|
333
|
-
this.getDescriptor(ModelMutationAction.AfterCreate),
|
|
334
|
-
input,
|
|
335
|
-
).setResult(matchedResult),
|
|
334
|
+
inputInfo.input,
|
|
335
|
+
).setResult(result),
|
|
336
336
|
)
|
|
337
337
|
}
|
|
338
338
|
|
|
339
339
|
// Emit all after events
|
|
340
340
|
await Promise.all(afterEvents.map((event) => this.emitter.emitAsync(event)))
|
|
341
341
|
|
|
342
|
-
// Return
|
|
342
|
+
// Return normalized results
|
|
343
343
|
return await Promise.all(results.map((result) => this.normalizeDetail(result)))
|
|
344
344
|
}
|
|
345
345
|
}
|
|
@@ -335,18 +335,41 @@ describe('ReadOnlyModelService', () => {
|
|
|
335
335
|
return results
|
|
336
336
|
}
|
|
337
337
|
}
|
|
338
|
-
class TestService extends ReadOnlyModelService<typeof mockSchema> {}
|
|
339
338
|
|
|
340
|
-
|
|
339
|
+
class TestServiceWithNormalization extends ReadOnlyModelService<typeof mockSchema> {
|
|
340
|
+
async normalizeDetail(detail: InferDetail<typeof mockSchema>): Promise<InferDetail<typeof mockSchema>> {
|
|
341
|
+
// Handle null case (e.g., when load returns null)
|
|
342
|
+
if (!detail) return detail
|
|
343
|
+
|
|
344
|
+
// Convert string dates back to Date objects
|
|
345
|
+
if (typeof detail.publishedDate === 'string') {
|
|
346
|
+
detail.publishedDate = new Date(detail.publishedDate) as any
|
|
347
|
+
}
|
|
348
|
+
return detail
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
async normalizeSummary(summary: InferDetail<typeof mockSchema>): Promise<InferDetail<typeof mockSchema>> {
|
|
352
|
+
// Handle null case (e.g., when load returns null)
|
|
353
|
+
if (!summary) return summary
|
|
354
|
+
|
|
355
|
+
// Convert string dates back to Date objects
|
|
356
|
+
if (typeof summary.publishedDate === 'string') {
|
|
357
|
+
summary.publishedDate = new Date(summary.publishedDate) as any
|
|
358
|
+
}
|
|
359
|
+
return summary
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
let testService: TestServiceWithNormalization
|
|
341
364
|
|
|
342
365
|
beforeEach(() => {
|
|
343
366
|
repository = new TestRepository()
|
|
344
367
|
emitter = new EventManager()
|
|
345
368
|
|
|
346
|
-
testService = new
|
|
369
|
+
testService = new TestServiceWithNormalization({ repository, emitter, schema: mockSchema, namespace })
|
|
347
370
|
})
|
|
348
371
|
|
|
349
|
-
it('should
|
|
372
|
+
it('should allow custom normalization of details in the load response when overridden', async () => {
|
|
350
373
|
const input = { id: 100, title: 'Normalization Test', author: 'Normalizer', publishedDate: new Date() }
|
|
351
374
|
await repository.create(input)
|
|
352
375
|
|
|
@@ -359,7 +382,7 @@ describe('ReadOnlyModelService', () => {
|
|
|
359
382
|
expect(actualDate).toBeInstanceOf(Date)
|
|
360
383
|
})
|
|
361
384
|
|
|
362
|
-
it('should
|
|
385
|
+
it('should allow custom normalization of details in the loadMany response when overridden', async () => {
|
|
363
386
|
const input1 = { id: 101, title: 'Normalization Test 1', author: 'Normalizer 1', publishedDate: new Date() }
|
|
364
387
|
const input2 = { id: 102, title: 'Normalization Test 2', author: 'Normalizer 2', publishedDate: new Date() }
|
|
365
388
|
await repository.create(input1)
|
|
@@ -376,7 +399,7 @@ describe('ReadOnlyModelService', () => {
|
|
|
376
399
|
}
|
|
377
400
|
})
|
|
378
401
|
|
|
379
|
-
it('should
|
|
402
|
+
it('should allow custom normalization of summaries in the search response when overridden', async () => {
|
|
380
403
|
const input1 = { id: 103, title: 'Normalization Test 3', author: 'Normalizer 3', publishedDate: new Date() }
|
|
381
404
|
const input2 = { id: 104, title: 'Normalization Test 4', author: 'Normalizer 4', publishedDate: new Date() }
|
|
382
405
|
await repository.create(input1)
|
|
@@ -392,5 +415,18 @@ describe('ReadOnlyModelService', () => {
|
|
|
392
415
|
expect(actualDate).toBeInstanceOf(Date)
|
|
393
416
|
}
|
|
394
417
|
})
|
|
418
|
+
|
|
419
|
+
it('should not normalize data by default when normalization methods are not overridden', async () => {
|
|
420
|
+
const defaultService = new ReadOnlyModelService({ repository, emitter, schema: mockSchema, namespace })
|
|
421
|
+
|
|
422
|
+
const input = { id: 105, title: 'Default Test', author: 'Default Author', publishedDate: new Date() }
|
|
423
|
+
await repository.create(input)
|
|
424
|
+
|
|
425
|
+
const record = await defaultService.load({ id: 105 })
|
|
426
|
+
|
|
427
|
+
// Should return the raw string from repository since no normalization is applied
|
|
428
|
+
expect(record.publishedDate as any).toBe('2024-01-01')
|
|
429
|
+
expect(typeof record.publishedDate).toBe('string')
|
|
430
|
+
})
|
|
395
431
|
})
|
|
396
432
|
})
|
|
@@ -10,7 +10,6 @@ import { ModelQueryEvent } from '../events/event-types'
|
|
|
10
10
|
import { QueryEvent } from '../events/query-event'
|
|
11
11
|
import { BaseModelService, type IActionOptions } from './base-model-service'
|
|
12
12
|
import type { IPaginationInput } from '../models/pagination'
|
|
13
|
-
import type { IUpdateOptions } from './model-service'
|
|
14
13
|
|
|
15
14
|
export interface ILoadOptions extends IActionOptions {}
|
|
16
15
|
export interface ISearchOptions<TSchema extends AnyModelSchema> extends IActionOptions {
|
|
@@ -27,15 +26,6 @@ export class ReadOnlyModelService<TSchema extends AnyModelSchema> extends BaseMo
|
|
|
27
26
|
* @returns The normalized detail data.
|
|
28
27
|
*/
|
|
29
28
|
async normalizeDetail(detail: InferDetail<TSchema>): Promise<InferDetail<TSchema>> {
|
|
30
|
-
const detailModel = this.schema.definition.detail as Model<any, any>
|
|
31
|
-
if (detailModel) {
|
|
32
|
-
const validation = await detailModel.validate(detail, { strict: false })
|
|
33
|
-
if (validation.issues) {
|
|
34
|
-
console.warn(`${detailModel.labels.singularLabel} shape did not match the expected schema`, validation)
|
|
35
|
-
} else {
|
|
36
|
-
return validation.value
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
29
|
return detail
|
|
40
30
|
}
|
|
41
31
|
|
|
@@ -48,15 +38,6 @@ export class ReadOnlyModelService<TSchema extends AnyModelSchema> extends BaseMo
|
|
|
48
38
|
* @returns The normalized summary data.
|
|
49
39
|
*/
|
|
50
40
|
async normalizeSummary(summary: InferDetail<TSchema>): Promise<InferDetail<TSchema>> {
|
|
51
|
-
const summaryModel = this.schema.definition.summary as Model<any, any>
|
|
52
|
-
if (summaryModel) {
|
|
53
|
-
const validation = await summaryModel.validate(summary, { strict: false })
|
|
54
|
-
if (validation.issues) {
|
|
55
|
-
console.warn(`${summaryModel.labels.singularLabel} shape did not match the expected schema`)
|
|
56
|
-
} else {
|
|
57
|
-
return validation.value
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
41
|
return summary
|
|
61
42
|
}
|
|
62
43
|
|