@api-client/core 0.18.5 → 0.18.7

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.
@@ -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
+ })