@unchainedshop/mongodb 2.5.12 → 2.6.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.
- package/lib/build-db-indexes.d.ts +8 -0
- package/lib/build-db-indexes.js +34 -0
- package/lib/build-db-indexes.js.map +1 -0
- package/lib/build-sort-option.d.ts +4 -0
- package/lib/build-sort-option.js +13 -0
- package/lib/build-sort-option.js.map +1 -0
- package/lib/check-id.d.ts +4 -0
- package/lib/check-id.js +6 -0
- package/lib/check-id.js.map +1 -0
- package/lib/find-localized-text.d.ts +5 -0
- package/lib/find-localized-text.js +45 -0
- package/lib/find-localized-text.js.map +1 -0
- package/lib/find-preserving-ids.d.ts +2 -0
- package/lib/find-preserving-ids.js +33 -0
- package/lib/find-preserving-ids.js.map +1 -0
- package/lib/generate-db-filter-by-id.d.ts +4 -0
- package/lib/generate-db-filter-by-id.js +5 -0
- package/lib/generate-db-filter-by-id.js.map +1 -0
- package/lib/generate-db-mutations.d.ts +10 -0
- package/lib/generate-db-mutations.js +73 -0
- package/lib/generate-db-mutations.js.map +1 -0
- package/lib/generate-db-object-id.d.ts +7 -0
- package/lib/generate-db-object-id.js +25 -0
- package/lib/generate-db-object-id.js.map +1 -0
- package/lib/initDb.js +32 -0
- package/lib/initDb.js.map +1 -0
- package/lib/mongodb-index.d.ts +11 -1
- package/lib/mongodb-index.js +14 -1
- package/lib/mongodb-index.js.map +1 -1
- package/package.json +8 -7
- package/src/build-db-indexes.ts +53 -0
- package/src/build-sort-option.ts +17 -0
- package/src/check-id.ts +13 -0
- package/src/find-localized-text.ts +63 -0
- package/src/find-preserving-ids.ts +44 -0
- package/src/generate-db-filter-by-id.ts +9 -0
- package/src/generate-db-mutations.ts +93 -0
- package/src/generate-db-object-id.ts +24 -0
- package/src/initDb.ts +36 -0
- package/src/mongodb-index.test.ts +71 -0
- package/src/mongodb-index.ts +18 -1
- package/lib/db/initDb.js +0 -54
- package/lib/db/initDb.js.map +0 -1
- package/src/db/initDb.ts +0 -61
- package/tests/mongodb-index.test.ts +0 -5
- /package/lib/{db/initDb.d.ts → initDb.d.ts} +0 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Collection, Document, CreateIndexesOptions, IndexDirection } from 'mongodb';
|
|
2
|
+
export type Indexes<T extends Document> = Array<{
|
|
3
|
+
index: {
|
|
4
|
+
[key in keyof T]?: IndexDirection;
|
|
5
|
+
};
|
|
6
|
+
options?: CreateIndexesOptions;
|
|
7
|
+
}>;
|
|
8
|
+
export declare const buildDbIndexes: <T extends Document>(collection: Collection<T>, indexes: Indexes<T>) => Promise<boolean>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { log, LogLevel } from '@unchainedshop/logger';
|
|
2
|
+
const buildIndexes = (collection, indexes) => Promise.all(indexes.map(async ({ index, options }) => {
|
|
3
|
+
try {
|
|
4
|
+
await collection.createIndex(index, options);
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
catch (e) {
|
|
8
|
+
log(e, { level: LogLevel.Error });
|
|
9
|
+
return e;
|
|
10
|
+
}
|
|
11
|
+
}));
|
|
12
|
+
export const buildDbIndexes = async (collection, indexes) => {
|
|
13
|
+
let success = true;
|
|
14
|
+
const buildErrors = (await buildIndexes(collection, indexes)).filter(Boolean);
|
|
15
|
+
if (buildErrors.length) {
|
|
16
|
+
// try {
|
|
17
|
+
// const dropError = await collection.dropIndexes();
|
|
18
|
+
// } catch (e) {
|
|
19
|
+
// /* */
|
|
20
|
+
// }
|
|
21
|
+
// if (!dropError) {
|
|
22
|
+
const rebuildErrors = (await buildIndexes(collection, indexes)).filter(Boolean);
|
|
23
|
+
if (rebuildErrors.length) {
|
|
24
|
+
log(`Error building some indexes for ${collection.collectionName}`, {
|
|
25
|
+
level: LogLevel.Error,
|
|
26
|
+
...rebuildErrors,
|
|
27
|
+
});
|
|
28
|
+
success = false;
|
|
29
|
+
}
|
|
30
|
+
// }
|
|
31
|
+
}
|
|
32
|
+
return success;
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=build-db-indexes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-db-indexes.js","sourceRoot":"","sources":["../src/build-db-indexes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAOtD,MAAM,YAAY,GAAG,CACnB,UAAyB,EACzB,OAAmB,EACY,EAAE,CACjC,OAAO,CAAC,GAAG,CACT,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE;IACvC,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC7C,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;QAClC,OAAO,CAAU,CAAC;IACpB,CAAC;AACH,CAAC,CAAC,CACH,CAAC;AAEJ,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EACjC,UAAyB,EACzB,OAAmB,EACnB,EAAE;IACF,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,MAAM,WAAW,GAAG,CAAC,MAAM,YAAY,CAAI,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEjF,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;QACvB,QAAQ;QACR,sDAAsD;QACtD,gBAAgB;QAChB,UAAU;QACV,IAAI;QAEJ,oBAAoB;QACpB,MAAM,aAAa,GAAG,CAAC,MAAM,YAAY,CAAI,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEnF,IAAI,aAAa,CAAC,MAAM,EAAE,CAAC;YACzB,GAAG,CAAC,mCAAmC,UAAU,CAAC,cAAc,EAAE,EAAE;gBAClE,KAAK,EAAE,QAAQ,CAAC,KAAK;gBACrB,GAAG,aAAa;aACjB,CAAC,CAAC;YACH,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC;QACD,IAAI;IACN,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const SORT_DIRECTIONS = {
|
|
2
|
+
ASC: 1,
|
|
3
|
+
DESC: -1,
|
|
4
|
+
};
|
|
5
|
+
export const buildSortOptions = (sort = []) => {
|
|
6
|
+
const sortBy = {};
|
|
7
|
+
sort?.forEach(({ key, value }) => {
|
|
8
|
+
sortBy[key] = SORT_DIRECTIONS[value];
|
|
9
|
+
});
|
|
10
|
+
return sortBy;
|
|
11
|
+
};
|
|
12
|
+
export default buildSortOptions;
|
|
13
|
+
//# sourceMappingURL=build-sort-option.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-sort-option.js","sourceRoot":"","sources":["../src/build-sort-option.ts"],"names":[],"mappings":"AAGA,MAAM,eAAe,GAAG;IACtB,GAAG,EAAE,CAAC;IACN,IAAI,EAAE,CAAC,CAAC;CACT,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAA0B,EAAE,EAAQ,EAAE;IACrE,MAAM,MAAM,GAAG,EAAE,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE;QAC/B,MAAM,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
package/lib/check-id.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-id.js","sourceRoot":"","sources":["../src/check-id.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,CACrB,KAAa,EACb,KAKa,EACP,EAAE;IACR,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,KAAK,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;IAC3C,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import 'abort-controller/polyfill.js';
|
|
2
|
+
import { Locale } from '@unchainedshop/types/common.js';
|
|
3
|
+
import type { Collection, Document, Filter } from 'mongodb';
|
|
4
|
+
export declare const findLocalizedText: <T extends Document>(collection: Collection<T>, selector: Filter<T>, locale: Locale) => Promise<T>;
|
|
5
|
+
export default findLocalizedText;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import 'abort-controller/polyfill.js';
|
|
2
|
+
import * as lruCache from 'lru-cache';
|
|
3
|
+
import { systemLocale } from '@unchainedshop/utils';
|
|
4
|
+
const { NODE_ENV } = process.env;
|
|
5
|
+
const ttl = NODE_ENV === 'production' ? 1000 * 10 : 0; // 10 seconds or 0 seconds
|
|
6
|
+
const textCache = new lruCache.LRUCache({ max: 50000, ttl });
|
|
7
|
+
const extendSelectorWithLocale = (selector, locale) => {
|
|
8
|
+
const localeSelector = {
|
|
9
|
+
locale: { $in: [locale.normalized, locale.language] },
|
|
10
|
+
};
|
|
11
|
+
return { ...localeSelector, ...selector };
|
|
12
|
+
};
|
|
13
|
+
export const findLocalizedText = async (collection, selector, locale) => {
|
|
14
|
+
const cacheKey = JSON.stringify({
|
|
15
|
+
n: collection.collectionName, // eslint-disable-line
|
|
16
|
+
s: selector,
|
|
17
|
+
l: locale,
|
|
18
|
+
});
|
|
19
|
+
const cachedText = textCache.get(cacheKey);
|
|
20
|
+
if (cachedText)
|
|
21
|
+
return cachedText;
|
|
22
|
+
const exactTranslation = await collection.findOne(extendSelectorWithLocale(selector, locale), {
|
|
23
|
+
sort: { updated: -1 },
|
|
24
|
+
});
|
|
25
|
+
if (exactTranslation) {
|
|
26
|
+
textCache.set(cacheKey, exactTranslation);
|
|
27
|
+
return exactTranslation;
|
|
28
|
+
}
|
|
29
|
+
if (systemLocale.normalized !== locale.normalized) {
|
|
30
|
+
const fallbackTranslation = await collection.findOne(extendSelectorWithLocale(selector, systemLocale), {
|
|
31
|
+
sort: { updated: -1 },
|
|
32
|
+
});
|
|
33
|
+
if (fallbackTranslation) {
|
|
34
|
+
textCache.set(cacheKey, fallbackTranslation);
|
|
35
|
+
return fallbackTranslation;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const foundText = await collection.findOne(selector, {
|
|
39
|
+
sort: { updated: -1 },
|
|
40
|
+
});
|
|
41
|
+
textCache.set(cacheKey, foundText);
|
|
42
|
+
return foundText;
|
|
43
|
+
};
|
|
44
|
+
export default findLocalizedText;
|
|
45
|
+
//# sourceMappingURL=find-localized-text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-localized-text.js","sourceRoot":"","sources":["../src/find-localized-text.ts"],"names":[],"mappings":"AAAA,OAAO,8BAA8B,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,WAAW,CAAC;AAGtC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;AAEjC,MAAM,GAAG,GAAG,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,0BAA0B;AAEjF,MAAM,SAAS,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;AAE7D,MAAM,wBAAwB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE;IACpD,MAAM,cAAc,GAAG;QACrB,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE;KACtD,CAAC;IACF,OAAO,EAAE,GAAG,cAAc,EAAE,GAAG,QAAQ,EAAE,CAAC;AAC5C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EACpC,UAAyB,EACzB,QAAmB,EACnB,MAAc,EACF,EAAE;IACd,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC;QAC9B,CAAC,EAAE,UAAU,CAAC,cAAc,EAAE,sBAAsB;QACpD,CAAC,EAAE,QAAQ;QACX,CAAC,EAAE,MAAM;KACV,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAE3C,IAAI,UAAU;QAAE,OAAO,UAAe,CAAC;IAEvC,MAAM,gBAAgB,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,wBAAwB,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE;QAC5F,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE;KACtB,CAAC,CAAC;IACH,IAAI,gBAAgB,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;QAC1C,OAAO,gBAAqB,CAAC;IAC/B,CAAC;IAED,IAAI,YAAY,CAAC,UAAU,KAAK,MAAM,CAAC,UAAU,EAAE,CAAC;QAClD,MAAM,mBAAmB,GAAG,MAAM,UAAU,CAAC,OAAO,CAClD,wBAAwB,CAAC,QAAQ,EAAE,YAAY,CAAC,EAChD;YACE,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE;SACtB,CACF,CAAC;QACF,IAAI,mBAAmB,EAAE,CAAC;YACxB,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;YAC7C,OAAO,mBAAwB,CAAC;QAClC,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE;QACnD,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE;KACtB,CAAC,CAAC;IACH,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACnC,OAAO,SAAc,CAAC;AACxB,CAAC,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const { AMAZON_DOCUMENTDB_COMPAT_MODE } = process.env;
|
|
2
|
+
const sortByIndex = {
|
|
3
|
+
index: 1,
|
|
4
|
+
};
|
|
5
|
+
const sortBySequence = {
|
|
6
|
+
sequence: 1,
|
|
7
|
+
};
|
|
8
|
+
const defaultSort = AMAZON_DOCUMENTDB_COMPAT_MODE ? sortBySequence : sortByIndex;
|
|
9
|
+
export const findPreservingIds = (collection) => async (selector, ids, options) => {
|
|
10
|
+
const { skip, limit, sort = defaultSort } = options || {};
|
|
11
|
+
const filteredSelector = {
|
|
12
|
+
...selector,
|
|
13
|
+
_id: { $in: ids },
|
|
14
|
+
};
|
|
15
|
+
const filteredPipeline = [
|
|
16
|
+
{
|
|
17
|
+
$match: filteredSelector,
|
|
18
|
+
},
|
|
19
|
+
typeof sort === 'object' &&
|
|
20
|
+
'index' in sort && {
|
|
21
|
+
$addFields: {
|
|
22
|
+
index: { $indexOfArray: [ids, '$_id'] },
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
sort && { $sort: sort },
|
|
26
|
+
skip && { $skip: skip },
|
|
27
|
+
limit && { $limit: limit },
|
|
28
|
+
].filter(Boolean);
|
|
29
|
+
const aggregationPointer = collection.aggregate(filteredPipeline);
|
|
30
|
+
const items = await aggregationPointer.toArray();
|
|
31
|
+
return items;
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=find-preserving-ids.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-preserving-ids.js","sourceRoot":"","sources":["../src/find-preserving-ids.ts"],"names":[],"mappings":"AAEA,MAAM,EAAE,6BAA6B,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;AAEtD,MAAM,WAAW,GAAG;IAClB,KAAK,EAAE,CAAC;CACT,CAAC;AAEF,MAAM,cAAc,GAAG;IACrB,QAAQ,EAAE,CAAC;CACZ,CAAC;AAEF,MAAM,WAAW,GAAG,6BAA6B,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,WAAW,CAAC;AAEjF,MAAM,CAAC,MAAM,iBAAiB,GAC5B,CACE,UAAyB,EACgE,EAAE,CAC7F,KAAK,EAAE,QAAmB,EAAE,GAAkB,EAAE,OAAqB,EAAqB,EAAE;IAC1F,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,GAAG,WAAW,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;IAC1D,MAAM,gBAAgB,GAAG;QACvB,GAAG,QAAQ;QACX,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE;KAClB,CAAC;IAEF,MAAM,gBAAgB,GAAG;QACvB;YACE,MAAM,EAAE,gBAAgB;SACzB;QACD,OAAO,IAAI,KAAK,QAAQ;YACtB,OAAO,IAAI,IAAI,IAAI;YACjB,UAAU,EAAE;gBACV,KAAK,EAAE,EAAE,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE;aACxC;SACF;QACH,IAAI,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;QACvB,IAAI,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;QACvB,KAAK,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE;KAC3B,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAElB,MAAM,kBAAkB,GAAG,UAAU,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,OAAO,EAAE,CAAC;IACjD,OAAO,KAAiB,CAAC;AAC3B,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-db-filter-by-id.js","sourceRoot":"","sources":["../src/generate-db-filter-by-id.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,EAAW,EACX,QAAmB,EAAE,EACV,EAAE;IACb,MAAM,GAAG,GAAG,EAAE,IAAI,IAAI,CAAC,CAAC,kDAAkD;IAC1E,OAAO,EAAE,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;AAC3B,CAAC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import SimpleSchema from 'simpl-schema';
|
|
2
|
+
import { TimestampFields } from '@unchainedshop/types/common.js';
|
|
3
|
+
import { ModuleCreateMutation, ModuleMutations } from '@unchainedshop/types/core.js';
|
|
4
|
+
import { Collection } from 'mongodb';
|
|
5
|
+
export declare const generateDbMutations: <T extends TimestampFields & {
|
|
6
|
+
_id?: string;
|
|
7
|
+
}>(collection: Collection<T>, schema: SimpleSchema, options?: {
|
|
8
|
+
hasCreateOnly?: boolean;
|
|
9
|
+
permanentlyDeleteByDefault?: boolean;
|
|
10
|
+
}) => ModuleMutations<T> | ModuleCreateMutation<T>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { checkId } from './check-id.js';
|
|
2
|
+
import { generateDbObjectId } from './generate-db-object-id.js';
|
|
3
|
+
import { generateDbFilterById } from './generate-db-filter-by-id.js';
|
|
4
|
+
export const generateDbMutations = (collection, schema, options) => {
|
|
5
|
+
if (!collection)
|
|
6
|
+
throw new Error('Collection is missing');
|
|
7
|
+
if (!schema)
|
|
8
|
+
throw new Error('Schema is missing');
|
|
9
|
+
const { hasCreateOnly, permanentlyDeleteByDefault } = options || {
|
|
10
|
+
hasCreateOnly: false,
|
|
11
|
+
permanentlyDeleteByDefault: false,
|
|
12
|
+
};
|
|
13
|
+
const deletePermanently = async (_id) => {
|
|
14
|
+
checkId(_id);
|
|
15
|
+
const filter = generateDbFilterById(_id);
|
|
16
|
+
const result = await collection.deleteOne(filter);
|
|
17
|
+
return result.deletedCount;
|
|
18
|
+
};
|
|
19
|
+
return {
|
|
20
|
+
create: async (doc) => {
|
|
21
|
+
const values = schema.clean(doc);
|
|
22
|
+
values.created = new Date();
|
|
23
|
+
schema.validate(values);
|
|
24
|
+
values._id = doc._id || generateDbObjectId();
|
|
25
|
+
const result = await collection.insertOne(values);
|
|
26
|
+
return result.insertedId;
|
|
27
|
+
},
|
|
28
|
+
update: hasCreateOnly
|
|
29
|
+
? undefined
|
|
30
|
+
: async (_id, doc) => {
|
|
31
|
+
checkId(_id);
|
|
32
|
+
let modifier;
|
|
33
|
+
if (doc?.$set) {
|
|
34
|
+
const values = schema.clean(doc, { isModifier: true });
|
|
35
|
+
modifier = {
|
|
36
|
+
...values,
|
|
37
|
+
$set: {
|
|
38
|
+
...(values.$set || {}),
|
|
39
|
+
updated: new Date(),
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const values = schema.clean(doc);
|
|
45
|
+
modifier = {
|
|
46
|
+
$set: {
|
|
47
|
+
...values,
|
|
48
|
+
updated: new Date(),
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
schema.validate(modifier, { modifier: true });
|
|
53
|
+
const filter = generateDbFilterById(_id, { deleted: null });
|
|
54
|
+
await collection.updateOne(filter, modifier);
|
|
55
|
+
return _id;
|
|
56
|
+
},
|
|
57
|
+
deletePermanently: hasCreateOnly ? undefined : deletePermanently,
|
|
58
|
+
delete: hasCreateOnly
|
|
59
|
+
? undefined
|
|
60
|
+
: async (_id) => {
|
|
61
|
+
if (permanentlyDeleteByDefault) {
|
|
62
|
+
return deletePermanently(_id);
|
|
63
|
+
}
|
|
64
|
+
checkId(_id);
|
|
65
|
+
const filter = generateDbFilterById(_id, { deleted: null });
|
|
66
|
+
const modifier = { $set: { deleted: new Date() } };
|
|
67
|
+
const values = schema.clean(modifier, { isModifier: true });
|
|
68
|
+
const result = await collection.updateOne(filter, values);
|
|
69
|
+
return result.modifiedCount;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=generate-db-mutations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-db-mutations.js","sourceRoot":"","sources":["../src/generate-db-mutations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
/**
|
|
3
|
+
* @name Random.hexString
|
|
4
|
+
* @summary Return a random string of `n` hexadecimal digits.
|
|
5
|
+
* @locus Anywhere
|
|
6
|
+
* @param {Number} n Length of the string
|
|
7
|
+
*/
|
|
8
|
+
export const generateDbObjectId = (digits = 24) => {
|
|
9
|
+
const numBytes = Math.ceil(digits / 2);
|
|
10
|
+
let bytes;
|
|
11
|
+
// Try to get cryptographically strong randomness. Fall back to
|
|
12
|
+
// non-cryptographically strong if not available.
|
|
13
|
+
try {
|
|
14
|
+
bytes = crypto.randomBytes(numBytes);
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
// XXX should re-throw any error except insufficient entropy
|
|
18
|
+
bytes = crypto.pseudoRandomBytes(numBytes);
|
|
19
|
+
}
|
|
20
|
+
const result = bytes.toString('hex');
|
|
21
|
+
// If the number of digits is odd, we'll have generated an extra 4 bits
|
|
22
|
+
// of randomness, so we need to trim the last digit.
|
|
23
|
+
return result.substring(0, digits);
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=generate-db-object-id.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-db-object-id.js","sourceRoot":"","sources":["../src/generate-db-object-id.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,MAAM,GAAG,EAAE,EAAU,EAAE;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvC,IAAI,KAAK,CAAC;IACV,+DAA+D;IAC/D,iDAAiD;IACjD,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,4DAA4D;QAC5D,KAAK,GAAG,MAAM,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC7C,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACrC,uEAAuE;IACvE,oDAAoD;IACpD,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AACrC,CAAC,CAAC"}
|
package/lib/initDb.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { mkdirSync } from 'fs';
|
|
2
|
+
import { MongoClient } from 'mongodb';
|
|
3
|
+
let mongod;
|
|
4
|
+
export const startDb = async () => {
|
|
5
|
+
const { MongoMemoryServer } = await import('mongodb-memory-server');
|
|
6
|
+
try {
|
|
7
|
+
mkdirSync(`${process.cwd()}/.db`);
|
|
8
|
+
}
|
|
9
|
+
catch (e) {
|
|
10
|
+
//
|
|
11
|
+
}
|
|
12
|
+
mongod = await MongoMemoryServer.create({
|
|
13
|
+
instance: {
|
|
14
|
+
dbPath: `${process.cwd()}/.db`,
|
|
15
|
+
storageEngine: 'wiredTiger',
|
|
16
|
+
port: parseInt(process.env.PORT, 10) + 1,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
return `${mongod.getUri()}unchained`;
|
|
20
|
+
};
|
|
21
|
+
export const stopDb = async () => {
|
|
22
|
+
await mongod.stop();
|
|
23
|
+
};
|
|
24
|
+
const initDb = async () => {
|
|
25
|
+
const url = process.env.MONGO_URL || (await startDb());
|
|
26
|
+
const client = new MongoClient(url);
|
|
27
|
+
await client.connect();
|
|
28
|
+
const db = client.db();
|
|
29
|
+
return db;
|
|
30
|
+
};
|
|
31
|
+
export { initDb };
|
|
32
|
+
//# sourceMappingURL=initDb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"initDb.js","sourceRoot":"","sources":["../src/initDb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,EAAM,WAAW,EAAE,MAAM,SAAS,CAAC;AAE1C,IAAI,MAAM,CAAC;AAEX,MAAM,CAAC,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;IAChC,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;IAEpE,IAAI,CAAC;QACH,SAAS,CAAC,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,EAAE;IACJ,CAAC;IACD,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC;QACtC,QAAQ,EAAE;YACR,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM;YAC9B,aAAa,EAAE,YAAY;YAC3B,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC;SACzC;KACF,CAAC,CAAC;IACH,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;AACvC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;IAC/B,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,MAAM,GAAG,KAAK,IAAiB,EAAE;IACrC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;IACvB,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,EAAE,CAAC;IACvB,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAEF,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
package/lib/mongodb-index.d.ts
CHANGED
|
@@ -1 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import * as mongodb from 'mongodb';
|
|
2
|
+
export { initDb, startDb, stopDb } from './initDb.js';
|
|
3
|
+
export { checkId } from './check-id.js';
|
|
4
|
+
export { generateDbObjectId } from './generate-db-object-id.js';
|
|
5
|
+
export { generateDbFilterById } from './generate-db-filter-by-id.js';
|
|
6
|
+
export { generateDbMutations } from './generate-db-mutations.js';
|
|
7
|
+
export { buildDbIndexes } from './build-db-indexes.js';
|
|
8
|
+
export { findPreservingIds } from './find-preserving-ids.js';
|
|
9
|
+
export { buildSortOptions } from './build-sort-option.js';
|
|
10
|
+
export { findLocalizedText } from './find-localized-text.js';
|
|
11
|
+
export { mongodb };
|
package/lib/mongodb-index.js
CHANGED
|
@@ -1,2 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
import * as mongodb from 'mongodb';
|
|
2
|
+
export { initDb, startDb, stopDb } from './initDb.js';
|
|
3
|
+
/*
|
|
4
|
+
* Db utils
|
|
5
|
+
*/
|
|
6
|
+
export { checkId } from './check-id.js';
|
|
7
|
+
export { generateDbObjectId } from './generate-db-object-id.js';
|
|
8
|
+
export { generateDbFilterById } from './generate-db-filter-by-id.js';
|
|
9
|
+
export { generateDbMutations } from './generate-db-mutations.js';
|
|
10
|
+
export { buildDbIndexes } from './build-db-indexes.js';
|
|
11
|
+
export { findPreservingIds } from './find-preserving-ids.js';
|
|
12
|
+
export { buildSortOptions } from './build-sort-option.js';
|
|
13
|
+
export { findLocalizedText } from './find-localized-text.js';
|
|
14
|
+
export { mongodb };
|
|
2
15
|
//# sourceMappingURL=mongodb-index.js.map
|
package/lib/mongodb-index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mongodb-index.js","sourceRoot":"","sources":["../src/mongodb-index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"mongodb-index.js","sourceRoot":"","sources":["../src/mongodb-index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAEtD;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unchainedshop/mongodb",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "MongoDB provider for unchained platform",
|
|
5
5
|
"main": "lib/mongodb-index.js",
|
|
6
6
|
"exports": {
|
|
@@ -31,16 +31,17 @@
|
|
|
31
31
|
},
|
|
32
32
|
"homepage": "https://github.com/unchainedshop/unchained#readme",
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@unchainedshop/utils": "^2.
|
|
35
|
-
"
|
|
34
|
+
"@unchainedshop/utils": "^2.6.0",
|
|
35
|
+
"lru-cache": "^10.1.0",
|
|
36
|
+
"mongodb": "^6.3.0"
|
|
36
37
|
},
|
|
37
38
|
"optionalDependencies": {
|
|
38
|
-
"mongodb-memory-server": "^
|
|
39
|
+
"mongodb-memory-server": "^9.1.6"
|
|
39
40
|
},
|
|
40
41
|
"devDependencies": {
|
|
41
|
-
"@types/node": "^20.
|
|
42
|
-
"@unchainedshop/types": "^2.
|
|
42
|
+
"@types/node": "^20.11.6",
|
|
43
|
+
"@unchainedshop/types": "^2.6.0",
|
|
43
44
|
"jest": "^29.7.0",
|
|
44
|
-
"typescript": "^5.3.
|
|
45
|
+
"typescript": "^5.3.3"
|
|
45
46
|
}
|
|
46
47
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Collection, Document, CreateIndexesOptions, IndexDirection } from 'mongodb';
|
|
2
|
+
import { log, LogLevel } from '@unchainedshop/logger';
|
|
3
|
+
|
|
4
|
+
export type Indexes<T extends Document> = Array<{
|
|
5
|
+
index: { [key in keyof T]?: IndexDirection }; // TODO: Support key with object path (e.g. 'product.proxy.assignments')
|
|
6
|
+
options?: CreateIndexesOptions;
|
|
7
|
+
}>;
|
|
8
|
+
|
|
9
|
+
const buildIndexes = <T>(
|
|
10
|
+
collection: Collection<T>,
|
|
11
|
+
indexes: Indexes<T>,
|
|
12
|
+
): Promise<Array<false | Error>> =>
|
|
13
|
+
Promise.all(
|
|
14
|
+
indexes.map(async ({ index, options }) => {
|
|
15
|
+
try {
|
|
16
|
+
await collection.createIndex(index, options);
|
|
17
|
+
return false;
|
|
18
|
+
} catch (e: any) {
|
|
19
|
+
log(e, { level: LogLevel.Error });
|
|
20
|
+
return e as Error;
|
|
21
|
+
}
|
|
22
|
+
}),
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
export const buildDbIndexes = async <T extends Document>(
|
|
26
|
+
collection: Collection<T>,
|
|
27
|
+
indexes: Indexes<T>,
|
|
28
|
+
) => {
|
|
29
|
+
let success = true;
|
|
30
|
+
const buildErrors = (await buildIndexes<T>(collection, indexes)).filter(Boolean);
|
|
31
|
+
|
|
32
|
+
if (buildErrors.length) {
|
|
33
|
+
// try {
|
|
34
|
+
// const dropError = await collection.dropIndexes();
|
|
35
|
+
// } catch (e) {
|
|
36
|
+
// /* */
|
|
37
|
+
// }
|
|
38
|
+
|
|
39
|
+
// if (!dropError) {
|
|
40
|
+
const rebuildErrors = (await buildIndexes<T>(collection, indexes)).filter(Boolean);
|
|
41
|
+
|
|
42
|
+
if (rebuildErrors.length) {
|
|
43
|
+
log(`Error building some indexes for ${collection.collectionName}`, {
|
|
44
|
+
level: LogLevel.Error,
|
|
45
|
+
...rebuildErrors,
|
|
46
|
+
});
|
|
47
|
+
success = false;
|
|
48
|
+
}
|
|
49
|
+
// }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return success;
|
|
53
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SortOption } from '@unchainedshop/types/api.js';
|
|
2
|
+
import type { Sort } from 'mongodb';
|
|
3
|
+
|
|
4
|
+
const SORT_DIRECTIONS = {
|
|
5
|
+
ASC: 1,
|
|
6
|
+
DESC: -1,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const buildSortOptions = (sort: Array<SortOption> = []): Sort => {
|
|
10
|
+
const sortBy = {};
|
|
11
|
+
sort?.forEach(({ key, value }) => {
|
|
12
|
+
sortBy[key] = SORT_DIRECTIONS[value];
|
|
13
|
+
});
|
|
14
|
+
return sortBy;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default buildSortOptions;
|
package/src/check-id.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import 'abort-controller/polyfill.js';
|
|
2
|
+
import * as lruCache from 'lru-cache';
|
|
3
|
+
import { Locale } from '@unchainedshop/types/common.js';
|
|
4
|
+
import type { Collection, Document, Filter } from 'mongodb';
|
|
5
|
+
import { systemLocale } from '@unchainedshop/utils';
|
|
6
|
+
|
|
7
|
+
const { NODE_ENV } = process.env;
|
|
8
|
+
|
|
9
|
+
const ttl = NODE_ENV === 'production' ? 1000 * 10 : 0; // 10 seconds or 0 seconds
|
|
10
|
+
|
|
11
|
+
const textCache = new lruCache.LRUCache({ max: 50000, ttl });
|
|
12
|
+
|
|
13
|
+
const extendSelectorWithLocale = (selector, locale) => {
|
|
14
|
+
const localeSelector = {
|
|
15
|
+
locale: { $in: [locale.normalized, locale.language] },
|
|
16
|
+
};
|
|
17
|
+
return { ...localeSelector, ...selector };
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const findLocalizedText = async <T extends Document>(
|
|
21
|
+
collection: Collection<T>,
|
|
22
|
+
selector: Filter<T>,
|
|
23
|
+
locale: Locale,
|
|
24
|
+
): Promise<T> => {
|
|
25
|
+
const cacheKey = JSON.stringify({
|
|
26
|
+
n: collection.collectionName, // eslint-disable-line
|
|
27
|
+
s: selector,
|
|
28
|
+
l: locale,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const cachedText = textCache.get(cacheKey);
|
|
32
|
+
|
|
33
|
+
if (cachedText) return cachedText as T;
|
|
34
|
+
|
|
35
|
+
const exactTranslation = await collection.findOne(extendSelectorWithLocale(selector, locale), {
|
|
36
|
+
sort: { updated: -1 },
|
|
37
|
+
});
|
|
38
|
+
if (exactTranslation) {
|
|
39
|
+
textCache.set(cacheKey, exactTranslation);
|
|
40
|
+
return exactTranslation as T;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (systemLocale.normalized !== locale.normalized) {
|
|
44
|
+
const fallbackTranslation = await collection.findOne(
|
|
45
|
+
extendSelectorWithLocale(selector, systemLocale),
|
|
46
|
+
{
|
|
47
|
+
sort: { updated: -1 },
|
|
48
|
+
},
|
|
49
|
+
);
|
|
50
|
+
if (fallbackTranslation) {
|
|
51
|
+
textCache.set(cacheKey, fallbackTranslation);
|
|
52
|
+
return fallbackTranslation as T;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const foundText = await collection.findOne(selector, {
|
|
57
|
+
sort: { updated: -1 },
|
|
58
|
+
});
|
|
59
|
+
textCache.set(cacheKey, foundText);
|
|
60
|
+
return foundText as T;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export default findLocalizedText;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Collection, FindOptions, Filter } from 'mongodb';
|
|
2
|
+
|
|
3
|
+
const { AMAZON_DOCUMENTDB_COMPAT_MODE } = process.env;
|
|
4
|
+
|
|
5
|
+
const sortByIndex = {
|
|
6
|
+
index: 1,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const sortBySequence = {
|
|
10
|
+
sequence: 1,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const defaultSort = AMAZON_DOCUMENTDB_COMPAT_MODE ? sortBySequence : sortByIndex;
|
|
14
|
+
|
|
15
|
+
export const findPreservingIds =
|
|
16
|
+
<T>(
|
|
17
|
+
collection: Collection<T>,
|
|
18
|
+
): ((selector: Filter<T>, ids: Array<string>, options?: FindOptions) => Promise<Array<T>>) =>
|
|
19
|
+
async (selector: Filter<T>, ids: Array<string>, options?: FindOptions): Promise<Array<T>> => {
|
|
20
|
+
const { skip, limit, sort = defaultSort } = options || {};
|
|
21
|
+
const filteredSelector = {
|
|
22
|
+
...selector,
|
|
23
|
+
_id: { $in: ids },
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const filteredPipeline = [
|
|
27
|
+
{
|
|
28
|
+
$match: filteredSelector,
|
|
29
|
+
},
|
|
30
|
+
typeof sort === 'object' &&
|
|
31
|
+
'index' in sort && {
|
|
32
|
+
$addFields: {
|
|
33
|
+
index: { $indexOfArray: [ids, '$_id'] },
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
sort && { $sort: sort },
|
|
37
|
+
skip && { $skip: skip },
|
|
38
|
+
limit && { $limit: limit },
|
|
39
|
+
].filter(Boolean);
|
|
40
|
+
|
|
41
|
+
const aggregationPointer = collection.aggregate(filteredPipeline);
|
|
42
|
+
const items = await aggregationPointer.toArray();
|
|
43
|
+
return items as Array<T>;
|
|
44
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Filter } from 'mongodb';
|
|
2
|
+
|
|
3
|
+
export const generateDbFilterById = <T extends { _id?: string }>(
|
|
4
|
+
id: unknown,
|
|
5
|
+
query: Filter<T> = {},
|
|
6
|
+
): Filter<T> => {
|
|
7
|
+
const _id = id || null; // never undefined, else it will get the first one
|
|
8
|
+
return { _id, ...query };
|
|
9
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import SimpleSchema from 'simpl-schema';
|
|
2
|
+
import { TimestampFields } from '@unchainedshop/types/common.js';
|
|
3
|
+
import { ModuleCreateMutation, ModuleMutations } from '@unchainedshop/types/core.js';
|
|
4
|
+
import { Collection, UpdateFilter } from 'mongodb';
|
|
5
|
+
import { checkId } from './check-id.js';
|
|
6
|
+
import { generateDbObjectId } from './generate-db-object-id.js';
|
|
7
|
+
import { generateDbFilterById } from './generate-db-filter-by-id.js';
|
|
8
|
+
|
|
9
|
+
export const generateDbMutations = <T extends TimestampFields & { _id?: string }>(
|
|
10
|
+
collection: Collection<T>,
|
|
11
|
+
schema: SimpleSchema,
|
|
12
|
+
options?: {
|
|
13
|
+
hasCreateOnly?: boolean;
|
|
14
|
+
permanentlyDeleteByDefault?: boolean;
|
|
15
|
+
},
|
|
16
|
+
): ModuleMutations<T> | ModuleCreateMutation<T> => {
|
|
17
|
+
if (!collection) throw new Error('Collection is missing');
|
|
18
|
+
if (!schema) throw new Error('Schema is missing');
|
|
19
|
+
|
|
20
|
+
const { hasCreateOnly, permanentlyDeleteByDefault } = options || {
|
|
21
|
+
hasCreateOnly: false,
|
|
22
|
+
permanentlyDeleteByDefault: false,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const deletePermanently = async (_id) => {
|
|
26
|
+
checkId(_id);
|
|
27
|
+
const filter = generateDbFilterById<T>(_id);
|
|
28
|
+
const result = await collection.deleteOne(filter);
|
|
29
|
+
return result.deletedCount;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
create: async (doc) => {
|
|
34
|
+
const values: any = schema.clean(doc);
|
|
35
|
+
values.created = new Date();
|
|
36
|
+
schema.validate(values);
|
|
37
|
+
values._id = doc._id || generateDbObjectId();
|
|
38
|
+
|
|
39
|
+
const result = await collection.insertOne(values);
|
|
40
|
+
return result.insertedId as string;
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
update: hasCreateOnly
|
|
44
|
+
? undefined
|
|
45
|
+
: async (_id, doc) => {
|
|
46
|
+
checkId(_id);
|
|
47
|
+
|
|
48
|
+
let modifier: UpdateFilter<T>;
|
|
49
|
+
|
|
50
|
+
if ((doc as UpdateFilter<T>)?.$set) {
|
|
51
|
+
const values: any = schema.clean(doc as any, { isModifier: true });
|
|
52
|
+
modifier = {
|
|
53
|
+
...values,
|
|
54
|
+
$set: {
|
|
55
|
+
...(values.$set || {}),
|
|
56
|
+
updated: new Date(),
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
} else {
|
|
60
|
+
const values: any = schema.clean(doc as any);
|
|
61
|
+
modifier = {
|
|
62
|
+
$set: {
|
|
63
|
+
...values,
|
|
64
|
+
updated: new Date(),
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
schema.validate(modifier, { modifier: true });
|
|
70
|
+
const filter = generateDbFilterById<T>(_id, { deleted: null });
|
|
71
|
+
await collection.updateOne(filter, modifier);
|
|
72
|
+
|
|
73
|
+
return _id;
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
deletePermanently: hasCreateOnly ? undefined : deletePermanently,
|
|
77
|
+
|
|
78
|
+
delete: hasCreateOnly
|
|
79
|
+
? undefined
|
|
80
|
+
: async (_id) => {
|
|
81
|
+
if (permanentlyDeleteByDefault) {
|
|
82
|
+
return deletePermanently(_id);
|
|
83
|
+
}
|
|
84
|
+
checkId(_id);
|
|
85
|
+
const filter = generateDbFilterById<T>(_id, { deleted: null });
|
|
86
|
+
const modifier = { $set: { deleted: new Date() } };
|
|
87
|
+
const values = schema.clean(modifier, { isModifier: true });
|
|
88
|
+
const result = await collection.updateOne(filter, values);
|
|
89
|
+
|
|
90
|
+
return result.modifiedCount;
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @name Random.hexString
|
|
5
|
+
* @summary Return a random string of `n` hexadecimal digits.
|
|
6
|
+
* @locus Anywhere
|
|
7
|
+
* @param {Number} n Length of the string
|
|
8
|
+
*/
|
|
9
|
+
export const generateDbObjectId = (digits = 24): string => {
|
|
10
|
+
const numBytes = Math.ceil(digits / 2);
|
|
11
|
+
let bytes;
|
|
12
|
+
// Try to get cryptographically strong randomness. Fall back to
|
|
13
|
+
// non-cryptographically strong if not available.
|
|
14
|
+
try {
|
|
15
|
+
bytes = crypto.randomBytes(numBytes);
|
|
16
|
+
} catch (e) {
|
|
17
|
+
// XXX should re-throw any error except insufficient entropy
|
|
18
|
+
bytes = crypto.pseudoRandomBytes(numBytes);
|
|
19
|
+
}
|
|
20
|
+
const result = bytes.toString('hex');
|
|
21
|
+
// If the number of digits is odd, we'll have generated an extra 4 bits
|
|
22
|
+
// of randomness, so we need to trim the last digit.
|
|
23
|
+
return result.substring(0, digits);
|
|
24
|
+
};
|
package/src/initDb.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { mkdirSync } from 'fs';
|
|
2
|
+
import { Db, MongoClient } from 'mongodb';
|
|
3
|
+
|
|
4
|
+
let mongod;
|
|
5
|
+
|
|
6
|
+
export const startDb = async () => {
|
|
7
|
+
const { MongoMemoryServer } = await import('mongodb-memory-server');
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
mkdirSync(`${process.cwd()}/.db`);
|
|
11
|
+
} catch (e) {
|
|
12
|
+
//
|
|
13
|
+
}
|
|
14
|
+
mongod = await MongoMemoryServer.create({
|
|
15
|
+
instance: {
|
|
16
|
+
dbPath: `${process.cwd()}/.db`,
|
|
17
|
+
storageEngine: 'wiredTiger',
|
|
18
|
+
port: parseInt(process.env.PORT, 10) + 1,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
return `${mongod.getUri()}unchained`;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const stopDb = async () => {
|
|
25
|
+
await mongod.stop();
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const initDb = async (): Promise<Db> => {
|
|
29
|
+
const url = process.env.MONGO_URL || (await startDb());
|
|
30
|
+
const client = new MongoClient(url);
|
|
31
|
+
await client.connect();
|
|
32
|
+
const db = client.db();
|
|
33
|
+
return db;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export { initDb };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { SortDirection } from '@unchainedshop/types/api.js';
|
|
2
|
+
import {
|
|
3
|
+
buildSortOptions,
|
|
4
|
+
checkId,
|
|
5
|
+
generateDbObjectId,
|
|
6
|
+
} from './mongodb-index.js';
|
|
7
|
+
|
|
8
|
+
describe('Mongo', () => {
|
|
9
|
+
it('Init', async () => {
|
|
10
|
+
expect(true).toBeTruthy()
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
describe('buildSortOptions', () => {
|
|
14
|
+
it('should return the correct db sort format', () => {
|
|
15
|
+
const sort = [ { key: 'name', value: SortDirection.ASC }, { key: 'age', value: SortDirection.DESC }, ];
|
|
16
|
+
expect(buildSortOptions(sort)).toEqual({ name: 1, age: -1 });
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('checkId', () => {
|
|
22
|
+
it('with a string value', () => {
|
|
23
|
+
const value = '12345';
|
|
24
|
+
const error = { message: 'Invalid id' };
|
|
25
|
+
|
|
26
|
+
expect(() => checkId(value, error)).not.toThrow();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('with a non-string value', () => {
|
|
30
|
+
const value: any = 12345;
|
|
31
|
+
const error = { message: 'Invalid id' };
|
|
32
|
+
|
|
33
|
+
expect(() => checkId(value, error)).toThrow('Invalid id');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('with a different error object', () => {
|
|
37
|
+
const value:any = 12345;
|
|
38
|
+
const error = { message: 'Invalid id', path: 'name' };
|
|
39
|
+
|
|
40
|
+
expect(() => checkId(value, error)).toThrow('Invalid id');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('without an error object', () => {
|
|
44
|
+
const value: any = 12345;
|
|
45
|
+
|
|
46
|
+
expect(() => checkId(value)).toThrow();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
});
|
|
50
|
+
describe('generateDbObjectId', () => {
|
|
51
|
+
it('generateDbObjectId with default digits', () => {
|
|
52
|
+
const result = generateDbObjectId();
|
|
53
|
+
expect(typeof result).toBe('string');
|
|
54
|
+
expect(result.length).toBe(24);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('generateDbObjectId with odd digits', () => {
|
|
58
|
+
const result = generateDbObjectId(23);
|
|
59
|
+
expect(typeof result).toBe('string');
|
|
60
|
+
expect(result.length).toBe(23);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('generateDbObjectId with even digits', () => {
|
|
64
|
+
const result = generateDbObjectId(24);
|
|
65
|
+
expect(typeof result).toBe('string');
|
|
66
|
+
expect(result.length).toBe(24);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
})
|
|
70
|
+
});
|
|
71
|
+
|
package/src/mongodb-index.ts
CHANGED
|
@@ -1 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
import * as mongodb from 'mongodb';
|
|
2
|
+
|
|
3
|
+
export { initDb, startDb, stopDb } from './initDb.js';
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* Db utils
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export { checkId } from './check-id.js';
|
|
10
|
+
export { generateDbObjectId } from './generate-db-object-id.js';
|
|
11
|
+
export { generateDbFilterById } from './generate-db-filter-by-id.js';
|
|
12
|
+
export { generateDbMutations } from './generate-db-mutations.js';
|
|
13
|
+
export { buildDbIndexes } from './build-db-indexes.js';
|
|
14
|
+
export { findPreservingIds } from './find-preserving-ids.js';
|
|
15
|
+
export { buildSortOptions } from './build-sort-option.js';
|
|
16
|
+
export { findLocalizedText } from './find-localized-text.js';
|
|
17
|
+
|
|
18
|
+
export { mongodb };
|
package/lib/db/initDb.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { mkdirSync } from 'fs';
|
|
2
|
-
import { MongoClient } from 'mongodb';
|
|
3
|
-
let mongod;
|
|
4
|
-
export const startDb = async () => {
|
|
5
|
-
const { MongoMemoryServer } = await import('mongodb-memory-server');
|
|
6
|
-
try {
|
|
7
|
-
mkdirSync(`${process.cwd()}/.db`);
|
|
8
|
-
}
|
|
9
|
-
catch (e) {
|
|
10
|
-
//
|
|
11
|
-
}
|
|
12
|
-
mongod = await MongoMemoryServer.create({
|
|
13
|
-
instance: {
|
|
14
|
-
dbPath: `${process.cwd()}/.db`,
|
|
15
|
-
storageEngine: 'wiredTiger',
|
|
16
|
-
port: parseInt(process.env.PORT, 10) + 1,
|
|
17
|
-
},
|
|
18
|
-
});
|
|
19
|
-
return `${mongod.getUri()}unchained`;
|
|
20
|
-
};
|
|
21
|
-
export const stopDb = async () => {
|
|
22
|
-
await mongod.stop();
|
|
23
|
-
};
|
|
24
|
-
const initDbNative = async () => {
|
|
25
|
-
const url = process.env.MONGO_URL || (await startDb());
|
|
26
|
-
const client = new MongoClient(url);
|
|
27
|
-
await client.connect();
|
|
28
|
-
const db = client.db();
|
|
29
|
-
return db;
|
|
30
|
-
};
|
|
31
|
-
// eslint-disable-next-line
|
|
32
|
-
// @ts-ignore
|
|
33
|
-
const isMeteor = typeof Meteor === 'object';
|
|
34
|
-
if (isMeteor) {
|
|
35
|
-
const { NpmModuleMongodb } = require('meteor/npm-mongo'); // eslint-disable-line
|
|
36
|
-
const originalFn = NpmModuleMongodb.Collection.prototype.updateOne;
|
|
37
|
-
NpmModuleMongodb.Collection.prototype.updateOne = async function updateOne(...rest) {
|
|
38
|
-
const result = await originalFn.bind(this)(...rest);
|
|
39
|
-
if (!result)
|
|
40
|
-
return result;
|
|
41
|
-
return {
|
|
42
|
-
result: { nModified: result.modifiedCount },
|
|
43
|
-
...result,
|
|
44
|
-
};
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
const initDbMeteor = async () => {
|
|
48
|
-
const { MongoInternals } = require('meteor/mongo'); // eslint-disable-line
|
|
49
|
-
const db = MongoInternals.defaultRemoteCollectionDriver().mongo.db; // eslint-disable-line
|
|
50
|
-
return db;
|
|
51
|
-
};
|
|
52
|
-
const initDb = isMeteor ? initDbMeteor : initDbNative;
|
|
53
|
-
export { initDb };
|
|
54
|
-
//# sourceMappingURL=initDb.js.map
|
package/lib/db/initDb.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"initDb.js","sourceRoot":"","sources":["../../src/db/initDb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,EAAM,WAAW,EAAE,MAAM,SAAS,CAAC;AAE1C,IAAI,MAAM,CAAC;AAEX,MAAM,CAAC,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;IAChC,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;IAEpE,IAAI,CAAC;QACH,SAAS,CAAC,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,EAAE;IACJ,CAAC;IACD,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC;QACtC,QAAQ,EAAE;YACR,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM;YAC9B,aAAa,EAAE,YAAY;YAC3B,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC;SACzC;KACF,CAAC,CAAC;IACH,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;AACvC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;IAC/B,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,KAAK,IAAiB,EAAE;IAC3C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;IACvB,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,EAAE,CAAC;IACvB,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAEF,2BAA2B;AAC3B,aAAa;AACb,MAAM,QAAQ,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC;AAE5C,IAAI,QAAQ,EAAE,CAAC;IACb,MAAM,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,sBAAsB;IAChF,MAAM,UAAU,GAAG,gBAAgB,CAAC,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC;IACnE,gBAAgB,CAAC,UAAU,CAAC,SAAS,CAAC,SAAS,GAAG,KAAK,UAAU,SAAS,CAAC,GAAG,IAAI;QAChF,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QACpD,IAAI,CAAC,MAAM;YAAE,OAAO,MAAM,CAAC;QAC3B,OAAO;YACL,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,aAAa,EAAE;YAC3C,GAAG,MAAM;SACV,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,YAAY,GAAG,KAAK,IAAiB,EAAE;IAC3C,MAAM,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,sBAAsB;IAC1E,MAAM,EAAE,GAAG,cAAc,CAAC,6BAA6B,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,sBAAsB;IAC1F,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAEF,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC;AAEtD,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
package/src/db/initDb.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { mkdirSync } from 'fs';
|
|
2
|
-
import { Db, MongoClient } from 'mongodb';
|
|
3
|
-
|
|
4
|
-
let mongod;
|
|
5
|
-
|
|
6
|
-
export const startDb = async () => {
|
|
7
|
-
const { MongoMemoryServer } = await import('mongodb-memory-server');
|
|
8
|
-
|
|
9
|
-
try {
|
|
10
|
-
mkdirSync(`${process.cwd()}/.db`);
|
|
11
|
-
} catch (e) {
|
|
12
|
-
//
|
|
13
|
-
}
|
|
14
|
-
mongod = await MongoMemoryServer.create({
|
|
15
|
-
instance: {
|
|
16
|
-
dbPath: `${process.cwd()}/.db`,
|
|
17
|
-
storageEngine: 'wiredTiger',
|
|
18
|
-
port: parseInt(process.env.PORT, 10) + 1,
|
|
19
|
-
},
|
|
20
|
-
});
|
|
21
|
-
return `${mongod.getUri()}unchained`;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export const stopDb = async () => {
|
|
25
|
-
await mongod.stop();
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const initDbNative = async (): Promise<Db> => {
|
|
29
|
-
const url = process.env.MONGO_URL || (await startDb());
|
|
30
|
-
const client = new MongoClient(url);
|
|
31
|
-
await client.connect();
|
|
32
|
-
const db = client.db();
|
|
33
|
-
return db;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
// eslint-disable-next-line
|
|
37
|
-
// @ts-ignore
|
|
38
|
-
const isMeteor = typeof Meteor === 'object';
|
|
39
|
-
|
|
40
|
-
if (isMeteor) {
|
|
41
|
-
const { NpmModuleMongodb } = require('meteor/npm-mongo'); // eslint-disable-line
|
|
42
|
-
const originalFn = NpmModuleMongodb.Collection.prototype.updateOne;
|
|
43
|
-
NpmModuleMongodb.Collection.prototype.updateOne = async function updateOne(...rest) {
|
|
44
|
-
const result = await originalFn.bind(this)(...rest);
|
|
45
|
-
if (!result) return result;
|
|
46
|
-
return {
|
|
47
|
-
result: { nModified: result.modifiedCount },
|
|
48
|
-
...result,
|
|
49
|
-
};
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const initDbMeteor = async (): Promise<Db> => {
|
|
54
|
-
const { MongoInternals } = require('meteor/mongo'); // eslint-disable-line
|
|
55
|
-
const db = MongoInternals.defaultRemoteCollectionDriver().mongo.db; // eslint-disable-line
|
|
56
|
-
return db;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const initDb = isMeteor ? initDbMeteor : initDbNative;
|
|
60
|
-
|
|
61
|
-
export { initDb };
|
|
File without changes
|