@e22m4u/js-repository 0.0.42 → 0.1.0

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.
Files changed (111) hide show
  1. package/.eslintignore +1 -0
  2. package/.husky/pre-commit +1 -0
  3. package/README.md +515 -577
  4. package/docs/.nojekyll +1 -0
  5. package/docs/assets/highlight.css +99 -0
  6. package/docs/assets/main.js +59 -0
  7. package/docs/assets/navigation.js +1 -0
  8. package/docs/assets/search.js +1 -0
  9. package/docs/assets/style.css +1394 -0
  10. package/docs/classes/Adapter.html +38 -0
  11. package/docs/classes/AdapterLoader.html +16 -0
  12. package/docs/classes/AdapterRegistry.html +16 -0
  13. package/docs/classes/BelongsToResolver.html +18 -0
  14. package/docs/classes/DatasourceDefinitionValidator.html +16 -0
  15. package/docs/classes/DefinitionRegistry.html +26 -0
  16. package/docs/classes/FieldsClauseTool.html +20 -0
  17. package/docs/classes/HasManyResolver.html +20 -0
  18. package/docs/classes/HasOneResolver.html +20 -0
  19. package/docs/classes/IncludeClauseTool.html +24 -0
  20. package/docs/classes/InvalidArgumentError.html +14 -0
  21. package/docs/classes/InvalidOperatorValueError.html +14 -0
  22. package/docs/classes/ModelDataSanitizer.html +16 -0
  23. package/docs/classes/ModelDataValidator.html +18 -0
  24. package/docs/classes/ModelDefinitionUtils.html +46 -0
  25. package/docs/classes/ModelDefinitionValidator.html +16 -0
  26. package/docs/classes/NotImplementedError.html +14 -0
  27. package/docs/classes/OperatorClauseTool.html +72 -0
  28. package/docs/classes/OrderClauseTool.html +20 -0
  29. package/docs/classes/PrimaryKeysDefinitionValidator.html +16 -0
  30. package/docs/classes/PropertiesDefinitionValidator.html +16 -0
  31. package/docs/classes/ReferencesManyResolver.html +16 -0
  32. package/docs/classes/RelationsDefinitionValidator.html +16 -0
  33. package/docs/classes/Repository.html +44 -0
  34. package/docs/classes/RepositoryRegistry.html +18 -0
  35. package/docs/classes/Schema.html +20 -0
  36. package/docs/classes/SliceClauseTool.html +20 -0
  37. package/docs/classes/WhereClauseTool.html +18 -0
  38. package/docs/enums/DataType.html +8 -0
  39. package/docs/enums/RelationType.html +6 -0
  40. package/docs/functions/capitalize.html +2 -0
  41. package/docs/functions/cloneDeep.html +2 -0
  42. package/docs/functions/excludeObjectKeys.html +2 -0
  43. package/docs/functions/getCtorName.html +2 -0
  44. package/docs/functions/getValueByPath.html +2 -0
  45. package/docs/functions/isCtor.html +2 -0
  46. package/docs/functions/isPureObject.html +2 -0
  47. package/docs/functions/selectObjectKeys.html +2 -0
  48. package/docs/functions/singularize.html +2 -0
  49. package/docs/functions/stringToRegexp.html +2 -0
  50. package/docs/index.html +284 -0
  51. package/docs/interfaces/AndClause.html +5 -0
  52. package/docs/interfaces/OrClause.html +5 -0
  53. package/docs/modules.html +80 -0
  54. package/docs/types/AnyObject.html +2 -0
  55. package/docs/types/BelongsToDefinition.html +6 -0
  56. package/docs/types/DEFAULT_PRIMARY_KEY_PROPERTY_NAME.html +2 -0
  57. package/docs/types/DatasourceDefinition.html +2 -0
  58. package/docs/types/FieldsClause.html +4 -0
  59. package/docs/types/FilterClause.html +2 -0
  60. package/docs/types/Flatten.html +1 -0
  61. package/docs/types/FullPropertyDefinition.html +2 -0
  62. package/docs/types/HasManyDefinition.html +4 -0
  63. package/docs/types/HasOneDefinition.html +4 -0
  64. package/docs/types/Identity.html +2 -0
  65. package/docs/types/IncludeClause.html +14 -0
  66. package/docs/types/ItemFilterClause.html +2 -0
  67. package/docs/types/ModelData.html +2 -0
  68. package/docs/types/ModelDefinition.html +2 -0
  69. package/docs/types/ModelId.html +2 -0
  70. package/docs/types/NestedIncludeClause.html +10 -0
  71. package/docs/types/NormalizedFieldsClause.html +4 -0
  72. package/docs/types/NormalizedIncludeClause.html +6 -0
  73. package/docs/types/OperatorClause.html +4 -0
  74. package/docs/types/OptionalUnlessRequiredId.html +2 -0
  75. package/docs/types/OrderClause.html +4 -0
  76. package/docs/types/PartialBy.html +2 -0
  77. package/docs/types/PartialWithoutId.html +2 -0
  78. package/docs/types/PolyBelongsToDefinition.html +6 -0
  79. package/docs/types/PolyHasManyDefinitionWithTargetKeys.html +4 -0
  80. package/docs/types/PolyHasManyDefinitionWithTargetRelationName.html +4 -0
  81. package/docs/types/PolyHasOneDefinitionWithTargetKeys.html +4 -0
  82. package/docs/types/PolyHasOneDefinitionWithTargetRelationName.html +4 -0
  83. package/docs/types/PropertiesClause.html +4 -0
  84. package/docs/types/PropertyDefinition.html +2 -0
  85. package/docs/types/PropertyDefinitionMap.html +2 -0
  86. package/docs/types/ReferencesManyDefinition.html +6 -0
  87. package/docs/types/RelationDefinition.html +4 -0
  88. package/docs/types/RelationDefinitionMap.html +2 -0
  89. package/docs/types/WhereClause.html +4 -0
  90. package/docs/types/WithoutId.html +2 -0
  91. package/package.json +14 -12
  92. package/src/adapter/adapter.d.ts +13 -0
  93. package/src/adapter/adapter.js +15 -0
  94. package/src/adapter/adapter.spec.js +8 -0
  95. package/src/adapter/builtin/memory-adapter.d.ts +13 -0
  96. package/src/adapter/builtin/memory-adapter.js +30 -0
  97. package/src/adapter/builtin/memory-adapter.spec.js +652 -0
  98. package/src/adapter/decorator/data-sanitizing-decorator.js +6 -0
  99. package/src/adapter/decorator/data-sanitizing-decorator.spec.js +13 -0
  100. package/src/adapter/decorator/data-validation-decorator.js +6 -0
  101. package/src/adapter/decorator/data-validation-decorator.spec.js +13 -0
  102. package/src/adapter/decorator/default-values-decorator.js +6 -0
  103. package/src/adapter/decorator/default-values-decorator.spec.js +16 -0
  104. package/src/adapter/decorator/fields-filtering-decorator.js +13 -0
  105. package/src/adapter/decorator/fields-filtering-decorator.spec.js +17 -0
  106. package/src/adapter/decorator/inclusion-decorator.js +13 -0
  107. package/src/adapter/decorator/inclusion-decorator.spec.js +17 -0
  108. package/src/definition/model/relations/relation-definition.d.ts +3 -3
  109. package/src/definition/model/relations/relations-definition-validator.js +4 -4
  110. package/src/repository/repository.js +2 -6
  111. package/typedoc.json +4 -0
@@ -154,6 +154,36 @@ export class MemoryAdapter extends Adapter {
154
154
  ).convertColumnNamesToPropertyNames(modelName, tableData);
155
155
  }
156
156
 
157
+ /**
158
+ * Replace or create.
159
+ *
160
+ * @param {string} modelName
161
+ * @param {object} modelData
162
+ * @param {object|undefined} filter
163
+ * @returns {Promise<object>}
164
+ */
165
+ async replaceOrCreate(modelName, modelData, filter = undefined) {
166
+ const pkPropName =
167
+ this.getService(ModelDefinitionUtils).getPrimaryKeyAsPropertyName(
168
+ modelName,
169
+ );
170
+ let idValue = modelData[pkPropName];
171
+ if (idValue == null) idValue = this._genNextIdValue(modelName, pkPropName);
172
+
173
+ const table = this._getTableOrCreate(modelName);
174
+ modelData = cloneDeep(modelData);
175
+ modelData[pkPropName] = idValue;
176
+
177
+ const tableData = this.getService(
178
+ ModelDefinitionUtils,
179
+ ).convertPropertyNamesToColumnNames(modelName, modelData);
180
+ table.set(idValue, tableData);
181
+
182
+ return this.getService(
183
+ ModelDefinitionUtils,
184
+ ).convertColumnNamesToPropertyNames(modelName, tableData);
185
+ }
186
+
157
187
  /**
158
188
  * Patch.
159
189
  *
@@ -1133,6 +1133,658 @@ describe('MemoryAdapter', function () {
1133
1133
  });
1134
1134
  });
1135
1135
 
1136
+ describe('replaceOrCreate', function () {
1137
+ it('generates a new identifier when a value of a primary key has not provided', async function () {
1138
+ const schema = new Schema();
1139
+ schema.defineDatasource({
1140
+ name: 'memory',
1141
+ adapter: 'memory',
1142
+ });
1143
+ schema.defineModel({
1144
+ name: 'model',
1145
+ datasource: 'memory',
1146
+ properties: {
1147
+ foo: DataType.STRING,
1148
+ bar: DataType.NUMBER,
1149
+ },
1150
+ });
1151
+ const adapter = new MemoryAdapter(schema.container, {});
1152
+ const input = {foo: 'string', bar: 10};
1153
+ const created = await adapter.replaceOrCreate('model', input);
1154
+ const idValue = created[DEF_PK];
1155
+ expect(created).to.be.eql({...input, [DEF_PK]: idValue});
1156
+ const table = adapter._getTableOrCreate('model');
1157
+ const tableData = table.get(idValue);
1158
+ expect(tableData).to.be.eql({...input, [DEF_PK]: idValue});
1159
+ });
1160
+
1161
+ it('generates a new identifier when a value of a primary key is undefined', async function () {
1162
+ const schema = new Schema();
1163
+ schema.defineDatasource({
1164
+ name: 'memory',
1165
+ adapter: 'memory',
1166
+ });
1167
+ schema.defineModel({
1168
+ name: 'model',
1169
+ datasource: 'memory',
1170
+ properties: {
1171
+ foo: DataType.STRING,
1172
+ bar: DataType.NUMBER,
1173
+ },
1174
+ });
1175
+ const adapter = new MemoryAdapter(schema.container, {});
1176
+ const input = {
1177
+ [DEF_PK]: undefined,
1178
+ foo: 'string',
1179
+ bar: 10,
1180
+ };
1181
+ const created = await adapter.replaceOrCreate('model', input);
1182
+ const idValue = created[DEF_PK];
1183
+ expect(created).to.be.eql({...input, [DEF_PK]: idValue});
1184
+ const table = adapter._getTableOrCreate('model');
1185
+ const tableData = table.get(idValue);
1186
+ expect(tableData).to.be.eql({...input, [DEF_PK]: idValue});
1187
+ });
1188
+
1189
+ it('generates a new identifier when a value of a primary key is null', async function () {
1190
+ const schema = new Schema();
1191
+ schema.defineDatasource({
1192
+ name: 'memory',
1193
+ adapter: 'memory',
1194
+ });
1195
+ schema.defineModel({
1196
+ name: 'model',
1197
+ datasource: 'memory',
1198
+ properties: {
1199
+ foo: DataType.STRING,
1200
+ bar: DataType.NUMBER,
1201
+ },
1202
+ });
1203
+ const adapter = new MemoryAdapter(schema.container, {});
1204
+ const input = {
1205
+ [DEF_PK]: null,
1206
+ foo: 'string',
1207
+ bar: 10,
1208
+ };
1209
+ const created = await adapter.replaceOrCreate('model', input);
1210
+ const idValue = created[DEF_PK];
1211
+ expect(created).to.be.eql({...input, [DEF_PK]: idValue});
1212
+ const table = adapter._getTableOrCreate('model');
1213
+ const tableData = table.get(idValue);
1214
+ expect(tableData).to.be.eql({...input, [DEF_PK]: idValue});
1215
+ });
1216
+
1217
+ it('generates a new identifier for a primary key of a "number" type', async function () {
1218
+ const schema = new Schema();
1219
+ schema.defineDatasource({
1220
+ name: 'memory',
1221
+ adapter: 'memory',
1222
+ });
1223
+ schema.defineModel({
1224
+ name: 'model',
1225
+ datasource: 'memory',
1226
+ properties: {
1227
+ myId: {
1228
+ type: DataType.NUMBER,
1229
+ primaryKey: true,
1230
+ },
1231
+ },
1232
+ });
1233
+ const adapter = new MemoryAdapter(schema.container, {});
1234
+ const result1 = await adapter.replaceOrCreate('model', {});
1235
+ const result2 = await adapter.replaceOrCreate('model', {});
1236
+ const result3 = await adapter.replaceOrCreate('model', {});
1237
+ expect(result1).to.be.eql({myId: 1});
1238
+ expect(result2).to.be.eql({myId: 2});
1239
+ expect(result3).to.be.eql({myId: 3});
1240
+ });
1241
+
1242
+ it('generates a new identifier for a primary key of an "any" type', async function () {
1243
+ const schema = new Schema();
1244
+ schema.defineDatasource({
1245
+ name: 'memory',
1246
+ adapter: 'memory',
1247
+ });
1248
+ schema.defineModel({
1249
+ name: 'model',
1250
+ datasource: 'memory',
1251
+ properties: {
1252
+ myId: {
1253
+ type: DataType.ANY,
1254
+ primaryKey: true,
1255
+ },
1256
+ },
1257
+ });
1258
+ const adapter = new MemoryAdapter(schema.container, {});
1259
+ const result1 = await adapter.replaceOrCreate('model', {});
1260
+ const result2 = await adapter.replaceOrCreate('model', {});
1261
+ const result3 = await adapter.replaceOrCreate('model', {});
1262
+ expect(result1).to.be.eql({myId: 1});
1263
+ expect(result2).to.be.eql({myId: 2});
1264
+ expect(result3).to.be.eql({myId: 3});
1265
+ });
1266
+
1267
+ it('throws an error when generating a new value for a primary key of a "string" type', async function () {
1268
+ const schema = new Schema();
1269
+ schema.defineDatasource({
1270
+ name: 'memory',
1271
+ adapter: 'memory',
1272
+ });
1273
+ schema.defineModel({
1274
+ name: 'model',
1275
+ datasource: 'memory',
1276
+ properties: {
1277
+ myId: {
1278
+ type: DataType.STRING,
1279
+ primaryKey: true,
1280
+ },
1281
+ },
1282
+ });
1283
+ const adapter = new MemoryAdapter(schema.container, {});
1284
+ const promise = adapter.replaceOrCreate('model', {
1285
+ foo: 'string',
1286
+ bar: 10,
1287
+ });
1288
+ await expect(promise).to.be.rejectedWith(
1289
+ 'The memory adapter able to generate only Number identifiers, ' +
1290
+ 'but the primary key "myId" of the model "model" is defined as String. ' +
1291
+ 'Do provide your own value for the "myId" property, or change the type ' +
1292
+ 'in the primary key definition to a Number that will be ' +
1293
+ 'generated automatically.',
1294
+ );
1295
+ });
1296
+
1297
+ it('throws an error when generating a new value for a primary key of a "boolean" type', async function () {
1298
+ const schema = new Schema();
1299
+ schema.defineDatasource({
1300
+ name: 'memory',
1301
+ adapter: 'memory',
1302
+ });
1303
+ schema.defineModel({
1304
+ name: 'model',
1305
+ datasource: 'memory',
1306
+ properties: {
1307
+ myId: {
1308
+ type: DataType.BOOLEAN,
1309
+ primaryKey: true,
1310
+ },
1311
+ },
1312
+ });
1313
+ const adapter = new MemoryAdapter(schema.container, {});
1314
+ const promise = adapter.replaceOrCreate('model', {
1315
+ foo: 'string',
1316
+ bar: 10,
1317
+ });
1318
+ await expect(promise).to.be.rejectedWith(
1319
+ 'The memory adapter able to generate only Number identifiers, ' +
1320
+ 'but the primary key "myId" of the model "model" is defined as Boolean. ' +
1321
+ 'Do provide your own value for the "myId" property, or change the type ' +
1322
+ 'in the primary key definition to a Number that will be ' +
1323
+ 'generated automatically.',
1324
+ );
1325
+ });
1326
+
1327
+ it('throws an error when generating a new value for a primary key of an "array" type', async function () {
1328
+ const schema = new Schema();
1329
+ schema.defineDatasource({
1330
+ name: 'memory',
1331
+ adapter: 'memory',
1332
+ });
1333
+ schema.defineModel({
1334
+ name: 'model',
1335
+ datasource: 'memory',
1336
+ properties: {
1337
+ myId: {
1338
+ type: DataType.ARRAY,
1339
+ itemType: DataType.NUMBER,
1340
+ primaryKey: true,
1341
+ },
1342
+ },
1343
+ });
1344
+ const adapter = new MemoryAdapter(schema.container, {});
1345
+ const promise = adapter.replaceOrCreate('model', {});
1346
+ await expect(promise).to.be.rejectedWith(
1347
+ 'The memory adapter able to generate only Number identifiers, ' +
1348
+ 'but the primary key "myId" of the model "model" is defined as Array. ' +
1349
+ 'Do provide your own value for the "myId" property, or change the type ' +
1350
+ 'in the primary key definition to a Number that will be ' +
1351
+ 'generated automatically.',
1352
+ );
1353
+ });
1354
+
1355
+ it('throws an error when generating a new value for a primary key of an "object" type', async function () {
1356
+ const schema = new Schema();
1357
+ schema.defineDatasource({
1358
+ name: 'memory',
1359
+ adapter: 'memory',
1360
+ });
1361
+ schema.defineModel({
1362
+ name: 'model',
1363
+ datasource: 'memory',
1364
+ properties: {
1365
+ myId: {
1366
+ type: DataType.OBJECT,
1367
+ primaryKey: true,
1368
+ },
1369
+ },
1370
+ });
1371
+ const adapter = new MemoryAdapter(schema.container, {});
1372
+ const promise = adapter.replaceOrCreate('model', {});
1373
+ await expect(promise).to.be.rejectedWith(
1374
+ 'The memory adapter able to generate only Number identifiers, ' +
1375
+ 'but the primary key "myId" of the model "model" is defined as Object. ' +
1376
+ 'Do provide your own value for the "myId" property, or change the type ' +
1377
+ 'in the primary key definition to a Number that will be ' +
1378
+ 'generated automatically.',
1379
+ );
1380
+ });
1381
+
1382
+ it('allows to specify an identifier value for a new item', async function () {
1383
+ const schema = new Schema();
1384
+ schema.defineDatasource({
1385
+ name: 'memory',
1386
+ adapter: 'memory',
1387
+ });
1388
+ schema.defineModel({
1389
+ name: 'model',
1390
+ datasource: 'memory',
1391
+ properties: {
1392
+ foo: DataType.STRING,
1393
+ bar: DataType.NUMBER,
1394
+ },
1395
+ });
1396
+ const adapter = new MemoryAdapter(schema.container, {});
1397
+ const idValue = 5;
1398
+ const input = {foo: 'string', bar: 10};
1399
+ const created = await adapter.replaceOrCreate('model', {
1400
+ [DEF_PK]: idValue,
1401
+ ...input,
1402
+ });
1403
+ expect(created).to.be.eql({[DEF_PK]: idValue, ...input});
1404
+ const table = adapter._getTableOrCreate('model');
1405
+ const tableData = table.get(idValue);
1406
+ expect(tableData).to.be.eql({[DEF_PK]: idValue, ...input});
1407
+ });
1408
+
1409
+ it('sets default values if they are not provided for a new item', async function () {
1410
+ const schema = new Schema();
1411
+ schema.defineDatasource({
1412
+ name: 'memory',
1413
+ adapter: 'memory',
1414
+ });
1415
+ schema.defineModel({
1416
+ name: 'model',
1417
+ datasource: 'memory',
1418
+ properties: {
1419
+ foo: {
1420
+ type: DataType.NUMBER,
1421
+ default: 10,
1422
+ },
1423
+ bar: {
1424
+ type: DataType.STRING,
1425
+ default: 'string',
1426
+ },
1427
+ },
1428
+ });
1429
+ const adapter = new MemoryAdapter(schema.container, {});
1430
+ const created = await adapter.replaceOrCreate('model', {});
1431
+ const idValue = created[DEF_PK];
1432
+ const defaults = {foo: 10, bar: 'string'};
1433
+ expect(created).to.be.eql({[DEF_PK]: idValue, ...defaults});
1434
+ const table = adapter._getTableOrCreate('model');
1435
+ const tableData = table.get(idValue);
1436
+ expect(tableData).to.be.eql({[DEF_PK]: idValue, ...defaults});
1437
+ });
1438
+
1439
+ it('sets default values for properties provided with an undefined value', async function () {
1440
+ const schema = new Schema();
1441
+ schema.defineDatasource({
1442
+ name: 'memory',
1443
+ adapter: 'memory',
1444
+ });
1445
+ schema.defineModel({
1446
+ name: 'model',
1447
+ datasource: 'memory',
1448
+ properties: {
1449
+ foo: {
1450
+ type: DataType.NUMBER,
1451
+ default: 1,
1452
+ },
1453
+ bar: {
1454
+ type: DataType.NUMBER,
1455
+ default: 2,
1456
+ },
1457
+ },
1458
+ });
1459
+ const adapter = new MemoryAdapter(schema.container, {});
1460
+ const created = await adapter.replaceOrCreate('model', {foo: undefined});
1461
+ const idValue = created[DEF_PK];
1462
+ const defaults = {foo: 1, bar: 2};
1463
+ expect(created).to.be.eql({[DEF_PK]: idValue, ...defaults});
1464
+ const table = adapter._getTableOrCreate('model');
1465
+ const tableData = table.get(idValue);
1466
+ expect(tableData).to.be.eql({[DEF_PK]: idValue, ...defaults});
1467
+ });
1468
+
1469
+ it('sets default values for properties provided with a null value', async function () {
1470
+ const schema = new Schema();
1471
+ schema.defineDatasource({
1472
+ name: 'memory',
1473
+ adapter: 'memory',
1474
+ });
1475
+ schema.defineModel({
1476
+ name: 'model',
1477
+ datasource: 'memory',
1478
+ properties: {
1479
+ foo: {
1480
+ type: DataType.NUMBER,
1481
+ default: 1,
1482
+ },
1483
+ bar: {
1484
+ type: DataType.NUMBER,
1485
+ default: 2,
1486
+ },
1487
+ },
1488
+ });
1489
+ const adapter = new MemoryAdapter(schema.container, {});
1490
+ const created = await adapter.replaceOrCreate('model', {foo: null});
1491
+ const idValue = created[DEF_PK];
1492
+ const defaults = {foo: 1, bar: 2};
1493
+ expect(created).to.be.eql({[DEF_PK]: idValue, ...defaults});
1494
+ const table = adapter._getTableOrCreate('model');
1495
+ const tableData = table.get(idValue);
1496
+ expect(tableData).to.be.eql({[DEF_PK]: idValue, ...defaults});
1497
+ });
1498
+
1499
+ it('uses a specified column name for a primary key', async function () {
1500
+ const schema = new Schema();
1501
+ schema.defineDatasource({
1502
+ name: 'memory',
1503
+ adapter: 'memory',
1504
+ });
1505
+ schema.defineModel({
1506
+ name: 'model',
1507
+ datasource: 'memory',
1508
+ properties: {
1509
+ foo: {
1510
+ type: DataType.NUMBER,
1511
+ primaryKey: true,
1512
+ columnName: 'bar',
1513
+ },
1514
+ },
1515
+ });
1516
+ const adapter = new MemoryAdapter(schema.container, {});
1517
+ const created = await adapter.replaceOrCreate('model', {});
1518
+ expect(created).to.be.eql({foo: created.foo});
1519
+ const table = adapter._getTableOrCreate('model');
1520
+ const tableData = table.get(created.foo);
1521
+ expect(tableData).to.be.eql({bar: created.foo});
1522
+ });
1523
+
1524
+ it('uses a specified column name for a regular property', async function () {
1525
+ const schema = new Schema();
1526
+ schema.defineDatasource({
1527
+ name: 'memory',
1528
+ adapter: 'memory',
1529
+ });
1530
+ schema.defineModel({
1531
+ name: 'model',
1532
+ datasource: 'memory',
1533
+ properties: {
1534
+ foo: {
1535
+ type: DataType.NUMBER,
1536
+ columnName: 'bar',
1537
+ },
1538
+ },
1539
+ });
1540
+ const adapter = new MemoryAdapter(schema.container, {});
1541
+ const created = await adapter.replaceOrCreate('model', {foo: 10});
1542
+ const idValue = created[DEF_PK];
1543
+ expect(created).to.be.eql({[DEF_PK]: idValue, foo: 10});
1544
+ const table = adapter._getTableOrCreate('model');
1545
+ const tableData = table.get(idValue);
1546
+ expect(tableData).to.be.eql({[DEF_PK]: idValue, bar: 10});
1547
+ });
1548
+
1549
+ it('uses a specified column name for a regular property with a default value', async function () {
1550
+ const schema = new Schema();
1551
+ schema.defineDatasource({
1552
+ name: 'memory',
1553
+ adapter: 'memory',
1554
+ });
1555
+ schema.defineModel({
1556
+ name: 'model',
1557
+ datasource: 'memory',
1558
+ properties: {
1559
+ foo: {
1560
+ type: DataType.NUMBER,
1561
+ columnName: 'bar',
1562
+ default: 10,
1563
+ },
1564
+ },
1565
+ });
1566
+ const adapter = new MemoryAdapter(schema.container, {});
1567
+ const created = await adapter.replaceOrCreate('model', {});
1568
+ const idValue = created[DEF_PK];
1569
+ expect(created).to.be.eql({[DEF_PK]: idValue, foo: 10});
1570
+ const table = adapter._getTableOrCreate('model');
1571
+ const tableData = table.get(idValue);
1572
+ expect(tableData).to.be.eql({[DEF_PK]: idValue, bar: 10});
1573
+ });
1574
+
1575
+ it('uses a short form of a fields clause to filter a return value', async function () {
1576
+ const schema = new Schema();
1577
+ schema.defineDatasource({
1578
+ name: 'memory',
1579
+ adapter: 'memory',
1580
+ });
1581
+ schema.defineModel({
1582
+ name: 'model',
1583
+ datasource: 'memory',
1584
+ properties: {
1585
+ foo: DataType.STRING,
1586
+ bar: DataType.NUMBER,
1587
+ },
1588
+ });
1589
+ const adapter = new MemoryAdapter(schema.container, {});
1590
+ const input = {foo: 'string', bar: 10};
1591
+ const filter = {fields: 'foo'};
1592
+ const result = await adapter.replaceOrCreate('model', input, filter);
1593
+ expect(result).to.be.eql({[DEF_PK]: result[DEF_PK], foo: input.foo});
1594
+ });
1595
+
1596
+ it('uses a full form of a fields clause to filter a return value', async function () {
1597
+ const schema = new Schema();
1598
+ schema.defineDatasource({
1599
+ name: 'memory',
1600
+ adapter: 'memory',
1601
+ });
1602
+ schema.defineModel({
1603
+ name: 'model',
1604
+ datasource: 'memory',
1605
+ properties: {
1606
+ foo: DataType.STRING,
1607
+ bar: DataType.NUMBER,
1608
+ baz: DataType.BOOLEAN,
1609
+ },
1610
+ });
1611
+ const adapter = new MemoryAdapter(schema.container, {});
1612
+ const input = {foo: 'string', bar: 10, baz: true};
1613
+ const filter = {fields: ['foo', 'bar']};
1614
+ const result = await adapter.replaceOrCreate('model', input, filter);
1615
+ expect(result).to.be.eql({
1616
+ [DEF_PK]: result[DEF_PK],
1617
+ foo: input.foo,
1618
+ bar: input.bar,
1619
+ });
1620
+ });
1621
+
1622
+ it('a fields clause uses property names instead of column names', async function () {
1623
+ const schema = new Schema();
1624
+ schema.defineDatasource({
1625
+ name: 'memory',
1626
+ adapter: 'memory',
1627
+ });
1628
+ schema.defineModel({
1629
+ name: 'model',
1630
+ datasource: 'memory',
1631
+ properties: {
1632
+ foo: {
1633
+ type: DataType.STRING,
1634
+ columnName: 'fooCol',
1635
+ },
1636
+ bar: {
1637
+ type: DataType.NUMBER,
1638
+ columnName: 'barCol',
1639
+ },
1640
+ baz: {
1641
+ type: DataType.BOOLEAN,
1642
+ columnName: 'bazCol',
1643
+ },
1644
+ },
1645
+ });
1646
+ const adapter = new MemoryAdapter(schema.container, {});
1647
+ const input = {foo: 'string', bar: 10, baz: true};
1648
+ const filter = {fields: ['foo', 'bar']};
1649
+ const result = await adapter.replaceOrCreate('model', input, filter);
1650
+ expect(result).to.be.eql({
1651
+ [DEF_PK]: result[DEF_PK],
1652
+ foo: input.foo,
1653
+ bar: input.bar,
1654
+ });
1655
+ });
1656
+
1657
+ it('removes properties when replacing an item by a given identifier', async function () {
1658
+ const schema = new Schema();
1659
+ schema.defineDatasource({
1660
+ name: 'memory',
1661
+ adapter: 'memory',
1662
+ });
1663
+ schema.defineModel({
1664
+ name: 'model',
1665
+ datasource: 'memory',
1666
+ properties: {
1667
+ foo: DataType.NUMBER,
1668
+ bar: DataType.NUMBER,
1669
+ },
1670
+ });
1671
+ const adapter = new MemoryAdapter(schema.container, {});
1672
+ const input = {foo: 1, bar: 2};
1673
+ const created = await adapter.create('model', input);
1674
+ const idValue = created[DEF_PK];
1675
+ expect(created).to.be.eql({[DEF_PK]: idValue, ...input});
1676
+ const replacement = {[DEF_PK]: idValue, foo: 2};
1677
+ const replaced = await adapter.replaceOrCreate('model', replacement);
1678
+ expect(replaced).to.be.eql(replacement);
1679
+ const table = adapter._getTableOrCreate('model');
1680
+ const tableData = table.get(idValue);
1681
+ expect(tableData).to.be.eql(replacement);
1682
+ });
1683
+
1684
+ it('sets a default values for removed properties when replacing an item', async function () {
1685
+ const schema = new Schema();
1686
+ schema.defineDatasource({
1687
+ name: 'memory',
1688
+ adapter: 'memory',
1689
+ });
1690
+ schema.defineModel({
1691
+ name: 'model',
1692
+ datasource: 'memory',
1693
+ properties: {
1694
+ foo: {
1695
+ type: DataType.NUMBER,
1696
+ default: 1,
1697
+ },
1698
+ bar: {
1699
+ type: DataType.NUMBER,
1700
+ default: 2,
1701
+ },
1702
+ },
1703
+ });
1704
+ const adapter = new MemoryAdapter(schema.container, {});
1705
+ const created = await adapter.create('model', {});
1706
+ const idValue = created[DEF_PK];
1707
+ const defaults = {foo: 1, bar: 2};
1708
+ expect(created).to.be.eql({[DEF_PK]: idValue, ...defaults});
1709
+ const replacement = {[DEF_PK]: idValue, foo: 2};
1710
+ const replaced = await adapter.replaceOrCreate('model', replacement);
1711
+ expect(replaced).to.be.eql({...defaults, ...replacement});
1712
+ const table = adapter._getTableOrCreate('model');
1713
+ const tableData = table.get(idValue);
1714
+ expect(tableData).to.be.eql({...defaults, ...replacement});
1715
+ });
1716
+
1717
+ it('sets a default values for replaced properties with an undefined value', async function () {
1718
+ const schema = new Schema();
1719
+ schema.defineDatasource({
1720
+ name: 'memory',
1721
+ adapter: 'memory',
1722
+ });
1723
+ schema.defineModel({
1724
+ name: 'model',
1725
+ datasource: 'memory',
1726
+ properties: {
1727
+ foo: {
1728
+ type: DataType.NUMBER,
1729
+ default: 1,
1730
+ },
1731
+ bar: {
1732
+ type: DataType.NUMBER,
1733
+ default: 2,
1734
+ },
1735
+ },
1736
+ });
1737
+ const adapter = new MemoryAdapter(schema.container, {});
1738
+ const created = await adapter.create('model', {});
1739
+ const idValue = created[DEF_PK];
1740
+ const defaults = {foo: 1, bar: 2};
1741
+ expect(created).to.be.eql({[DEF_PK]: idValue, ...defaults});
1742
+ const replaced = await adapter.replaceOrCreate('model', {
1743
+ [DEF_PK]: idValue,
1744
+ foo: undefined,
1745
+ });
1746
+ expect(replaced).to.be.eql({[DEF_PK]: idValue, ...defaults});
1747
+ const table = adapter._getTableOrCreate('model');
1748
+ const tableData = table.get(idValue);
1749
+ expect(tableData).to.be.eql({[DEF_PK]: idValue, ...defaults});
1750
+ });
1751
+
1752
+ it('sets a default values for replaced properties with a null value', async function () {
1753
+ const schema = new Schema();
1754
+ schema.defineDatasource({
1755
+ name: 'memory',
1756
+ adapter: 'memory',
1757
+ });
1758
+ schema.defineModel({
1759
+ name: 'model',
1760
+ datasource: 'memory',
1761
+ properties: {
1762
+ foo: {
1763
+ type: DataType.NUMBER,
1764
+ default: 1,
1765
+ },
1766
+ bar: {
1767
+ type: DataType.NUMBER,
1768
+ default: 2,
1769
+ },
1770
+ },
1771
+ });
1772
+ const adapter = new MemoryAdapter(schema.container, {});
1773
+ const created = await adapter.create('model', {});
1774
+ const idValue = created[DEF_PK];
1775
+ const defaults = {foo: 1, bar: 2};
1776
+ expect(created).to.be.eql({[DEF_PK]: idValue, ...defaults});
1777
+ const replaced = await adapter.replaceOrCreate('model', {
1778
+ [DEF_PK]: idValue,
1779
+ foo: null,
1780
+ });
1781
+ expect(replaced).to.be.eql({[DEF_PK]: idValue, ...defaults});
1782
+ const table = adapter._getTableOrCreate('model');
1783
+ const tableData = table.get(idValue);
1784
+ expect(tableData).to.be.eql({[DEF_PK]: idValue, ...defaults});
1785
+ });
1786
+ });
1787
+
1136
1788
  describe('patch', function () {
1137
1789
  it('updates only provided properties for all items and returns their number', async function () {
1138
1790
  const schema = new Schema();
@@ -35,6 +35,12 @@ export class DataSanitizingDecorator extends Service {
35
35
  return replaceById.call(this, modelName, id, modelData, filter);
36
36
  };
37
37
 
38
+ const replaceOrCreate = adapter.replaceOrCreate;
39
+ adapter.replaceOrCreate = async function (modelName, modelData, filter) {
40
+ modelData = sanitize(modelName, modelData);
41
+ return replaceOrCreate.call(this, modelName, modelData, filter);
42
+ };
43
+
38
44
  const patch = adapter.patch;
39
45
  adapter.patch = async function (modelName, modelData, where) {
40
46
  modelData = sanitize(modelName, modelData);