@api-client/core 0.18.6 → 0.18.8
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/build/src/modeling/importers/CsvImporter.d.ts +40 -6
- package/build/src/modeling/importers/CsvImporter.d.ts.map +1 -1
- package/build/src/modeling/importers/CsvImporter.js +75 -2
- package/build/src/modeling/importers/CsvImporter.js.map +1 -1
- package/build/src/modeling/importers/JsonSchemaImporter.d.ts +4 -0
- package/build/src/modeling/importers/JsonSchemaImporter.d.ts.map +1 -1
- package/build/src/modeling/importers/JsonSchemaImporter.js +89 -16
- package/build/src/modeling/importers/JsonSchemaImporter.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/data/models/example-generator-api.json +21 -21
- package/package.json +1 -1
- package/src/modeling/importers/CsvImporter.ts +115 -5
- package/src/modeling/importers/JsonSchemaImporter.ts +111 -20
- package/tests/fixtures/schemas/arrays.json +35 -0
- package/tests/fixtures/schemas/complex.json +41 -0
- package/tests/fixtures/schemas/enumerated_values.json +11 -0
- package/tests/fixtures/schemas/person.json +21 -0
- package/tests/fixtures/schemas/regexp.json +12 -0
- package/tests/unit/modeling/importers/csv_importer.spec.ts +351 -0
- package/tests/unit/modeling/importers/json_schema_importer.spec.ts +137 -0
|
@@ -50,6 +50,7 @@ test.group('CsvImporter: import', (group) => {
|
|
|
50
50
|
],
|
|
51
51
|
values: [[1, 'test-item', 99.9]],
|
|
52
52
|
header: ['id', 'name', 'value'],
|
|
53
|
+
file: 'products.csv',
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
await importer.import(parseResult, 'My Products')
|
|
@@ -87,6 +88,7 @@ test.group('CsvImporter: import', (group) => {
|
|
|
87
88
|
format: [{ index: 0, name: 'First Name', type: 'string' }],
|
|
88
89
|
values: [['John']],
|
|
89
90
|
header: ['First Name'],
|
|
91
|
+
file: 'users.csv',
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
await importer.import(parseResult, 'User List!')
|
|
@@ -113,6 +115,7 @@ test.group('CsvImporter: import', (group) => {
|
|
|
113
115
|
],
|
|
114
116
|
values: [], // No data rows
|
|
115
117
|
header: ['id', 'email'],
|
|
118
|
+
file: 'empty.csv',
|
|
116
119
|
}
|
|
117
120
|
|
|
118
121
|
await importer.import(parseResult, 'users')
|
|
@@ -140,6 +143,7 @@ test.group('CsvImporter: import', (group) => {
|
|
|
140
143
|
// @ts-expect-error TypeScript expects values to be defined
|
|
141
144
|
values: [[null, 'has-value', undefined]],
|
|
142
145
|
header: ['col_a', 'col_b', 'col_c'],
|
|
146
|
+
file: 'test.csv',
|
|
143
147
|
}
|
|
144
148
|
|
|
145
149
|
await importer.import(parseResult, 'test_data')
|
|
@@ -169,6 +173,7 @@ test.group('CsvImporter: import', (group) => {
|
|
|
169
173
|
],
|
|
170
174
|
values: [[123, 45.67]],
|
|
171
175
|
header: ['integer_val', 'float_val'],
|
|
176
|
+
file: 'numeric.csv',
|
|
172
177
|
}
|
|
173
178
|
|
|
174
179
|
await importer.import(parseResult, 'Numeric Data')
|
|
@@ -187,3 +192,349 @@ test.group('CsvImporter: import', (group) => {
|
|
|
187
192
|
assert.deepEqual(floatProp!.bindings, [{ type: 'web', schema: { format: 'double' } }])
|
|
188
193
|
})
|
|
189
194
|
})
|
|
195
|
+
|
|
196
|
+
test.group('CsvImporter: importMany', (group) => {
|
|
197
|
+
let domain: DataDomain
|
|
198
|
+
|
|
199
|
+
group.each.setup(() => {
|
|
200
|
+
domain = new DataDomain()
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
test('should import multiple CSV structures into a single model', async ({ assert }) => {
|
|
204
|
+
const importer = new CsvImporter(domain)
|
|
205
|
+
const parseResults: ParseResult[] = [
|
|
206
|
+
{
|
|
207
|
+
format: [
|
|
208
|
+
{ index: 0, name: 'id', type: 'number', format: 'integer' },
|
|
209
|
+
{ index: 1, name: 'name', type: 'string' },
|
|
210
|
+
],
|
|
211
|
+
values: [
|
|
212
|
+
[1, 'Product A'],
|
|
213
|
+
[2, 'Product B'],
|
|
214
|
+
],
|
|
215
|
+
header: ['id', 'name'],
|
|
216
|
+
file: 'products.csv',
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
format: [
|
|
220
|
+
{ index: 0, name: 'user_id', type: 'number', format: 'integer' },
|
|
221
|
+
{ index: 1, name: 'email', type: 'string' },
|
|
222
|
+
{ index: 2, name: 'active', type: 'boolean' },
|
|
223
|
+
],
|
|
224
|
+
values: [
|
|
225
|
+
[100, 'user@example.com', true],
|
|
226
|
+
[101, 'admin@example.com', false],
|
|
227
|
+
],
|
|
228
|
+
header: ['user_id', 'email', 'active'],
|
|
229
|
+
file: 'users.csv',
|
|
230
|
+
},
|
|
231
|
+
]
|
|
232
|
+
|
|
233
|
+
const result = await importer.importMany(parseResults, 'E-commerce Data')
|
|
234
|
+
|
|
235
|
+
// Check model
|
|
236
|
+
const model = findModelByName(domain, 'e_commerce_data')
|
|
237
|
+
assert.exists(model)
|
|
238
|
+
assert.equal(model!.info.displayName, 'E-commerce Data')
|
|
239
|
+
|
|
240
|
+
// Check entities
|
|
241
|
+
assert.lengthOf(result.entities, 2)
|
|
242
|
+
assert.equal(result.model, model)
|
|
243
|
+
|
|
244
|
+
// Check products entity
|
|
245
|
+
const productsEntity = findEntityByName(domain, 'products')
|
|
246
|
+
assert.exists(productsEntity)
|
|
247
|
+
assert.isUndefined(productsEntity!.info.displayName, 'the products entity should not have a displayName')
|
|
248
|
+
|
|
249
|
+
const productIdProp = findPropertyByName(productsEntity!, 'id')
|
|
250
|
+
assert.exists(productIdProp)
|
|
251
|
+
assert.equal(productIdProp!.type, 'number')
|
|
252
|
+
assert.deepEqual(productIdProp!.bindings, [{ type: 'web', schema: { format: 'int64' } }])
|
|
253
|
+
assert.deepEqual(productIdProp!.schema?.examples, ['1'])
|
|
254
|
+
|
|
255
|
+
const productNameProp = findPropertyByName(productsEntity!, 'name')
|
|
256
|
+
assert.exists(productNameProp)
|
|
257
|
+
assert.equal(productNameProp!.type, 'string')
|
|
258
|
+
assert.deepEqual(productNameProp!.schema?.examples, ['Product A'])
|
|
259
|
+
|
|
260
|
+
// Check users entity
|
|
261
|
+
const usersEntity = findEntityByName(domain, 'users')
|
|
262
|
+
assert.exists(usersEntity)
|
|
263
|
+
assert.isUndefined(usersEntity!.info.displayName, 'the users entity should not have a displayName')
|
|
264
|
+
|
|
265
|
+
const userIdProp = findPropertyByName(usersEntity!, 'user_id')
|
|
266
|
+
assert.exists(userIdProp)
|
|
267
|
+
assert.equal(userIdProp!.type, 'number')
|
|
268
|
+
assert.deepEqual(userIdProp!.bindings, [{ type: 'web', schema: { format: 'int64' } }])
|
|
269
|
+
assert.deepEqual(userIdProp!.schema?.examples, ['100'])
|
|
270
|
+
|
|
271
|
+
const emailProp = findPropertyByName(usersEntity!, 'email')
|
|
272
|
+
assert.exists(emailProp)
|
|
273
|
+
assert.equal(emailProp!.type, 'string')
|
|
274
|
+
assert.deepEqual(emailProp!.schema?.examples, ['user@example.com'])
|
|
275
|
+
|
|
276
|
+
const activeProp = findPropertyByName(usersEntity!, 'active')
|
|
277
|
+
assert.exists(activeProp)
|
|
278
|
+
assert.equal(activeProp!.type, 'boolean')
|
|
279
|
+
assert.deepEqual(activeProp!.schema?.examples, ['true'])
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
test('should handle name sanitization for model and entities', async ({ assert }) => {
|
|
283
|
+
const importer = new CsvImporter(domain)
|
|
284
|
+
const parseResults: ParseResult[] = [
|
|
285
|
+
{
|
|
286
|
+
format: [{ index: 0, name: 'First Name', type: 'string' }],
|
|
287
|
+
values: [['John']],
|
|
288
|
+
header: ['First Name'],
|
|
289
|
+
file: 'Employee List!',
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
format: [{ index: 0, name: 'Department Name', type: 'string' }],
|
|
293
|
+
values: [['Engineering']],
|
|
294
|
+
header: ['Department Name'],
|
|
295
|
+
file: 'Department Info@',
|
|
296
|
+
},
|
|
297
|
+
]
|
|
298
|
+
|
|
299
|
+
await importer.importMany(parseResults, 'HR Data!')
|
|
300
|
+
|
|
301
|
+
const model = findModelByName(domain, 'hr_data')
|
|
302
|
+
assert.exists(model)
|
|
303
|
+
assert.equal(model!.info.displayName, 'HR Data!')
|
|
304
|
+
|
|
305
|
+
const employeeEntity = findEntityByName(domain, 'employee_list')
|
|
306
|
+
assert.exists(employeeEntity)
|
|
307
|
+
assert.equal(employeeEntity!.info.displayName, 'Employee List!')
|
|
308
|
+
|
|
309
|
+
const departmentEntity = findEntityByName(domain, 'department_info')
|
|
310
|
+
assert.exists(departmentEntity)
|
|
311
|
+
assert.equal(departmentEntity!.info.displayName, 'Department Info@')
|
|
312
|
+
|
|
313
|
+
const firstNameProp = findPropertyByName(employeeEntity!, 'first_name')
|
|
314
|
+
assert.exists(firstNameProp)
|
|
315
|
+
assert.equal(firstNameProp!.info.displayName, 'First Name')
|
|
316
|
+
|
|
317
|
+
const deptNameProp = findPropertyByName(departmentEntity!, 'department_name')
|
|
318
|
+
assert.exists(deptNameProp)
|
|
319
|
+
assert.equal(deptNameProp!.info.displayName, 'Department Name')
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
test('should handle empty data arrays for some entities', async ({ assert }) => {
|
|
323
|
+
const importer = new CsvImporter(domain)
|
|
324
|
+
const parseResults: ParseResult[] = [
|
|
325
|
+
{
|
|
326
|
+
format: [
|
|
327
|
+
{ index: 0, name: 'id', type: 'number', format: 'integer' },
|
|
328
|
+
{ index: 1, name: 'title', type: 'string' },
|
|
329
|
+
],
|
|
330
|
+
values: [[1, 'Sample Title']],
|
|
331
|
+
header: ['id', 'title'],
|
|
332
|
+
file: 'articles.csv',
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
format: [
|
|
336
|
+
{ index: 0, name: 'tag_id', type: 'number' },
|
|
337
|
+
{ index: 1, name: 'tag_name', type: 'string' },
|
|
338
|
+
],
|
|
339
|
+
values: [], // No data rows
|
|
340
|
+
header: ['tag_id', 'tag_name'],
|
|
341
|
+
file: 'tags.csv',
|
|
342
|
+
},
|
|
343
|
+
]
|
|
344
|
+
|
|
345
|
+
const result = await importer.importMany(parseResults, 'Blog Data')
|
|
346
|
+
|
|
347
|
+
assert.lengthOf(result.entities, 2)
|
|
348
|
+
|
|
349
|
+
const articlesEntity = findEntityByName(domain, 'articles')
|
|
350
|
+
assert.exists(articlesEntity)
|
|
351
|
+
|
|
352
|
+
const idProp = findPropertyByName(articlesEntity!, 'id')
|
|
353
|
+
assert.exists(idProp)
|
|
354
|
+
assert.deepEqual(idProp!.schema?.examples, ['1'])
|
|
355
|
+
|
|
356
|
+
const tagsEntity = findEntityByName(domain, 'tags')
|
|
357
|
+
assert.exists(tagsEntity)
|
|
358
|
+
|
|
359
|
+
const tagIdProp = findPropertyByName(tagsEntity!, 'tag_id')
|
|
360
|
+
assert.exists(tagIdProp)
|
|
361
|
+
assert.isUndefined(tagIdProp!.schema?.examples, 'should have no examples for empty data')
|
|
362
|
+
|
|
363
|
+
const tagNameProp = findPropertyByName(tagsEntity!, 'tag_name')
|
|
364
|
+
assert.exists(tagNameProp)
|
|
365
|
+
assert.isUndefined(tagNameProp!.schema?.examples, 'should have no examples for empty data')
|
|
366
|
+
})
|
|
367
|
+
|
|
368
|
+
test('should handle null and undefined values in example rows', async ({ assert }) => {
|
|
369
|
+
const importer = new CsvImporter(domain)
|
|
370
|
+
const parseResults: ParseResult[] = [
|
|
371
|
+
{
|
|
372
|
+
format: [
|
|
373
|
+
{ index: 0, name: 'col_a', type: 'string' },
|
|
374
|
+
{ index: 1, name: 'col_b', type: 'string' },
|
|
375
|
+
],
|
|
376
|
+
// @ts-expect-error TypeScript expects values to be defined
|
|
377
|
+
values: [[null, 'valid-value']],
|
|
378
|
+
header: ['col_a', 'col_b'],
|
|
379
|
+
file: 'test_data.csv',
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
format: [
|
|
383
|
+
{ index: 0, name: 'col_x', type: 'string' },
|
|
384
|
+
{ index: 1, name: 'col_y', type: 'string' },
|
|
385
|
+
],
|
|
386
|
+
// @ts-expect-error TypeScript expects values to be defined
|
|
387
|
+
values: [['another-value', undefined]],
|
|
388
|
+
header: ['col_x', 'col_y'],
|
|
389
|
+
file: 'more_test_data.csv',
|
|
390
|
+
},
|
|
391
|
+
]
|
|
392
|
+
|
|
393
|
+
const result = await importer.importMany(parseResults, 'Test Data')
|
|
394
|
+
|
|
395
|
+
assert.lengthOf(result.entities, 2)
|
|
396
|
+
|
|
397
|
+
const testDataEntity = findEntityByName(domain, 'test_data')
|
|
398
|
+
assert.exists(testDataEntity)
|
|
399
|
+
|
|
400
|
+
const propA = findPropertyByName(testDataEntity!, 'col_a')
|
|
401
|
+
assert.exists(propA)
|
|
402
|
+
assert.isUndefined(propA!.schema?.examples, 'should not create example for null')
|
|
403
|
+
|
|
404
|
+
const propB = findPropertyByName(testDataEntity!, 'col_b')
|
|
405
|
+
assert.exists(propB)
|
|
406
|
+
assert.deepEqual(propB!.schema?.examples, ['valid-value'])
|
|
407
|
+
|
|
408
|
+
const moreTestDataEntity = findEntityByName(domain, 'more_test_data')
|
|
409
|
+
assert.exists(moreTestDataEntity)
|
|
410
|
+
|
|
411
|
+
const propX = findPropertyByName(moreTestDataEntity!, 'col_x')
|
|
412
|
+
assert.exists(propX)
|
|
413
|
+
assert.deepEqual(propX!.schema?.examples, ['another-value'])
|
|
414
|
+
|
|
415
|
+
const propY = findPropertyByName(moreTestDataEntity!, 'col_y')
|
|
416
|
+
assert.exists(propY)
|
|
417
|
+
assert.isUndefined(propY!.schema?.examples, 'should not create example for undefined')
|
|
418
|
+
})
|
|
419
|
+
|
|
420
|
+
test('should handle different number formats across entities', async ({ assert }) => {
|
|
421
|
+
const importer = new CsvImporter(domain)
|
|
422
|
+
const parseResults: ParseResult[] = [
|
|
423
|
+
{
|
|
424
|
+
format: [
|
|
425
|
+
{ index: 0, name: 'int_val', type: 'number', format: 'integer' },
|
|
426
|
+
{ index: 1, name: 'decimal_val', type: 'number', format: 'decimal' },
|
|
427
|
+
],
|
|
428
|
+
values: [[42, 3.14]],
|
|
429
|
+
header: ['int_val', 'decimal_val'],
|
|
430
|
+
file: 'numbers.csv',
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
format: [
|
|
434
|
+
{ index: 0, name: 'price', type: 'number', format: 'decimal' },
|
|
435
|
+
{ index: 1, name: 'quantity', type: 'number', format: 'integer' },
|
|
436
|
+
],
|
|
437
|
+
values: [[19.99, 5]],
|
|
438
|
+
header: ['price', 'quantity'],
|
|
439
|
+
file: 'inventory.csv',
|
|
440
|
+
},
|
|
441
|
+
]
|
|
442
|
+
|
|
443
|
+
const result = await importer.importMany(parseResults, 'Numeric Data')
|
|
444
|
+
|
|
445
|
+
assert.lengthOf(result.entities, 2)
|
|
446
|
+
|
|
447
|
+
const numbersEntity = findEntityByName(domain, 'numbers')
|
|
448
|
+
assert.exists(numbersEntity)
|
|
449
|
+
|
|
450
|
+
const intProp = findPropertyByName(numbersEntity!, 'int_val')
|
|
451
|
+
assert.exists(intProp)
|
|
452
|
+
assert.equal(intProp!.type, 'number')
|
|
453
|
+
assert.deepEqual(intProp!.bindings, [{ type: 'web', schema: { format: 'int64' } }])
|
|
454
|
+
|
|
455
|
+
const decimalProp = findPropertyByName(numbersEntity!, 'decimal_val')
|
|
456
|
+
assert.exists(decimalProp)
|
|
457
|
+
assert.equal(decimalProp!.type, 'number')
|
|
458
|
+
assert.deepEqual(decimalProp!.bindings, [{ type: 'web', schema: { format: 'double' } }])
|
|
459
|
+
|
|
460
|
+
const inventoryEntity = findEntityByName(domain, 'inventory')
|
|
461
|
+
assert.exists(inventoryEntity)
|
|
462
|
+
|
|
463
|
+
const priceProp = findPropertyByName(inventoryEntity!, 'price')
|
|
464
|
+
assert.exists(priceProp)
|
|
465
|
+
assert.equal(priceProp!.type, 'number')
|
|
466
|
+
assert.deepEqual(priceProp!.bindings, [{ type: 'web', schema: { format: 'double' } }])
|
|
467
|
+
|
|
468
|
+
const quantityProp = findPropertyByName(inventoryEntity!, 'quantity')
|
|
469
|
+
assert.exists(quantityProp)
|
|
470
|
+
assert.equal(quantityProp!.type, 'number')
|
|
471
|
+
assert.deepEqual(quantityProp!.bindings, [{ type: 'web', schema: { format: 'int64' } }])
|
|
472
|
+
})
|
|
473
|
+
|
|
474
|
+
test('should handle single CSV data in array', async ({ assert }) => {
|
|
475
|
+
const importer = new CsvImporter(domain)
|
|
476
|
+
const parseResults: ParseResult[] = [
|
|
477
|
+
{
|
|
478
|
+
format: [
|
|
479
|
+
{ index: 0, name: 'id', type: 'number', format: 'integer' },
|
|
480
|
+
{ index: 1, name: 'name', type: 'string' },
|
|
481
|
+
],
|
|
482
|
+
values: [[1, 'Single Item']],
|
|
483
|
+
header: ['id', 'name'],
|
|
484
|
+
file: 'single.csv',
|
|
485
|
+
},
|
|
486
|
+
]
|
|
487
|
+
|
|
488
|
+
const result = await importer.importMany(parseResults, 'Single Data')
|
|
489
|
+
|
|
490
|
+
const model = findModelByName(domain, 'single_data')
|
|
491
|
+
assert.exists(model)
|
|
492
|
+
assert.equal(model!.info.displayName, 'Single Data')
|
|
493
|
+
|
|
494
|
+
assert.lengthOf(result.entities, 1)
|
|
495
|
+
assert.equal(result.model, model)
|
|
496
|
+
|
|
497
|
+
const singleEntity = findEntityByName(domain, 'single')
|
|
498
|
+
assert.exists(singleEntity)
|
|
499
|
+
assert.isUndefined(singleEntity!.info.displayName, 'the single entity should not have a displayName')
|
|
500
|
+
|
|
501
|
+
const idProp = findPropertyByName(singleEntity!, 'id')
|
|
502
|
+
assert.exists(idProp)
|
|
503
|
+
assert.equal(idProp!.type, 'number')
|
|
504
|
+
assert.deepEqual(idProp!.schema?.examples, ['1'])
|
|
505
|
+
|
|
506
|
+
const nameProp = findPropertyByName(singleEntity!, 'name')
|
|
507
|
+
assert.exists(nameProp)
|
|
508
|
+
assert.equal(nameProp!.type, 'string')
|
|
509
|
+
assert.deepEqual(nameProp!.schema?.examples, ['Single Item'])
|
|
510
|
+
})
|
|
511
|
+
|
|
512
|
+
test('should handle entities with fallback names when file names are missing', async ({ assert }) => {
|
|
513
|
+
const importer = new CsvImporter(domain)
|
|
514
|
+
const parseResults: ParseResult[] = [
|
|
515
|
+
{
|
|
516
|
+
format: [{ index: 0, name: 'col1', type: 'string' }],
|
|
517
|
+
values: [['value1']],
|
|
518
|
+
header: ['col1'],
|
|
519
|
+
file: '',
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
format: [{ index: 0, name: 'col2', type: 'string' }],
|
|
523
|
+
values: [['value2']],
|
|
524
|
+
header: ['col2'],
|
|
525
|
+
file: '',
|
|
526
|
+
},
|
|
527
|
+
]
|
|
528
|
+
|
|
529
|
+
const result = await importer.importMany(parseResults, 'Fallback Data')
|
|
530
|
+
|
|
531
|
+
assert.lengthOf(result.entities, 2)
|
|
532
|
+
|
|
533
|
+
// Should use fallback names based on entity index
|
|
534
|
+
const entity0 = findEntityByName(domain, 'entity_0')
|
|
535
|
+
assert.exists(entity0)
|
|
536
|
+
|
|
537
|
+
const entity1 = findEntityByName(domain, 'entity_1')
|
|
538
|
+
assert.exists(entity1)
|
|
539
|
+
})
|
|
540
|
+
})
|
|
@@ -7,6 +7,11 @@ import { DataDomain } from '../../../../src/modeling/DataDomain.js'
|
|
|
7
7
|
import type { JSONSchema7 } from 'json-schema'
|
|
8
8
|
import type { DomainEntity } from '../../../../src/modeling/DomainEntity.js'
|
|
9
9
|
import { DomainAssociation, DomainProperty } from '../../../../src/browser.js'
|
|
10
|
+
import Person from '../../../fixtures/schemas/person.json' with { type: 'json' }
|
|
11
|
+
import Arrays from '../../../fixtures/schemas/arrays.json' with { type: 'json' }
|
|
12
|
+
import EnumValues from '../../../fixtures/schemas/enumerated_values.json' with { type: 'json' }
|
|
13
|
+
import RegexpSchema from '../../../fixtures/schemas/regexp.json' with { type: 'json' }
|
|
14
|
+
import ComplexSchema from '../../../fixtures/schemas/complex.json' with { type: 'json' }
|
|
10
15
|
|
|
11
16
|
const input: InMemorySchema[] = []
|
|
12
17
|
for (const [key, value] of Object.entries(schemas)) {
|
|
@@ -43,6 +48,13 @@ function findAssociationByName(entity: DomainEntity, name: string): DomainAssoci
|
|
|
43
48
|
throw new Error(`Association with name "${name}" not found`)
|
|
44
49
|
}
|
|
45
50
|
|
|
51
|
+
async function importSchemas(input: InMemorySchema[]): Promise<DataDomain> {
|
|
52
|
+
const domain = new DataDomain({ info: { name: 'Test Domain' } })
|
|
53
|
+
const importer = new JsonSchemaImporter(domain)
|
|
54
|
+
await importer.import(input, 'imported_model')
|
|
55
|
+
return domain
|
|
56
|
+
}
|
|
57
|
+
|
|
46
58
|
test.group('JsonSchemaImporter', (g) => {
|
|
47
59
|
let domain: DataDomain
|
|
48
60
|
|
|
@@ -449,3 +461,128 @@ test.group('JsonSchemaImporter', (g) => {
|
|
|
449
461
|
)
|
|
450
462
|
})
|
|
451
463
|
})
|
|
464
|
+
|
|
465
|
+
test.group('small batch of schemas', () => {
|
|
466
|
+
test('imports a single schema', async ({ assert }) => {
|
|
467
|
+
const domain = await importSchemas(input.slice(0, 1))
|
|
468
|
+
const models = [...domain.listModels()]
|
|
469
|
+
assert.lengthOf(models, 1, 'Should import one model')
|
|
470
|
+
const entities = [...domain.listEntities()]
|
|
471
|
+
assert.lengthOf(entities, 1, 'Should import one entity')
|
|
472
|
+
assert.equal(entities[0].info.name, '3_d_model', 'Entity should be 3_d_model')
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
test('imports two schemas only', async ({ assert }) => {
|
|
476
|
+
const domain = await importSchemas(input.slice(0, 2))
|
|
477
|
+
const models = [...domain.listModels()]
|
|
478
|
+
assert.lengthOf(models, 1, 'Should import one model')
|
|
479
|
+
const entities = [...domain.listEntities()]
|
|
480
|
+
assert.lengthOf(entities, 2, 'Should import two entities')
|
|
481
|
+
assert.equal(entities[0].info.name, '3_d_model', 'Entity should be 3_d_model')
|
|
482
|
+
assert.equal(entities[1].info.name, 'am_radio_channel', 'Entity should be am_radio_channel')
|
|
483
|
+
})
|
|
484
|
+
})
|
|
485
|
+
|
|
486
|
+
//
|
|
487
|
+
// From the JSON Schema website.
|
|
488
|
+
//
|
|
489
|
+
test.group('JSON Schema Examples', () => {
|
|
490
|
+
test('imports Person schema correctly', async ({ assert }) => {
|
|
491
|
+
const domain = await importSchemas([{ path: 'person.json', contents: Person as JSONSchema7 }])
|
|
492
|
+
const models = [...domain.listModels()]
|
|
493
|
+
assert.lengthOf(models, 1, 'Should import one model')
|
|
494
|
+
const entities = [...domain.listEntities()]
|
|
495
|
+
assert.lengthOf(entities, 1, 'Should import one entity')
|
|
496
|
+
const [person] = entities
|
|
497
|
+
const properties = [...person.listProperties()]
|
|
498
|
+
assert.lengthOf(properties, 3, 'Person should have three properties')
|
|
499
|
+
assert.equal(properties[0].info.name, 'first_name', 'First property should be first_name')
|
|
500
|
+
assert.equal(properties[1].info.name, 'last_name', 'Second property should be last_name')
|
|
501
|
+
assert.equal(properties[2].info.name, 'age', 'Third property should be age')
|
|
502
|
+
assert.equal(properties[0].type, 'string', 'First property should be string')
|
|
503
|
+
assert.equal(properties[1].type, 'string', 'Second property should be string')
|
|
504
|
+
assert.equal(properties[2].type, 'number', 'Third property should be number')
|
|
505
|
+
assert.strictEqual(properties[2].schema?.minimum, 0, 'Third property should have minimum 0')
|
|
506
|
+
})
|
|
507
|
+
|
|
508
|
+
test('imports Arrays schema correctly', async ({ assert }) => {
|
|
509
|
+
const domain = await importSchemas([{ path: 'arrays.json', contents: Arrays as JSONSchema7 }])
|
|
510
|
+
const models = [...domain.listModels()]
|
|
511
|
+
assert.lengthOf(models, 1, 'Should import one model')
|
|
512
|
+
const entities = [...domain.listEntities()]
|
|
513
|
+
assert.lengthOf(entities, 2, 'Should import two entities')
|
|
514
|
+
const arraysEntity = findEntityByName(domain, 'arrays')
|
|
515
|
+
const veggieEntity = findEntityByName(domain, 'veggie')
|
|
516
|
+
assert.exists(arraysEntity, 'arrays entity should exist')
|
|
517
|
+
assert.exists(veggieEntity, 'veggie entity should exist')
|
|
518
|
+
const arraysProperties = [...arraysEntity.listProperties()]
|
|
519
|
+
const arraysAssociations = [...arraysEntity.listAssociations()]
|
|
520
|
+
assert.lengthOf(arraysProperties, 1, 'Arrays entity should have one property')
|
|
521
|
+
assert.lengthOf(arraysAssociations, 1, 'Arrays entity should have one association')
|
|
522
|
+
const veggieProperties = [...veggieEntity.listProperties()]
|
|
523
|
+
const veggieAssociations = [...veggieEntity.listAssociations()]
|
|
524
|
+
assert.lengthOf(veggieProperties, 2, 'Veggie entity should have two properties')
|
|
525
|
+
assert.lengthOf(veggieAssociations, 0, 'Veggie entity should have no associations')
|
|
526
|
+
const [vp1, vp2] = veggieProperties
|
|
527
|
+
assert.equal(vp1.info.name, 'veggie_name', 'First veggie property should be veggie_name')
|
|
528
|
+
assert.equal(vp2.info.name, 'veggie_like', 'Second veggie property should be veggie_like')
|
|
529
|
+
assert.isTrue(vp1.required, 'veggie_name should be required')
|
|
530
|
+
assert.isTrue(vp2.required, 'veggie_like should not be required')
|
|
531
|
+
})
|
|
532
|
+
|
|
533
|
+
test('imports EnumValues schema correctly', async ({ assert }) => {
|
|
534
|
+
const domain = await importSchemas([{ path: 'enumerated_values.json', contents: EnumValues as JSONSchema7 }])
|
|
535
|
+
const models = [...domain.listModels()]
|
|
536
|
+
assert.lengthOf(models, 1, 'Should import one model')
|
|
537
|
+
const entities = [...domain.listEntities()]
|
|
538
|
+
assert.lengthOf(entities, 1, 'Should import one entity')
|
|
539
|
+
const enumEntity = findEntityByName(domain, 'enumerated_values')
|
|
540
|
+
assert.exists(enumEntity, 'EnumeratedValues entity should exist')
|
|
541
|
+
const properties = [...enumEntity.listProperties()]
|
|
542
|
+
assert.lengthOf(properties, 1, 'EnumeratedValues entity should have one property')
|
|
543
|
+
const [p1] = properties
|
|
544
|
+
assert.equal(p1.info.name, 'data', 'Property should be data')
|
|
545
|
+
assert.deepEqual(
|
|
546
|
+
p1.schema?.enum,
|
|
547
|
+
['42', 'true', 'hello', 'null', '1,2,3'],
|
|
548
|
+
'Property should have correct enum values'
|
|
549
|
+
)
|
|
550
|
+
})
|
|
551
|
+
|
|
552
|
+
test('imports RegexpSchema schema correctly', async ({ assert }) => {
|
|
553
|
+
const domain = await importSchemas([{ path: 'regexp.json', contents: RegexpSchema as JSONSchema7 }])
|
|
554
|
+
const models = [...domain.listModels()]
|
|
555
|
+
assert.lengthOf(models, 1, 'Should import one model')
|
|
556
|
+
const entities = [...domain.listEntities()]
|
|
557
|
+
assert.lengthOf(entities, 1, 'Should import one entity')
|
|
558
|
+
const entity = findEntityByName(domain, 'regular_expression_pattern')
|
|
559
|
+
assert.exists(entity, 'RegularExpressionPattern entity should exist')
|
|
560
|
+
const properties = [...entity.listProperties()]
|
|
561
|
+
assert.lengthOf(properties, 1, 'RegularExpressionPattern entity should have one property')
|
|
562
|
+
const [p1] = properties
|
|
563
|
+
assert.equal(p1.info.name, 'code', 'Property should be code')
|
|
564
|
+
assert.equal(p1.schema?.pattern, '^[A-Z]{3}-\\d{3}$', 'Property should have correct pattern')
|
|
565
|
+
})
|
|
566
|
+
|
|
567
|
+
test('imports ComplexSchema schema correctly', async ({ assert }) => {
|
|
568
|
+
const domain = await importSchemas([{ path: 'complex.json', contents: ComplexSchema as JSONSchema7 }])
|
|
569
|
+
const models = [...domain.listModels()]
|
|
570
|
+
assert.lengthOf(models, 1, 'Should import one model')
|
|
571
|
+
const entities = [...domain.listEntities()]
|
|
572
|
+
assert.lengthOf(entities, 2, 'Should import two entities')
|
|
573
|
+
const entity = findEntityByName(domain, 'complex_object')
|
|
574
|
+
assert.exists(entity, 'ComplexObject entity should exist')
|
|
575
|
+
const properties = [...entity.listProperties()]
|
|
576
|
+
assert.lengthOf(properties, 3, 'ComplexObject entity should have three properties')
|
|
577
|
+
const [p1, p2, p3] = properties
|
|
578
|
+
assert.equal(p1.info.name, 'name', 'First property should be name')
|
|
579
|
+
assert.equal(p2.info.name, 'age', 'Second property should be age')
|
|
580
|
+
assert.equal(p3.info.name, 'hobbies', 'Third property should be hobbies')
|
|
581
|
+
const associations = [...entity.listAssociations()]
|
|
582
|
+
assert.lengthOf(associations, 1, 'ComplexObject entity should have one association')
|
|
583
|
+
const inlineEntity = findEntityByName(domain, 'complex_object_address')
|
|
584
|
+
assert.exists(inlineEntity, 'ComplexObjectAddress entity should exist')
|
|
585
|
+
const [a1] = associations
|
|
586
|
+
assert.deepEqual(a1.targets, [{ key: inlineEntity.key }], 'Association should target ComplexObjectAddress')
|
|
587
|
+
})
|
|
588
|
+
})
|