@e22m4u/js-repository-mongodb-adapter 0.8.2 → 0.8.3
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/cjs/index.cjs +163 -65
- package/eslint.config.js +1 -0
- package/package.json +13 -13
- package/src/mongodb-adapter.js +127 -48
- package/src/utils/create-mongodb-url.js +14 -7
- package/src/utils/is-iso-date.js +9 -3
- package/src/utils/is-object-id.js +9 -3
- package/src/utils/to-camel-case.js +6 -2
- package/src/utils/transform-values-deep.js +4 -2
package/dist/cjs/index.cjs
CHANGED
|
@@ -860,9 +860,15 @@ __name(pluralize, "pluralize");
|
|
|
860
860
|
|
|
861
861
|
// src/utils/is-iso-date.js
|
|
862
862
|
function isIsoDate(value) {
|
|
863
|
-
if (!value)
|
|
864
|
-
|
|
865
|
-
|
|
863
|
+
if (!value) {
|
|
864
|
+
return false;
|
|
865
|
+
}
|
|
866
|
+
if (value instanceof Date) {
|
|
867
|
+
return true;
|
|
868
|
+
}
|
|
869
|
+
if (!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(value)) {
|
|
870
|
+
return false;
|
|
871
|
+
}
|
|
866
872
|
const d = new Date(value);
|
|
867
873
|
return d instanceof Date && !isNaN(d.getTime()) && d.toISOString() === value;
|
|
868
874
|
}
|
|
@@ -871,19 +877,29 @@ __name(isIsoDate, "isIsoDate");
|
|
|
871
877
|
// src/utils/is-object-id.js
|
|
872
878
|
var import_mongodb = require("mongodb");
|
|
873
879
|
function isObjectId(value) {
|
|
874
|
-
if (!value)
|
|
875
|
-
|
|
876
|
-
|
|
880
|
+
if (!value) {
|
|
881
|
+
return false;
|
|
882
|
+
}
|
|
883
|
+
if (value instanceof import_mongodb.ObjectId) {
|
|
884
|
+
return true;
|
|
885
|
+
}
|
|
886
|
+
if (typeof value !== "string") {
|
|
887
|
+
return false;
|
|
888
|
+
}
|
|
877
889
|
return value.match(/^[a-fA-F0-9]{24}$/) != null;
|
|
878
890
|
}
|
|
879
891
|
__name(isObjectId, "isObjectId");
|
|
880
892
|
|
|
881
893
|
// src/utils/to-camel-case.js
|
|
882
894
|
function toCamelCase2(input) {
|
|
883
|
-
if (!input)
|
|
895
|
+
if (!input) {
|
|
896
|
+
return "";
|
|
897
|
+
}
|
|
884
898
|
const spacedString = String(input).replace(/([-_])/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2");
|
|
885
899
|
const intermediateCased = spacedString.toLowerCase().replace(/\s(.)/g, ($1) => $1.toUpperCase()).replace(/\s/g, "");
|
|
886
|
-
if (!intermediateCased)
|
|
900
|
+
if (!intermediateCased) {
|
|
901
|
+
return "";
|
|
902
|
+
}
|
|
887
903
|
return intermediateCased.charAt(0).toLowerCase() + intermediateCased.slice(1);
|
|
888
904
|
}
|
|
889
905
|
__name(toCamelCase2, "toCamelCase");
|
|
@@ -891,47 +907,54 @@ __name(toCamelCase2, "toCamelCase");
|
|
|
891
907
|
// src/utils/create-mongodb-url.js
|
|
892
908
|
var import_js_repository = require("@e22m4u/js-repository");
|
|
893
909
|
function createMongodbUrl(options = {}) {
|
|
894
|
-
if (!options || typeof options !== "object" || Array.isArray(options))
|
|
910
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
895
911
|
throw new import_js_repository.InvalidArgumentError(
|
|
896
912
|
'The first argument of "createMongodbUrl" must be an Object, but %v given.',
|
|
897
913
|
options
|
|
898
914
|
);
|
|
899
|
-
|
|
915
|
+
}
|
|
916
|
+
if (options.protocol && typeof options.protocol !== "string") {
|
|
900
917
|
throw new import_js_repository.InvalidArgumentError(
|
|
901
918
|
'MongoDB option "protocol" must be a String, but %v given.',
|
|
902
919
|
options.protocol
|
|
903
920
|
);
|
|
904
|
-
|
|
921
|
+
}
|
|
922
|
+
if (options.hostname && typeof options.hostname !== "string") {
|
|
905
923
|
throw new import_js_repository.InvalidArgumentError(
|
|
906
924
|
'MongoDB option "hostname" must be a String, but %v given.',
|
|
907
925
|
options.hostname
|
|
908
926
|
);
|
|
909
|
-
|
|
927
|
+
}
|
|
928
|
+
if (options.host && typeof options.host !== "string") {
|
|
910
929
|
throw new import_js_repository.InvalidArgumentError(
|
|
911
930
|
'MongoDB option "host" must be a String, but %v given.',
|
|
912
931
|
options.host
|
|
913
932
|
);
|
|
933
|
+
}
|
|
914
934
|
if (options.port && typeof options.port !== "number" && typeof options.port !== "string") {
|
|
915
935
|
throw new import_js_repository.InvalidArgumentError(
|
|
916
936
|
'MongoDB option "port" must be a Number or a String, but %v given.',
|
|
917
937
|
options.port
|
|
918
938
|
);
|
|
919
939
|
}
|
|
920
|
-
if (options.database && typeof options.database !== "string")
|
|
940
|
+
if (options.database && typeof options.database !== "string") {
|
|
921
941
|
throw new import_js_repository.InvalidArgumentError(
|
|
922
942
|
'MongoDB option "database" must be a String, but %v given.',
|
|
923
943
|
options.database
|
|
924
944
|
);
|
|
925
|
-
|
|
945
|
+
}
|
|
946
|
+
if (options.db && typeof options.db !== "string") {
|
|
926
947
|
throw new import_js_repository.InvalidArgumentError(
|
|
927
948
|
'MongoDB option "db" must be a String, but %v given.',
|
|
928
949
|
options.db
|
|
929
950
|
);
|
|
930
|
-
|
|
951
|
+
}
|
|
952
|
+
if (options.username && typeof options.username !== "string") {
|
|
931
953
|
throw new import_js_repository.InvalidArgumentError(
|
|
932
954
|
'MongoDB option "username" must be a String, but %v given.',
|
|
933
955
|
options.username
|
|
934
956
|
);
|
|
957
|
+
}
|
|
935
958
|
if (options.password && typeof options.password !== "string" && typeof options.password !== "number") {
|
|
936
959
|
throw new import_js_repository.InvalidArgumentError(
|
|
937
960
|
'MongoDB option "password" must be a String or a Number, but %v given.',
|
|
@@ -965,19 +988,21 @@ __name(createMongodbUrl, "createMongodbUrl");
|
|
|
965
988
|
// src/utils/transform-values-deep.js
|
|
966
989
|
var import_js_repository2 = require("@e22m4u/js-repository");
|
|
967
990
|
function transformValuesDeep(value, transformer) {
|
|
968
|
-
if (!transformer || typeof transformer !== "function")
|
|
991
|
+
if (!transformer || typeof transformer !== "function") {
|
|
969
992
|
throw new import_js_repository2.InvalidArgumentError(
|
|
970
993
|
'The second argument of "transformValuesDeep" must be a Function, but %v given.',
|
|
971
994
|
transformer
|
|
972
995
|
);
|
|
996
|
+
}
|
|
973
997
|
if (Array.isArray(value)) {
|
|
974
998
|
value.forEach((v, i) => value[i] = transformValuesDeep(v, transformer));
|
|
975
999
|
return value;
|
|
976
1000
|
} else if (value && typeof value === "object") {
|
|
977
1001
|
if (!value.constructor || value.constructor && value.constructor.name === "Object") {
|
|
978
1002
|
Object.keys(value).forEach((key) => {
|
|
979
|
-
if (Object.prototype.hasOwnProperty.call(value, key))
|
|
1003
|
+
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
980
1004
|
value[key] = transformValuesDeep(value[key], transformer);
|
|
1005
|
+
}
|
|
981
1006
|
});
|
|
982
1007
|
return value;
|
|
983
1008
|
} else {
|
|
@@ -1158,8 +1183,12 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1158
1183
|
* @returns {ObjectId|*}
|
|
1159
1184
|
*/
|
|
1160
1185
|
_coerceId(value) {
|
|
1161
|
-
if (value == null)
|
|
1162
|
-
|
|
1186
|
+
if (value == null) {
|
|
1187
|
+
return value;
|
|
1188
|
+
}
|
|
1189
|
+
if (isObjectId(value)) {
|
|
1190
|
+
return new import_mongodb2.ObjectId(value);
|
|
1191
|
+
}
|
|
1163
1192
|
return value;
|
|
1164
1193
|
}
|
|
1165
1194
|
/**
|
|
@@ -1169,9 +1198,15 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1169
1198
|
* @returns {Date|*}
|
|
1170
1199
|
*/
|
|
1171
1200
|
_coerceDate(value) {
|
|
1172
|
-
if (value == null)
|
|
1173
|
-
|
|
1174
|
-
|
|
1201
|
+
if (value == null) {
|
|
1202
|
+
return value;
|
|
1203
|
+
}
|
|
1204
|
+
if (value instanceof Date) {
|
|
1205
|
+
return value;
|
|
1206
|
+
}
|
|
1207
|
+
if (isIsoDate(value)) {
|
|
1208
|
+
return new Date(value);
|
|
1209
|
+
}
|
|
1175
1210
|
return value;
|
|
1176
1211
|
}
|
|
1177
1212
|
/**
|
|
@@ -1186,20 +1221,29 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1186
1221
|
import_js_repository3.ModelDefinitionUtils
|
|
1187
1222
|
).convertPropertyNamesToColumnNames(modelName, modelData);
|
|
1188
1223
|
const idColName = this._getIdColName(modelName);
|
|
1189
|
-
if (idColName !== "id" && idColName !== "_id")
|
|
1224
|
+
if (idColName !== "id" && idColName !== "_id") {
|
|
1190
1225
|
throw new import_js_repository3.InvalidArgumentError(
|
|
1191
1226
|
'MongoDB is not supporting custom names of the primary key. Do use "id" as a primary key instead of %v.',
|
|
1192
1227
|
idColName
|
|
1193
1228
|
);
|
|
1229
|
+
}
|
|
1194
1230
|
if (idColName in tableData && idColName !== "_id") {
|
|
1195
1231
|
tableData._id = tableData[idColName];
|
|
1196
1232
|
delete tableData[idColName];
|
|
1197
1233
|
}
|
|
1198
1234
|
return transformValuesDeep(tableData, (value) => {
|
|
1199
|
-
if (value instanceof import_mongodb2.ObjectId)
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
if (
|
|
1235
|
+
if (value instanceof import_mongodb2.ObjectId) {
|
|
1236
|
+
return value;
|
|
1237
|
+
}
|
|
1238
|
+
if (value instanceof Date) {
|
|
1239
|
+
return value;
|
|
1240
|
+
}
|
|
1241
|
+
if (isObjectId(value)) {
|
|
1242
|
+
return new import_mongodb2.ObjectId(value);
|
|
1243
|
+
}
|
|
1244
|
+
if (isIsoDate(value)) {
|
|
1245
|
+
return new Date(value);
|
|
1246
|
+
}
|
|
1203
1247
|
return value;
|
|
1204
1248
|
});
|
|
1205
1249
|
}
|
|
@@ -1213,11 +1257,12 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1213
1257
|
_fromDatabase(modelName, tableData) {
|
|
1214
1258
|
if ("_id" in tableData) {
|
|
1215
1259
|
const idColName = this._getIdColName(modelName);
|
|
1216
|
-
if (idColName !== "id" && idColName !== "_id")
|
|
1260
|
+
if (idColName !== "id" && idColName !== "_id") {
|
|
1217
1261
|
throw new import_js_repository3.InvalidArgumentError(
|
|
1218
1262
|
'MongoDB is not supporting custom names of the primary key. Do use "id" as a primary key instead of %v.',
|
|
1219
1263
|
idColName
|
|
1220
1264
|
);
|
|
1265
|
+
}
|
|
1221
1266
|
if (idColName !== "_id") {
|
|
1222
1267
|
tableData[idColName] = tableData._id;
|
|
1223
1268
|
delete tableData._id;
|
|
@@ -1227,8 +1272,12 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1227
1272
|
import_js_repository3.ModelDefinitionUtils
|
|
1228
1273
|
).convertColumnNamesToPropertyNames(modelName, tableData);
|
|
1229
1274
|
return transformValuesDeep(modelData, (value) => {
|
|
1230
|
-
if (value instanceof import_mongodb2.ObjectId)
|
|
1231
|
-
|
|
1275
|
+
if (value instanceof import_mongodb2.ObjectId) {
|
|
1276
|
+
return String(value);
|
|
1277
|
+
}
|
|
1278
|
+
if (value instanceof Date) {
|
|
1279
|
+
return value.toISOString();
|
|
1280
|
+
}
|
|
1232
1281
|
return value;
|
|
1233
1282
|
});
|
|
1234
1283
|
}
|
|
@@ -1240,7 +1289,9 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1240
1289
|
*/
|
|
1241
1290
|
_getCollectionNameByModelName(modelName) {
|
|
1242
1291
|
const modelDef = this.getService(import_js_repository3.DefinitionRegistry).getModel(modelName);
|
|
1243
|
-
if (modelDef.tableName != null)
|
|
1292
|
+
if (modelDef.tableName != null) {
|
|
1293
|
+
return modelDef.tableName;
|
|
1294
|
+
}
|
|
1244
1295
|
return pluralize(toCamelCase2(modelDef.name));
|
|
1245
1296
|
}
|
|
1246
1297
|
/**
|
|
@@ -1251,7 +1302,9 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1251
1302
|
*/
|
|
1252
1303
|
_getCollection(modelName) {
|
|
1253
1304
|
let collection = this._collections.get(modelName);
|
|
1254
|
-
if (collection)
|
|
1305
|
+
if (collection) {
|
|
1306
|
+
return collection;
|
|
1307
|
+
}
|
|
1255
1308
|
const collectionName = this._getCollectionNameByModelName(modelName);
|
|
1256
1309
|
collection = this.client.db(this.settings.database).collection(collectionName);
|
|
1257
1310
|
this._collections.set(modelName, collection);
|
|
@@ -1276,11 +1329,12 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1276
1329
|
* @returns {string}
|
|
1277
1330
|
*/
|
|
1278
1331
|
_getColName(modelName, propName) {
|
|
1279
|
-
if (!propName || typeof propName !== "string")
|
|
1332
|
+
if (!propName || typeof propName !== "string") {
|
|
1280
1333
|
throw new import_js_repository3.InvalidArgumentError(
|
|
1281
1334
|
"Property name must be a non-empty String, but %v given.",
|
|
1282
1335
|
propName
|
|
1283
1336
|
);
|
|
1337
|
+
}
|
|
1284
1338
|
const utils = this.getService(import_js_repository3.ModelDefinitionUtils);
|
|
1285
1339
|
let colName = propName;
|
|
1286
1340
|
try {
|
|
@@ -1300,22 +1354,26 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1300
1354
|
* @returns {string}
|
|
1301
1355
|
*/
|
|
1302
1356
|
_convertPropNamesChainToColNamesChain(modelName, propsChain) {
|
|
1303
|
-
if (!modelName || typeof modelName !== "string")
|
|
1357
|
+
if (!modelName || typeof modelName !== "string") {
|
|
1304
1358
|
throw new import_js_repository3.InvalidArgumentError(
|
|
1305
1359
|
"Model name must be a non-empty String, but %v given.",
|
|
1306
1360
|
modelName
|
|
1307
1361
|
);
|
|
1308
|
-
|
|
1362
|
+
}
|
|
1363
|
+
if (!propsChain || typeof propsChain !== "string") {
|
|
1309
1364
|
throw new import_js_repository3.InvalidArgumentError(
|
|
1310
1365
|
"Properties chain must be a non-empty String, but %v given.",
|
|
1311
1366
|
propsChain
|
|
1312
1367
|
);
|
|
1368
|
+
}
|
|
1313
1369
|
propsChain = propsChain.replace(/\.{2,}/g, ".");
|
|
1314
1370
|
const propNames = propsChain.split(".");
|
|
1315
1371
|
const utils = this.getService(import_js_repository3.ModelDefinitionUtils);
|
|
1316
1372
|
let currModelName = modelName;
|
|
1317
1373
|
return propNames.map((currPropName) => {
|
|
1318
|
-
if (!currModelName)
|
|
1374
|
+
if (!currModelName) {
|
|
1375
|
+
return currPropName;
|
|
1376
|
+
}
|
|
1319
1377
|
const colName = this._getColName(currModelName, currPropName);
|
|
1320
1378
|
currModelName = utils.getModelNameOfPropertyValueIfDefined(
|
|
1321
1379
|
currModelName,
|
|
@@ -1332,16 +1390,25 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1332
1390
|
* @returns {Record<string, number>|undefined}
|
|
1333
1391
|
*/
|
|
1334
1392
|
_buildProjection(modelName, fields) {
|
|
1335
|
-
if (fields == null)
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
if (
|
|
1393
|
+
if (fields == null) {
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1396
|
+
if (Array.isArray(fields) === false) {
|
|
1397
|
+
fields = [fields];
|
|
1398
|
+
}
|
|
1399
|
+
if (!fields.length) {
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
if (fields.indexOf("_id") === -1) {
|
|
1403
|
+
fields.push("_id");
|
|
1404
|
+
}
|
|
1339
1405
|
return fields.reduce((acc, field) => {
|
|
1340
|
-
if (!field || typeof field !== "string")
|
|
1406
|
+
if (!field || typeof field !== "string") {
|
|
1341
1407
|
throw new import_js_repository3.InvalidArgumentError(
|
|
1342
1408
|
'The provided option "fields" should be a non-empty String or an Array of non-empty String, but %v given.',
|
|
1343
1409
|
field
|
|
1344
1410
|
);
|
|
1411
|
+
}
|
|
1345
1412
|
let colName = this._convertPropNamesChainToColNamesChain(
|
|
1346
1413
|
modelName,
|
|
1347
1414
|
field
|
|
@@ -1358,16 +1425,23 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1358
1425
|
* @returns {object|undefined}
|
|
1359
1426
|
*/
|
|
1360
1427
|
_buildSort(modelName, clause) {
|
|
1361
|
-
if (clause == null)
|
|
1362
|
-
|
|
1363
|
-
|
|
1428
|
+
if (clause == null) {
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1431
|
+
if (Array.isArray(clause) === false) {
|
|
1432
|
+
clause = [clause];
|
|
1433
|
+
}
|
|
1434
|
+
if (!clause.length) {
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1364
1437
|
const idPropName = this._getIdPropName(modelName);
|
|
1365
1438
|
return clause.reduce((acc, order) => {
|
|
1366
|
-
if (!order || typeof order !== "string")
|
|
1439
|
+
if (!order || typeof order !== "string") {
|
|
1367
1440
|
throw new import_js_repository3.InvalidArgumentError(
|
|
1368
1441
|
'The provided option "order" should be a non-empty String or an Array of non-empty String, but %v given.',
|
|
1369
1442
|
order
|
|
1370
1443
|
);
|
|
1444
|
+
}
|
|
1371
1445
|
const direction = order.match(/\s+(A|DE)SC$/);
|
|
1372
1446
|
let field = order.replace(/\s+(A|DE)SC$/, "").trim();
|
|
1373
1447
|
if (field === idPropName) {
|
|
@@ -1393,27 +1467,36 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1393
1467
|
* @returns {object|undefined}
|
|
1394
1468
|
*/
|
|
1395
1469
|
_buildQuery(modelName, clause) {
|
|
1396
|
-
if (clause == null)
|
|
1397
|
-
|
|
1470
|
+
if (clause == null) {
|
|
1471
|
+
return;
|
|
1472
|
+
}
|
|
1473
|
+
if (typeof clause !== "object" || Array.isArray(clause)) {
|
|
1398
1474
|
throw new import_js_repository3.InvalidArgumentError(
|
|
1399
1475
|
'The provided option "where" should be an Object, but %v given.',
|
|
1400
1476
|
clause
|
|
1401
1477
|
);
|
|
1478
|
+
}
|
|
1402
1479
|
const query = {};
|
|
1403
1480
|
const idPropName = this._getIdPropName(modelName);
|
|
1404
1481
|
Object.keys(clause).forEach((key) => {
|
|
1405
1482
|
var _a, _b;
|
|
1406
|
-
if (String(key).indexOf("$") !== -1)
|
|
1483
|
+
if (String(key).indexOf("$") !== -1) {
|
|
1407
1484
|
throw new import_js_repository3.InvalidArgumentError(
|
|
1408
1485
|
'The symbol "$" is not supported, but %v given.',
|
|
1409
1486
|
key
|
|
1410
1487
|
);
|
|
1488
|
+
}
|
|
1411
1489
|
let cond = clause[key];
|
|
1412
1490
|
if (key === "and" || key === "or" || key === "nor") {
|
|
1413
|
-
if (cond == null)
|
|
1414
|
-
|
|
1491
|
+
if (cond == null) {
|
|
1492
|
+
return;
|
|
1493
|
+
}
|
|
1494
|
+
if (!Array.isArray(cond)) {
|
|
1415
1495
|
throw new import_js_repository3.InvalidOperatorValueError(key, "an Array", cond);
|
|
1416
|
-
|
|
1496
|
+
}
|
|
1497
|
+
if (cond.length === 0) {
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1417
1500
|
cond = cond.map((c) => this._buildQuery(modelName, c));
|
|
1418
1501
|
cond = cond.filter((c) => c != null);
|
|
1419
1502
|
const opKey = "$" + key;
|
|
@@ -1464,12 +1547,13 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1464
1547
|
opConds.push({ $lte: lte });
|
|
1465
1548
|
}
|
|
1466
1549
|
if ("inq" in cond) {
|
|
1467
|
-
if (!cond.inq || !Array.isArray(cond.inq))
|
|
1550
|
+
if (!cond.inq || !Array.isArray(cond.inq)) {
|
|
1468
1551
|
throw new import_js_repository3.InvalidOperatorValueError(
|
|
1469
1552
|
"inq",
|
|
1470
1553
|
"an Array of possible values",
|
|
1471
1554
|
cond.inq
|
|
1472
1555
|
);
|
|
1556
|
+
}
|
|
1473
1557
|
const inq = cond.inq.map((v) => {
|
|
1474
1558
|
v = this._coerceId(v);
|
|
1475
1559
|
v = this._coerceDate(v);
|
|
@@ -1478,12 +1562,13 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1478
1562
|
opConds.push({ $in: inq });
|
|
1479
1563
|
}
|
|
1480
1564
|
if ("nin" in cond) {
|
|
1481
|
-
if (!cond.nin || !Array.isArray(cond.nin))
|
|
1565
|
+
if (!cond.nin || !Array.isArray(cond.nin)) {
|
|
1482
1566
|
throw new import_js_repository3.InvalidOperatorValueError(
|
|
1483
1567
|
"nin",
|
|
1484
1568
|
"an Array of possible values",
|
|
1485
1569
|
cond
|
|
1486
1570
|
);
|
|
1571
|
+
}
|
|
1487
1572
|
const nin = cond.nin.map((v) => {
|
|
1488
1573
|
v = this._coerceId(v);
|
|
1489
1574
|
v = this._coerceDate(v);
|
|
@@ -1492,50 +1577,55 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1492
1577
|
opConds.push({ $nin: nin });
|
|
1493
1578
|
}
|
|
1494
1579
|
if ("between" in cond) {
|
|
1495
|
-
if (!Array.isArray(cond.between) || cond.between.length !== 2)
|
|
1580
|
+
if (!Array.isArray(cond.between) || cond.between.length !== 2) {
|
|
1496
1581
|
throw new import_js_repository3.InvalidOperatorValueError(
|
|
1497
1582
|
"between",
|
|
1498
1583
|
"an Array of 2 elements",
|
|
1499
1584
|
cond.between
|
|
1500
1585
|
);
|
|
1586
|
+
}
|
|
1501
1587
|
const gte = this._coerceDate(cond.between[0]);
|
|
1502
1588
|
const lte = this._coerceDate(cond.between[1]);
|
|
1503
1589
|
opConds.push({ $gte: gte, $lte: lte });
|
|
1504
1590
|
}
|
|
1505
1591
|
if ("exists" in cond) {
|
|
1506
|
-
if (typeof cond.exists !== "boolean")
|
|
1592
|
+
if (typeof cond.exists !== "boolean") {
|
|
1507
1593
|
throw new import_js_repository3.InvalidOperatorValueError(
|
|
1508
1594
|
"exists",
|
|
1509
1595
|
"a Boolean",
|
|
1510
1596
|
cond.exists
|
|
1511
1597
|
);
|
|
1598
|
+
}
|
|
1512
1599
|
opConds.push({ $exists: cond.exists });
|
|
1513
1600
|
}
|
|
1514
1601
|
if ("like" in cond) {
|
|
1515
|
-
if (typeof cond.like !== "string" && !(cond.like instanceof RegExp))
|
|
1602
|
+
if (typeof cond.like !== "string" && !(cond.like instanceof RegExp)) {
|
|
1516
1603
|
throw new import_js_repository3.InvalidOperatorValueError(
|
|
1517
1604
|
"like",
|
|
1518
1605
|
"a String or RegExp",
|
|
1519
1606
|
cond.like
|
|
1520
1607
|
);
|
|
1608
|
+
}
|
|
1521
1609
|
opConds.push({ $regex: (0, import_js_repository3.likeToRegexp)(cond.like) });
|
|
1522
1610
|
}
|
|
1523
1611
|
if ("nlike" in cond) {
|
|
1524
|
-
if (typeof cond.nlike !== "string" && !(cond.nlike instanceof RegExp))
|
|
1612
|
+
if (typeof cond.nlike !== "string" && !(cond.nlike instanceof RegExp)) {
|
|
1525
1613
|
throw new import_js_repository3.InvalidOperatorValueError(
|
|
1526
1614
|
"nlike",
|
|
1527
1615
|
"a String or RegExp",
|
|
1528
1616
|
cond.nlike
|
|
1529
1617
|
);
|
|
1618
|
+
}
|
|
1530
1619
|
opConds.push({ $not: (0, import_js_repository3.likeToRegexp)(cond.nlike) });
|
|
1531
1620
|
}
|
|
1532
1621
|
if ("ilike" in cond) {
|
|
1533
|
-
if (typeof cond.ilike !== "string" && !(cond.ilike instanceof RegExp))
|
|
1622
|
+
if (typeof cond.ilike !== "string" && !(cond.ilike instanceof RegExp)) {
|
|
1534
1623
|
throw new import_js_repository3.InvalidOperatorValueError(
|
|
1535
1624
|
"ilike",
|
|
1536
1625
|
"a String or RegExp",
|
|
1537
1626
|
cond.ilike
|
|
1538
1627
|
);
|
|
1628
|
+
}
|
|
1539
1629
|
opConds.push({ $regex: (0, import_js_repository3.likeToRegexp)(cond.ilike, true) });
|
|
1540
1630
|
}
|
|
1541
1631
|
if ("nilike" in cond) {
|
|
@@ -1557,11 +1647,12 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1557
1647
|
);
|
|
1558
1648
|
}
|
|
1559
1649
|
const flags = cond.flags || void 0;
|
|
1560
|
-
if (flags && typeof flags !== "string")
|
|
1650
|
+
if (flags && typeof flags !== "string") {
|
|
1561
1651
|
throw new import_js_repository3.InvalidArgumentError(
|
|
1562
1652
|
"RegExp flags must be a String, but %v given.",
|
|
1563
1653
|
cond.flags
|
|
1564
1654
|
);
|
|
1655
|
+
}
|
|
1565
1656
|
opConds.push({ $regex: (0, import_js_repository3.stringToRegexp)(cond.regexp, flags) });
|
|
1566
1657
|
}
|
|
1567
1658
|
if (opConds.length === 1) {
|
|
@@ -1589,12 +1680,13 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1589
1680
|
const idValue = modelData[idPropName];
|
|
1590
1681
|
if (idValue == null || idValue === "" || idValue === 0) {
|
|
1591
1682
|
const pkType = this._getIdType(modelName);
|
|
1592
|
-
if (pkType !== import_js_repository3.DataType.STRING && pkType !== import_js_repository3.DataType.ANY)
|
|
1683
|
+
if (pkType !== import_js_repository3.DataType.STRING && pkType !== import_js_repository3.DataType.ANY) {
|
|
1593
1684
|
throw new import_js_repository3.InvalidArgumentError(
|
|
1594
1685
|
"MongoDB unable to generate primary keys of %s. Do provide your own value for the %v property or set property type to String.",
|
|
1595
1686
|
(0, import_js_repository3.capitalize)(pkType),
|
|
1596
1687
|
idPropName
|
|
1597
1688
|
);
|
|
1689
|
+
}
|
|
1598
1690
|
delete modelData[idPropName];
|
|
1599
1691
|
}
|
|
1600
1692
|
const tableData = this._toDatabase(modelName, modelData);
|
|
@@ -1623,8 +1715,9 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1623
1715
|
const tableData = this._toDatabase(modelName, modelData);
|
|
1624
1716
|
const table = this._getCollection(modelName);
|
|
1625
1717
|
const { matchedCount } = await table.replaceOne({ _id: id }, tableData);
|
|
1626
|
-
if (matchedCount < 1)
|
|
1718
|
+
if (matchedCount < 1) {
|
|
1627
1719
|
throw new import_js_repository3.InvalidArgumentError("Identifier %v is not found.", String(id));
|
|
1720
|
+
}
|
|
1628
1721
|
const projection = this._buildProjection(
|
|
1629
1722
|
modelName,
|
|
1630
1723
|
filter && filter.fields
|
|
@@ -1646,12 +1739,13 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1646
1739
|
idValue = this._coerceId(idValue);
|
|
1647
1740
|
if (idValue == null || idValue === "" || idValue === 0) {
|
|
1648
1741
|
const pkType = this._getIdType(modelName);
|
|
1649
|
-
if (pkType !== import_js_repository3.DataType.STRING && pkType !== import_js_repository3.DataType.ANY)
|
|
1742
|
+
if (pkType !== import_js_repository3.DataType.STRING && pkType !== import_js_repository3.DataType.ANY) {
|
|
1650
1743
|
throw new import_js_repository3.InvalidArgumentError(
|
|
1651
1744
|
"MongoDB unable to generate primary keys of %s. Do provide your own value for the %v property or set property type to String.",
|
|
1652
1745
|
(0, import_js_repository3.capitalize)(pkType),
|
|
1653
1746
|
idPropName
|
|
1654
1747
|
);
|
|
1748
|
+
}
|
|
1655
1749
|
delete modelData[idPropName];
|
|
1656
1750
|
idValue = void 0;
|
|
1657
1751
|
}
|
|
@@ -1664,7 +1758,9 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1664
1758
|
const { upsertedId } = await table.replaceOne({ _id: idValue }, tableData, {
|
|
1665
1759
|
upsert: true
|
|
1666
1760
|
});
|
|
1667
|
-
if (upsertedId)
|
|
1761
|
+
if (upsertedId) {
|
|
1762
|
+
idValue = upsertedId;
|
|
1763
|
+
}
|
|
1668
1764
|
}
|
|
1669
1765
|
const projection = this._buildProjection(
|
|
1670
1766
|
modelName,
|
|
@@ -1706,8 +1802,9 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1706
1802
|
const tableData = this._toDatabase(modelName, modelData);
|
|
1707
1803
|
const table = this._getCollection(modelName);
|
|
1708
1804
|
const { matchedCount } = await table.updateOne({ _id: id }, { $set: tableData });
|
|
1709
|
-
if (matchedCount < 1)
|
|
1805
|
+
if (matchedCount < 1) {
|
|
1710
1806
|
throw new import_js_repository3.InvalidArgumentError("Identifier %v is not found.", String(id));
|
|
1807
|
+
}
|
|
1711
1808
|
const projection = this._buildProjection(
|
|
1712
1809
|
modelName,
|
|
1713
1810
|
filter && filter.fields
|
|
@@ -1750,8 +1847,9 @@ var _MongodbAdapter = class _MongodbAdapter extends import_js_repository3.Adapte
|
|
|
1750
1847
|
filter && filter.fields
|
|
1751
1848
|
);
|
|
1752
1849
|
const patchedData = await table.findOne({ _id: id }, { projection });
|
|
1753
|
-
if (!patchedData)
|
|
1850
|
+
if (!patchedData) {
|
|
1754
1851
|
throw new import_js_repository3.InvalidArgumentError("Identifier %v is not found.", String(id));
|
|
1852
|
+
}
|
|
1755
1853
|
return this._fromDatabase(modelName, patchedData);
|
|
1756
1854
|
}
|
|
1757
1855
|
/**
|
package/eslint.config.js
CHANGED
|
@@ -27,6 +27,7 @@ export default [{
|
|
|
27
27
|
...eslintMochaPlugin.configs.recommended.rules,
|
|
28
28
|
...eslintChaiExpectPlugin.configs['recommended-flat'].rules,
|
|
29
29
|
...eslintJsdocPlugin.configs['flat/recommended-error'].rules,
|
|
30
|
+
'curly': 'error',
|
|
30
31
|
'no-duplicate-imports': 'error',
|
|
31
32
|
'import/export': 0,
|
|
32
33
|
'jsdoc/reject-any-type': 0,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e22m4u/js-repository-mongodb-adapter",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "MongoDB адаптер для @e22m4u/js-repository",
|
|
5
5
|
"author": "Mikhail Evstropov <e22m4u@yandex.ru>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,33 +38,33 @@
|
|
|
38
38
|
"prepare": "husky"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@e22m4u/js-format": "~0.3.
|
|
42
|
-
"mongodb": "6.
|
|
41
|
+
"@e22m4u/js-format": "~0.3.2",
|
|
42
|
+
"mongodb": "6.21.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"@e22m4u/js-repository": "~0.8.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@commitlint/cli": "~20.1
|
|
49
|
-
"@commitlint/config-conventional": "~20.
|
|
50
|
-
"@eslint/js": "~9.39.
|
|
48
|
+
"@commitlint/cli": "~20.4.1",
|
|
49
|
+
"@commitlint/config-conventional": "~20.4.1",
|
|
50
|
+
"@eslint/js": "~9.39.2",
|
|
51
51
|
"@types/chai": "~5.2.3",
|
|
52
52
|
"@types/mocha": "~10.0.10",
|
|
53
53
|
"c8": "~10.1.3",
|
|
54
|
-
"chai": "~6.2.
|
|
54
|
+
"chai": "~6.2.2",
|
|
55
55
|
"chai-as-promised": "~8.0.2",
|
|
56
|
-
"dotenv": "~17.2.
|
|
57
|
-
"esbuild": "~0.27.
|
|
58
|
-
"eslint": "~9.39.
|
|
56
|
+
"dotenv": "~17.2.4",
|
|
57
|
+
"esbuild": "~0.27.3",
|
|
58
|
+
"eslint": "~9.39.2",
|
|
59
59
|
"eslint-config-prettier": "~10.1.8",
|
|
60
60
|
"eslint-plugin-chai-expect": "~3.1.0",
|
|
61
61
|
"eslint-plugin-import": "~2.32.0",
|
|
62
|
-
"eslint-plugin-jsdoc": "~
|
|
62
|
+
"eslint-plugin-jsdoc": "~62.5.4",
|
|
63
63
|
"eslint-plugin-mocha": "~11.2.0",
|
|
64
|
-
"globals": "~
|
|
64
|
+
"globals": "~17.3.0",
|
|
65
65
|
"husky": "~9.1.7",
|
|
66
66
|
"mocha": "~11.7.5",
|
|
67
|
-
"prettier": "~3.
|
|
67
|
+
"prettier": "~3.8.1",
|
|
68
68
|
"rimraf": "~6.1.2"
|
|
69
69
|
}
|
|
70
70
|
}
|
package/src/mongodb-adapter.js
CHANGED
|
@@ -216,8 +216,12 @@ export class MongodbAdapter extends Adapter {
|
|
|
216
216
|
* @returns {ObjectId|*}
|
|
217
217
|
*/
|
|
218
218
|
_coerceId(value) {
|
|
219
|
-
if (value == null)
|
|
220
|
-
|
|
219
|
+
if (value == null) {
|
|
220
|
+
return value;
|
|
221
|
+
}
|
|
222
|
+
if (isObjectId(value)) {
|
|
223
|
+
return new ObjectId(value);
|
|
224
|
+
}
|
|
221
225
|
return value;
|
|
222
226
|
}
|
|
223
227
|
|
|
@@ -228,9 +232,15 @@ export class MongodbAdapter extends Adapter {
|
|
|
228
232
|
* @returns {Date|*}
|
|
229
233
|
*/
|
|
230
234
|
_coerceDate(value) {
|
|
231
|
-
if (value == null)
|
|
232
|
-
|
|
233
|
-
|
|
235
|
+
if (value == null) {
|
|
236
|
+
return value;
|
|
237
|
+
}
|
|
238
|
+
if (value instanceof Date) {
|
|
239
|
+
return value;
|
|
240
|
+
}
|
|
241
|
+
if (isIsoDate(value)) {
|
|
242
|
+
return new Date(value);
|
|
243
|
+
}
|
|
234
244
|
return value;
|
|
235
245
|
}
|
|
236
246
|
|
|
@@ -247,22 +257,31 @@ export class MongodbAdapter extends Adapter {
|
|
|
247
257
|
).convertPropertyNamesToColumnNames(modelName, modelData);
|
|
248
258
|
|
|
249
259
|
const idColName = this._getIdColName(modelName);
|
|
250
|
-
if (idColName !== 'id' && idColName !== '_id')
|
|
260
|
+
if (idColName !== 'id' && idColName !== '_id') {
|
|
251
261
|
throw new InvalidArgumentError(
|
|
252
262
|
'MongoDB is not supporting custom names of the primary key. ' +
|
|
253
263
|
'Do use "id" as a primary key instead of %v.',
|
|
254
264
|
idColName,
|
|
255
265
|
);
|
|
266
|
+
}
|
|
256
267
|
if (idColName in tableData && idColName !== '_id') {
|
|
257
268
|
tableData._id = tableData[idColName];
|
|
258
269
|
delete tableData[idColName];
|
|
259
270
|
}
|
|
260
271
|
|
|
261
272
|
return transformValuesDeep(tableData, value => {
|
|
262
|
-
if (value instanceof ObjectId)
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
if (
|
|
273
|
+
if (value instanceof ObjectId) {
|
|
274
|
+
return value;
|
|
275
|
+
}
|
|
276
|
+
if (value instanceof Date) {
|
|
277
|
+
return value;
|
|
278
|
+
}
|
|
279
|
+
if (isObjectId(value)) {
|
|
280
|
+
return new ObjectId(value);
|
|
281
|
+
}
|
|
282
|
+
if (isIsoDate(value)) {
|
|
283
|
+
return new Date(value);
|
|
284
|
+
}
|
|
266
285
|
return value;
|
|
267
286
|
});
|
|
268
287
|
}
|
|
@@ -277,12 +296,13 @@ export class MongodbAdapter extends Adapter {
|
|
|
277
296
|
_fromDatabase(modelName, tableData) {
|
|
278
297
|
if ('_id' in tableData) {
|
|
279
298
|
const idColName = this._getIdColName(modelName);
|
|
280
|
-
if (idColName !== 'id' && idColName !== '_id')
|
|
299
|
+
if (idColName !== 'id' && idColName !== '_id') {
|
|
281
300
|
throw new InvalidArgumentError(
|
|
282
301
|
'MongoDB is not supporting custom names of the primary key. ' +
|
|
283
302
|
'Do use "id" as a primary key instead of %v.',
|
|
284
303
|
idColName,
|
|
285
304
|
);
|
|
305
|
+
}
|
|
286
306
|
if (idColName !== '_id') {
|
|
287
307
|
tableData[idColName] = tableData._id;
|
|
288
308
|
delete tableData._id;
|
|
@@ -294,8 +314,12 @@ export class MongodbAdapter extends Adapter {
|
|
|
294
314
|
).convertColumnNamesToPropertyNames(modelName, tableData);
|
|
295
315
|
|
|
296
316
|
return transformValuesDeep(modelData, value => {
|
|
297
|
-
if (value instanceof ObjectId)
|
|
298
|
-
|
|
317
|
+
if (value instanceof ObjectId) {
|
|
318
|
+
return String(value);
|
|
319
|
+
}
|
|
320
|
+
if (value instanceof Date) {
|
|
321
|
+
return value.toISOString();
|
|
322
|
+
}
|
|
299
323
|
return value;
|
|
300
324
|
});
|
|
301
325
|
}
|
|
@@ -308,7 +332,9 @@ export class MongodbAdapter extends Adapter {
|
|
|
308
332
|
*/
|
|
309
333
|
_getCollectionNameByModelName(modelName) {
|
|
310
334
|
const modelDef = this.getService(DefinitionRegistry).getModel(modelName);
|
|
311
|
-
if (modelDef.tableName != null)
|
|
335
|
+
if (modelDef.tableName != null) {
|
|
336
|
+
return modelDef.tableName;
|
|
337
|
+
}
|
|
312
338
|
// если имя коллекции не определено явно (опция "tableName"),
|
|
313
339
|
// то выполняется приведение имени модели к стандартному camelCase
|
|
314
340
|
// во множественном числе
|
|
@@ -324,7 +350,9 @@ export class MongodbAdapter extends Adapter {
|
|
|
324
350
|
*/
|
|
325
351
|
_getCollection(modelName) {
|
|
326
352
|
let collection = this._collections.get(modelName);
|
|
327
|
-
if (collection)
|
|
353
|
+
if (collection) {
|
|
354
|
+
return collection;
|
|
355
|
+
}
|
|
328
356
|
const collectionName = this._getCollectionNameByModelName(modelName);
|
|
329
357
|
collection = this.client
|
|
330
358
|
.db(this.settings.database)
|
|
@@ -353,11 +381,12 @@ export class MongodbAdapter extends Adapter {
|
|
|
353
381
|
* @returns {string}
|
|
354
382
|
*/
|
|
355
383
|
_getColName(modelName, propName) {
|
|
356
|
-
if (!propName || typeof propName !== 'string')
|
|
384
|
+
if (!propName || typeof propName !== 'string') {
|
|
357
385
|
throw new InvalidArgumentError(
|
|
358
386
|
'Property name must be a non-empty String, but %v given.',
|
|
359
387
|
propName,
|
|
360
388
|
);
|
|
389
|
+
}
|
|
361
390
|
const utils = this.getService(ModelDefinitionUtils);
|
|
362
391
|
let colName = propName;
|
|
363
392
|
try {
|
|
@@ -381,16 +410,18 @@ export class MongodbAdapter extends Adapter {
|
|
|
381
410
|
* @returns {string}
|
|
382
411
|
*/
|
|
383
412
|
_convertPropNamesChainToColNamesChain(modelName, propsChain) {
|
|
384
|
-
if (!modelName || typeof modelName !== 'string')
|
|
413
|
+
if (!modelName || typeof modelName !== 'string') {
|
|
385
414
|
throw new InvalidArgumentError(
|
|
386
415
|
'Model name must be a non-empty String, but %v given.',
|
|
387
416
|
modelName,
|
|
388
417
|
);
|
|
389
|
-
|
|
418
|
+
}
|
|
419
|
+
if (!propsChain || typeof propsChain !== 'string') {
|
|
390
420
|
throw new InvalidArgumentError(
|
|
391
421
|
'Properties chain must be a non-empty String, but %v given.',
|
|
392
422
|
propsChain,
|
|
393
423
|
);
|
|
424
|
+
}
|
|
394
425
|
// удаление повторяющихся точек,
|
|
395
426
|
// где строка "foo..bar.baz...qux"
|
|
396
427
|
// будет преобразована к "foo.bar.baz.qux"
|
|
@@ -402,7 +433,9 @@ export class MongodbAdapter extends Adapter {
|
|
|
402
433
|
let currModelName = modelName;
|
|
403
434
|
return propNames
|
|
404
435
|
.map(currPropName => {
|
|
405
|
-
if (!currModelName)
|
|
436
|
+
if (!currModelName) {
|
|
437
|
+
return currPropName;
|
|
438
|
+
}
|
|
406
439
|
const colName = this._getColName(currModelName, currPropName);
|
|
407
440
|
currModelName = utils.getModelNameOfPropertyValueIfDefined(
|
|
408
441
|
currModelName,
|
|
@@ -421,17 +454,26 @@ export class MongodbAdapter extends Adapter {
|
|
|
421
454
|
* @returns {Record<string, number>|undefined}
|
|
422
455
|
*/
|
|
423
456
|
_buildProjection(modelName, fields) {
|
|
424
|
-
if (fields == null)
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
if (
|
|
457
|
+
if (fields == null) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
if (Array.isArray(fields) === false) {
|
|
461
|
+
fields = [fields];
|
|
462
|
+
}
|
|
463
|
+
if (!fields.length) {
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
if (fields.indexOf('_id') === -1) {
|
|
467
|
+
fields.push('_id');
|
|
468
|
+
}
|
|
428
469
|
return fields.reduce((acc, field) => {
|
|
429
|
-
if (!field || typeof field !== 'string')
|
|
470
|
+
if (!field || typeof field !== 'string') {
|
|
430
471
|
throw new InvalidArgumentError(
|
|
431
472
|
'The provided option "fields" should be a non-empty String ' +
|
|
432
473
|
'or an Array of non-empty String, but %v given.',
|
|
433
474
|
field,
|
|
434
475
|
);
|
|
476
|
+
}
|
|
435
477
|
let colName = this._convertPropNamesChainToColNamesChain(
|
|
436
478
|
modelName,
|
|
437
479
|
field,
|
|
@@ -449,17 +491,24 @@ export class MongodbAdapter extends Adapter {
|
|
|
449
491
|
* @returns {object|undefined}
|
|
450
492
|
*/
|
|
451
493
|
_buildSort(modelName, clause) {
|
|
452
|
-
if (clause == null)
|
|
453
|
-
|
|
454
|
-
|
|
494
|
+
if (clause == null) {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
if (Array.isArray(clause) === false) {
|
|
498
|
+
clause = [clause];
|
|
499
|
+
}
|
|
500
|
+
if (!clause.length) {
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
455
503
|
const idPropName = this._getIdPropName(modelName);
|
|
456
504
|
return clause.reduce((acc, order) => {
|
|
457
|
-
if (!order || typeof order !== 'string')
|
|
505
|
+
if (!order || typeof order !== 'string') {
|
|
458
506
|
throw new InvalidArgumentError(
|
|
459
507
|
'The provided option "order" should be a non-empty String ' +
|
|
460
508
|
'or an Array of non-empty String, but %v given.',
|
|
461
509
|
order,
|
|
462
510
|
);
|
|
511
|
+
}
|
|
463
512
|
const direction = order.match(/\s+(A|DE)SC$/);
|
|
464
513
|
let field = order.replace(/\s+(A|DE)SC$/, '').trim();
|
|
465
514
|
if (field === idPropName) {
|
|
@@ -489,27 +538,36 @@ export class MongodbAdapter extends Adapter {
|
|
|
489
538
|
* @returns {object|undefined}
|
|
490
539
|
*/
|
|
491
540
|
_buildQuery(modelName, clause) {
|
|
492
|
-
if (clause == null)
|
|
493
|
-
|
|
541
|
+
if (clause == null) {
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
if (typeof clause !== 'object' || Array.isArray(clause)) {
|
|
494
545
|
throw new InvalidArgumentError(
|
|
495
546
|
'The provided option "where" should be an Object, but %v given.',
|
|
496
547
|
clause,
|
|
497
548
|
);
|
|
549
|
+
}
|
|
498
550
|
const query = {};
|
|
499
551
|
const idPropName = this._getIdPropName(modelName);
|
|
500
552
|
Object.keys(clause).forEach(key => {
|
|
501
|
-
if (String(key).indexOf('$') !== -1)
|
|
553
|
+
if (String(key).indexOf('$') !== -1) {
|
|
502
554
|
throw new InvalidArgumentError(
|
|
503
555
|
'The symbol "$" is not supported, but %v given.',
|
|
504
556
|
key,
|
|
505
557
|
);
|
|
558
|
+
}
|
|
506
559
|
let cond = clause[key];
|
|
507
560
|
// and/or/nor clause
|
|
508
561
|
if (key === 'and' || key === 'or' || key === 'nor') {
|
|
509
|
-
if (cond == null)
|
|
510
|
-
|
|
562
|
+
if (cond == null) {
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
if (!Array.isArray(cond)) {
|
|
511
566
|
throw new InvalidOperatorValueError(key, 'an Array', cond);
|
|
512
|
-
|
|
567
|
+
}
|
|
568
|
+
if (cond.length === 0) {
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
513
571
|
cond = cond.map(c => this._buildQuery(modelName, c));
|
|
514
572
|
cond = cond.filter(c => c != null);
|
|
515
573
|
const opKey = '$' + key;
|
|
@@ -571,12 +629,13 @@ export class MongodbAdapter extends Adapter {
|
|
|
571
629
|
}
|
|
572
630
|
// inq
|
|
573
631
|
if ('inq' in cond) {
|
|
574
|
-
if (!cond.inq || !Array.isArray(cond.inq))
|
|
632
|
+
if (!cond.inq || !Array.isArray(cond.inq)) {
|
|
575
633
|
throw new InvalidOperatorValueError(
|
|
576
634
|
'inq',
|
|
577
635
|
'an Array of possible values',
|
|
578
636
|
cond.inq,
|
|
579
637
|
);
|
|
638
|
+
}
|
|
580
639
|
const inq = cond.inq.map(v => {
|
|
581
640
|
v = this._coerceId(v);
|
|
582
641
|
v = this._coerceDate(v);
|
|
@@ -586,12 +645,13 @@ export class MongodbAdapter extends Adapter {
|
|
|
586
645
|
}
|
|
587
646
|
// nin
|
|
588
647
|
if ('nin' in cond) {
|
|
589
|
-
if (!cond.nin || !Array.isArray(cond.nin))
|
|
648
|
+
if (!cond.nin || !Array.isArray(cond.nin)) {
|
|
590
649
|
throw new InvalidOperatorValueError(
|
|
591
650
|
'nin',
|
|
592
651
|
'an Array of possible values',
|
|
593
652
|
cond,
|
|
594
653
|
);
|
|
654
|
+
}
|
|
595
655
|
const nin = cond.nin.map(v => {
|
|
596
656
|
v = this._coerceId(v);
|
|
597
657
|
v = this._coerceDate(v);
|
|
@@ -601,54 +661,65 @@ export class MongodbAdapter extends Adapter {
|
|
|
601
661
|
}
|
|
602
662
|
// between
|
|
603
663
|
if ('between' in cond) {
|
|
604
|
-
if (!Array.isArray(cond.between) || cond.between.length !== 2)
|
|
664
|
+
if (!Array.isArray(cond.between) || cond.between.length !== 2) {
|
|
605
665
|
throw new InvalidOperatorValueError(
|
|
606
666
|
'between',
|
|
607
667
|
'an Array of 2 elements',
|
|
608
668
|
cond.between,
|
|
609
669
|
);
|
|
670
|
+
}
|
|
610
671
|
const gte = this._coerceDate(cond.between[0]);
|
|
611
672
|
const lte = this._coerceDate(cond.between[1]);
|
|
612
673
|
opConds.push({$gte: gte, $lte: lte});
|
|
613
674
|
}
|
|
614
675
|
// exists
|
|
615
676
|
if ('exists' in cond) {
|
|
616
|
-
if (typeof cond.exists !== 'boolean')
|
|
677
|
+
if (typeof cond.exists !== 'boolean') {
|
|
617
678
|
throw new InvalidOperatorValueError(
|
|
618
679
|
'exists',
|
|
619
680
|
'a Boolean',
|
|
620
681
|
cond.exists,
|
|
621
682
|
);
|
|
683
|
+
}
|
|
622
684
|
opConds.push({$exists: cond.exists});
|
|
623
685
|
}
|
|
624
686
|
// like
|
|
625
687
|
if ('like' in cond) {
|
|
626
|
-
if (typeof cond.like !== 'string' && !(cond.like instanceof RegExp))
|
|
688
|
+
if (typeof cond.like !== 'string' && !(cond.like instanceof RegExp)) {
|
|
627
689
|
throw new InvalidOperatorValueError(
|
|
628
690
|
'like',
|
|
629
691
|
'a String or RegExp',
|
|
630
692
|
cond.like,
|
|
631
693
|
);
|
|
694
|
+
}
|
|
632
695
|
opConds.push({$regex: likeToRegexp(cond.like)});
|
|
633
696
|
}
|
|
634
697
|
// nlike
|
|
635
698
|
if ('nlike' in cond) {
|
|
636
|
-
if (
|
|
699
|
+
if (
|
|
700
|
+
typeof cond.nlike !== 'string' &&
|
|
701
|
+
!(cond.nlike instanceof RegExp)
|
|
702
|
+
) {
|
|
637
703
|
throw new InvalidOperatorValueError(
|
|
638
704
|
'nlike',
|
|
639
705
|
'a String or RegExp',
|
|
640
706
|
cond.nlike,
|
|
641
707
|
);
|
|
708
|
+
}
|
|
642
709
|
opConds.push({$not: likeToRegexp(cond.nlike)});
|
|
643
710
|
}
|
|
644
711
|
// ilike
|
|
645
712
|
if ('ilike' in cond) {
|
|
646
|
-
if (
|
|
713
|
+
if (
|
|
714
|
+
typeof cond.ilike !== 'string' &&
|
|
715
|
+
!(cond.ilike instanceof RegExp)
|
|
716
|
+
) {
|
|
647
717
|
throw new InvalidOperatorValueError(
|
|
648
718
|
'ilike',
|
|
649
719
|
'a String or RegExp',
|
|
650
720
|
cond.ilike,
|
|
651
721
|
);
|
|
722
|
+
}
|
|
652
723
|
opConds.push({$regex: likeToRegexp(cond.ilike, true)});
|
|
653
724
|
}
|
|
654
725
|
// nilike
|
|
@@ -678,11 +749,12 @@ export class MongodbAdapter extends Adapter {
|
|
|
678
749
|
);
|
|
679
750
|
}
|
|
680
751
|
const flags = cond.flags || undefined;
|
|
681
|
-
if (flags && typeof flags !== 'string')
|
|
752
|
+
if (flags && typeof flags !== 'string') {
|
|
682
753
|
throw new InvalidArgumentError(
|
|
683
754
|
'RegExp flags must be a String, but %v given.',
|
|
684
755
|
cond.flags,
|
|
685
756
|
);
|
|
757
|
+
}
|
|
686
758
|
opConds.push({$regex: stringToRegexp(cond.regexp, flags)});
|
|
687
759
|
}
|
|
688
760
|
// adds a single operator condition
|
|
@@ -714,7 +786,7 @@ export class MongodbAdapter extends Adapter {
|
|
|
714
786
|
const idValue = modelData[idPropName];
|
|
715
787
|
if (idValue == null || idValue === '' || idValue === 0) {
|
|
716
788
|
const pkType = this._getIdType(modelName);
|
|
717
|
-
if (pkType !== DataType.STRING && pkType !== DataType.ANY)
|
|
789
|
+
if (pkType !== DataType.STRING && pkType !== DataType.ANY) {
|
|
718
790
|
throw new InvalidArgumentError(
|
|
719
791
|
'MongoDB unable to generate primary keys of %s. ' +
|
|
720
792
|
'Do provide your own value for the %v property ' +
|
|
@@ -722,6 +794,7 @@ export class MongodbAdapter extends Adapter {
|
|
|
722
794
|
capitalize(pkType),
|
|
723
795
|
idPropName,
|
|
724
796
|
);
|
|
797
|
+
}
|
|
725
798
|
delete modelData[idPropName];
|
|
726
799
|
}
|
|
727
800
|
const tableData = this._toDatabase(modelName, modelData);
|
|
@@ -751,8 +824,9 @@ export class MongodbAdapter extends Adapter {
|
|
|
751
824
|
const tableData = this._toDatabase(modelName, modelData);
|
|
752
825
|
const table = this._getCollection(modelName);
|
|
753
826
|
const {matchedCount} = await table.replaceOne({_id: id}, tableData);
|
|
754
|
-
if (matchedCount < 1)
|
|
827
|
+
if (matchedCount < 1) {
|
|
755
828
|
throw new InvalidArgumentError('Identifier %v is not found.', String(id));
|
|
829
|
+
}
|
|
756
830
|
const projection = this._buildProjection(
|
|
757
831
|
modelName,
|
|
758
832
|
filter && filter.fields,
|
|
@@ -775,7 +849,7 @@ export class MongodbAdapter extends Adapter {
|
|
|
775
849
|
idValue = this._coerceId(idValue);
|
|
776
850
|
if (idValue == null || idValue === '' || idValue === 0) {
|
|
777
851
|
const pkType = this._getIdType(modelName);
|
|
778
|
-
if (pkType !== DataType.STRING && pkType !== DataType.ANY)
|
|
852
|
+
if (pkType !== DataType.STRING && pkType !== DataType.ANY) {
|
|
779
853
|
throw new InvalidArgumentError(
|
|
780
854
|
'MongoDB unable to generate primary keys of %s. ' +
|
|
781
855
|
'Do provide your own value for the %v property ' +
|
|
@@ -783,6 +857,7 @@ export class MongodbAdapter extends Adapter {
|
|
|
783
857
|
capitalize(pkType),
|
|
784
858
|
idPropName,
|
|
785
859
|
);
|
|
860
|
+
}
|
|
786
861
|
delete modelData[idPropName];
|
|
787
862
|
idValue = undefined;
|
|
788
863
|
}
|
|
@@ -795,7 +870,9 @@ export class MongodbAdapter extends Adapter {
|
|
|
795
870
|
const {upsertedId} = await table.replaceOne({_id: idValue}, tableData, {
|
|
796
871
|
upsert: true,
|
|
797
872
|
});
|
|
798
|
-
if (upsertedId)
|
|
873
|
+
if (upsertedId) {
|
|
874
|
+
idValue = upsertedId;
|
|
875
|
+
}
|
|
799
876
|
}
|
|
800
877
|
const projection = this._buildProjection(
|
|
801
878
|
modelName,
|
|
@@ -839,8 +916,9 @@ export class MongodbAdapter extends Adapter {
|
|
|
839
916
|
const tableData = this._toDatabase(modelName, modelData);
|
|
840
917
|
const table = this._getCollection(modelName);
|
|
841
918
|
const {matchedCount} = await table.updateOne({_id: id}, {$set: tableData});
|
|
842
|
-
if (matchedCount < 1)
|
|
919
|
+
if (matchedCount < 1) {
|
|
843
920
|
throw new InvalidArgumentError('Identifier %v is not found.', String(id));
|
|
921
|
+
}
|
|
844
922
|
const projection = this._buildProjection(
|
|
845
923
|
modelName,
|
|
846
924
|
filter && filter.fields,
|
|
@@ -885,8 +963,9 @@ export class MongodbAdapter extends Adapter {
|
|
|
885
963
|
filter && filter.fields,
|
|
886
964
|
);
|
|
887
965
|
const patchedData = await table.findOne({_id: id}, {projection});
|
|
888
|
-
if (!patchedData)
|
|
966
|
+
if (!patchedData) {
|
|
889
967
|
throw new InvalidArgumentError('Identifier %v is not found.', String(id));
|
|
968
|
+
}
|
|
890
969
|
return this._fromDatabase(modelName, patchedData);
|
|
891
970
|
}
|
|
892
971
|
|
|
@@ -20,26 +20,30 @@ import {InvalidArgumentError} from '@e22m4u/js-repository';
|
|
|
20
20
|
* @returns {string}
|
|
21
21
|
*/
|
|
22
22
|
export function createMongodbUrl(options = {}) {
|
|
23
|
-
if (!options || typeof options !== 'object' || Array.isArray(options))
|
|
23
|
+
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
24
24
|
throw new InvalidArgumentError(
|
|
25
25
|
'The first argument of "createMongodbUrl" must be an Object, but %v given.',
|
|
26
26
|
options,
|
|
27
27
|
);
|
|
28
|
-
|
|
28
|
+
}
|
|
29
|
+
if (options.protocol && typeof options.protocol !== 'string') {
|
|
29
30
|
throw new InvalidArgumentError(
|
|
30
31
|
'MongoDB option "protocol" must be a String, but %v given.',
|
|
31
32
|
options.protocol,
|
|
32
33
|
);
|
|
33
|
-
|
|
34
|
+
}
|
|
35
|
+
if (options.hostname && typeof options.hostname !== 'string') {
|
|
34
36
|
throw new InvalidArgumentError(
|
|
35
37
|
'MongoDB option "hostname" must be a String, but %v given.',
|
|
36
38
|
options.hostname,
|
|
37
39
|
);
|
|
38
|
-
|
|
40
|
+
}
|
|
41
|
+
if (options.host && typeof options.host !== 'string') {
|
|
39
42
|
throw new InvalidArgumentError(
|
|
40
43
|
'MongoDB option "host" must be a String, but %v given.',
|
|
41
44
|
options.host,
|
|
42
45
|
);
|
|
46
|
+
}
|
|
43
47
|
if (
|
|
44
48
|
options.port &&
|
|
45
49
|
typeof options.port !== 'number' &&
|
|
@@ -50,21 +54,24 @@ export function createMongodbUrl(options = {}) {
|
|
|
50
54
|
options.port,
|
|
51
55
|
);
|
|
52
56
|
}
|
|
53
|
-
if (options.database && typeof options.database !== 'string')
|
|
57
|
+
if (options.database && typeof options.database !== 'string') {
|
|
54
58
|
throw new InvalidArgumentError(
|
|
55
59
|
'MongoDB option "database" must be a String, but %v given.',
|
|
56
60
|
options.database,
|
|
57
61
|
);
|
|
58
|
-
|
|
62
|
+
}
|
|
63
|
+
if (options.db && typeof options.db !== 'string') {
|
|
59
64
|
throw new InvalidArgumentError(
|
|
60
65
|
'MongoDB option "db" must be a String, but %v given.',
|
|
61
66
|
options.db,
|
|
62
67
|
);
|
|
63
|
-
|
|
68
|
+
}
|
|
69
|
+
if (options.username && typeof options.username !== 'string') {
|
|
64
70
|
throw new InvalidArgumentError(
|
|
65
71
|
'MongoDB option "username" must be a String, but %v given.',
|
|
66
72
|
options.username,
|
|
67
73
|
);
|
|
74
|
+
}
|
|
68
75
|
if (
|
|
69
76
|
options.password &&
|
|
70
77
|
typeof options.password !== 'string' &&
|
package/src/utils/is-iso-date.js
CHANGED
|
@@ -5,9 +5,15 @@
|
|
|
5
5
|
* @returns {boolean}
|
|
6
6
|
*/
|
|
7
7
|
export function isIsoDate(value) {
|
|
8
|
-
if (!value)
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
if (!value) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
if (value instanceof Date) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
if (!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(value)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
11
17
|
const d = new Date(value);
|
|
12
18
|
return d instanceof Date && !isNaN(d.getTime()) && d.toISOString() === value;
|
|
13
19
|
}
|
|
@@ -7,8 +7,14 @@ import {ObjectId} from 'mongodb';
|
|
|
7
7
|
* @returns {boolean}
|
|
8
8
|
*/
|
|
9
9
|
export function isObjectId(value) {
|
|
10
|
-
if (!value)
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
if (!value) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
if (value instanceof ObjectId) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
if (typeof value !== 'string') {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
13
19
|
return value.match(/^[a-fA-F0-9]{24}$/) != null;
|
|
14
20
|
}
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
* @returns {string}
|
|
6
6
|
*/
|
|
7
7
|
export function toCamelCase(input) {
|
|
8
|
-
if (!input)
|
|
8
|
+
if (!input) {
|
|
9
|
+
return '';
|
|
10
|
+
}
|
|
9
11
|
const spacedString = String(input)
|
|
10
12
|
.replace(/([-_])/g, ' ')
|
|
11
13
|
.replace(/([a-z])([A-Z])/g, '$1 $2');
|
|
@@ -13,6 +15,8 @@ export function toCamelCase(input) {
|
|
|
13
15
|
.toLowerCase()
|
|
14
16
|
.replace(/\s(.)/g, $1 => $1.toUpperCase())
|
|
15
17
|
.replace(/\s/g, '');
|
|
16
|
-
if (!intermediateCased)
|
|
18
|
+
if (!intermediateCased) {
|
|
19
|
+
return '';
|
|
20
|
+
}
|
|
17
21
|
return intermediateCased.charAt(0).toLowerCase() + intermediateCased.slice(1);
|
|
18
22
|
}
|
|
@@ -14,12 +14,13 @@ import {InvalidArgumentError} from '@e22m4u/js-repository';
|
|
|
14
14
|
* @returns {*}
|
|
15
15
|
*/
|
|
16
16
|
export function transformValuesDeep(value, transformer) {
|
|
17
|
-
if (!transformer || typeof transformer !== 'function')
|
|
17
|
+
if (!transformer || typeof transformer !== 'function') {
|
|
18
18
|
throw new InvalidArgumentError(
|
|
19
19
|
'The second argument of "transformValuesDeep" ' +
|
|
20
20
|
'must be a Function, but %v given.',
|
|
21
21
|
transformer,
|
|
22
22
|
);
|
|
23
|
+
}
|
|
23
24
|
if (Array.isArray(value)) {
|
|
24
25
|
value.forEach((v, i) => (value[i] = transformValuesDeep(v, transformer)));
|
|
25
26
|
return value;
|
|
@@ -30,8 +31,9 @@ export function transformValuesDeep(value, transformer) {
|
|
|
30
31
|
(value.constructor && value.constructor.name === 'Object')
|
|
31
32
|
) {
|
|
32
33
|
Object.keys(value).forEach(key => {
|
|
33
|
-
if (Object.prototype.hasOwnProperty.call(value, key))
|
|
34
|
+
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
34
35
|
value[key] = transformValuesDeep(value[key], transformer);
|
|
36
|
+
}
|
|
35
37
|
});
|
|
36
38
|
return value;
|
|
37
39
|
// Date, ObjectId etc..
|