@aeriajs/core 0.0.277 → 0.0.279
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/__scripts__/postinstall.js +2 -37
- package/dist/accessControl.js +14 -18
- package/dist/assets.js +25 -31
- package/dist/collection/cascadingRemove.js +14 -19
- package/dist/collection/define.js +5 -10
- package/dist/collection/description.js +2 -7
- package/dist/collection/index.js +8 -24
- package/dist/collection/makePagination.js +5 -9
- package/dist/collection/normalizeProjection.js +1 -5
- package/dist/collection/preload.js +13 -18
- package/dist/collection/reference.js +19 -26
- package/dist/collection/traverseDocument.js +90 -127
- package/dist/context.js +16 -53
- package/dist/database.js +12 -52
- package/dist/endpoints.js +11 -48
- package/dist/functions/count.js +11 -15
- package/dist/functions/get.js +20 -24
- package/dist/functions/getAll.js +8 -12
- package/dist/functions/index.js +9 -27
- package/dist/functions/insert.js +19 -23
- package/dist/functions/remove.js +15 -19
- package/dist/functions/removeAll.js +11 -15
- package/dist/functions/removeFile.js +7 -11
- package/dist/functions/unpaginatedGetAll.js +15 -19
- package/dist/functions/upload.js +19 -57
- package/dist/index.js +11 -51
- package/dist/presets/add.js +1 -4
- package/dist/presets/crud.js +1 -4
- package/dist/presets/duplicate.js +1 -4
- package/dist/presets/index.js +17 -20
- package/dist/presets/owned.js +1 -4
- package/dist/presets/remove.js +1 -4
- package/dist/presets/removeAll.js +1 -4
- package/dist/presets/timestamped.js +1 -4
- package/dist/presets/view.js +1 -4
- package/dist/token.js +7 -15
- package/package.json +12 -17
- package/dist/__scripts__/postinstall.mjs +0 -50
- package/dist/accessControl.mjs +0 -31
- package/dist/assets.mjs +0 -67
- package/dist/collection/cascadingRemove.mjs +0 -71
- package/dist/collection/define.mjs +0 -13
- package/dist/collection/description.mjs +0 -8
- package/dist/collection/index.mjs +0 -9
- package/dist/collection/makePagination.mjs +0 -20
- package/dist/collection/normalizeProjection.mjs +0 -17
- package/dist/collection/preload.mjs +0 -88
- package/dist/collection/reference.mjs +0 -374
- package/dist/collection/traverseDocument.mjs +0 -454
- package/dist/context.mjs +0 -120
- package/dist/database.mjs +0 -49
- package/dist/endpoints.mjs +0 -52
- package/dist/functions/count.mjs +0 -50
- package/dist/functions/get.mjs +0 -89
- package/dist/functions/getAll.mjs +0 -14
- package/dist/functions/index.mjs +0 -12
- package/dist/functions/insert.mjs +0 -102
- package/dist/functions/remove.mjs +0 -41
- package/dist/functions/removeAll.mjs +0 -40
- package/dist/functions/removeFile.mjs +0 -29
- package/dist/functions/unpaginatedGetAll.mjs +0 -123
- package/dist/functions/upload.mjs +0 -91
- package/dist/index.mjs +0 -14
- package/dist/presets/add.mjs +0 -12
- package/dist/presets/crud.mjs +0 -35
- package/dist/presets/duplicate.mjs +0 -11
- package/dist/presets/index.mjs +0 -19
- package/dist/presets/owned.mjs +0 -9
- package/dist/presets/remove.mjs +0 -11
- package/dist/presets/removeAll.mjs +0 -11
- package/dist/presets/timestamped.mjs +0 -19
- package/dist/presets/view.mjs +0 -14
- package/dist/token.mjs +0 -31
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
import { ObjectId } from "mongodb";
|
|
3
|
-
import { createContext } from "../context.mjs";
|
|
4
|
-
import { getFunction } from "../assets.mjs";
|
|
5
|
-
import { getDatabaseCollection } from "../database.mjs";
|
|
6
|
-
import { getReferences } from "./reference.mjs";
|
|
7
|
-
const internalCascadingRemove = async (target, refMap, context) => {
|
|
8
|
-
for (const refName in refMap) {
|
|
9
|
-
const reference = refMap[refName];
|
|
10
|
-
if (!target[refName]) {
|
|
11
|
-
continue;
|
|
12
|
-
}
|
|
13
|
-
if (reference.referencedCollection) {
|
|
14
|
-
if (reference.isInline || reference.referencedCollection === "file") {
|
|
15
|
-
if (target[refName] instanceof ObjectId || Array.isArray(target[refName])) {
|
|
16
|
-
await preferredRemove(target[refName], reference, context);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
} else if (reference.deepReferences) {
|
|
20
|
-
if (Array.isArray(target[refName])) {
|
|
21
|
-
for (const elem of target[refName]) {
|
|
22
|
-
await internalCascadingRemove(elem, reference.deepReferences, context);
|
|
23
|
-
}
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
await internalCascadingRemove(target[refName], reference.deepReferences, context);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
export const preferredRemove = async (targetId, reference, parentContext) => {
|
|
31
|
-
if (!reference.referencedCollection) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const coll = getDatabaseCollection(reference.referencedCollection);
|
|
35
|
-
const context = await createContext({
|
|
36
|
-
parentContext,
|
|
37
|
-
collectionName: reference.referencedCollection
|
|
38
|
-
});
|
|
39
|
-
if (Array.isArray(targetId)) {
|
|
40
|
-
if (targetId.length === 0) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
const nonNullable = targetId.filter((id) => !!id);
|
|
44
|
-
const { result: removeAll } = await getFunction(reference.referencedCollection, "removeAll");
|
|
45
|
-
if (removeAll) {
|
|
46
|
-
return removeAll({
|
|
47
|
-
filters: nonNullable
|
|
48
|
-
}, context);
|
|
49
|
-
}
|
|
50
|
-
return coll.deleteMany({
|
|
51
|
-
_id: {
|
|
52
|
-
$in: nonNullable
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
const { result: remove } = await getFunction(reference.referencedCollection, "remove");
|
|
57
|
-
if (remove) {
|
|
58
|
-
return remove({
|
|
59
|
-
filters: {
|
|
60
|
-
_id: targetId
|
|
61
|
-
}
|
|
62
|
-
}, context);
|
|
63
|
-
}
|
|
64
|
-
return coll.deleteOne({
|
|
65
|
-
_id: targetId
|
|
66
|
-
});
|
|
67
|
-
};
|
|
68
|
-
export const cascadingRemove = async (target, context) => {
|
|
69
|
-
const refMap = await getReferences(context.description.properties);
|
|
70
|
-
return internalCascadingRemove(target, refMap, context);
|
|
71
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
import { deepMerge, freshItem } from "@aeriajs/common";
|
|
3
|
-
export const defineCollection = (collection) => {
|
|
4
|
-
return Object.assign(
|
|
5
|
-
{
|
|
6
|
-
item: freshItem(collection.description)
|
|
7
|
-
},
|
|
8
|
-
collection
|
|
9
|
-
);
|
|
10
|
-
};
|
|
11
|
-
export const extendCollection = (left, right) => {
|
|
12
|
-
return deepMerge(left, right);
|
|
13
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
export * from "./cascadingRemove.mjs";
|
|
3
|
-
export * from "./define.mjs";
|
|
4
|
-
export * from "./description.mjs";
|
|
5
|
-
export * from "./makePagination.mjs";
|
|
6
|
-
export * from "./normalizeProjection.mjs";
|
|
7
|
-
export * from "./preload.mjs";
|
|
8
|
-
export * from "./reference.mjs";
|
|
9
|
-
export * from "./traverseDocument.mjs";
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
import { throwIfError } from "@aeriajs/common";
|
|
3
|
-
import { count } from "../functions/count.mjs";
|
|
4
|
-
export const makePagination = async (payload, documents, context) => {
|
|
5
|
-
const {
|
|
6
|
-
offset = 0,
|
|
7
|
-
limit = context.config.defaultPaginationLimit
|
|
8
|
-
} = payload;
|
|
9
|
-
const recordsTotal = typeof context.collection.functions.count === "function" ? throwIfError(await context.collection.functions.count({
|
|
10
|
-
filters: payload.filters
|
|
11
|
-
})) : throwIfError(await count({
|
|
12
|
-
filters: payload.filters
|
|
13
|
-
}, context));
|
|
14
|
-
return {
|
|
15
|
-
recordsCount: documents.length,
|
|
16
|
-
recordsTotal,
|
|
17
|
-
offset,
|
|
18
|
-
limit
|
|
19
|
-
};
|
|
20
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
export const normalizeProjection = (properties, description) => {
|
|
3
|
-
const target = Array.from(properties);
|
|
4
|
-
if (target.length === 0) {
|
|
5
|
-
target.push(...Object.keys(description.properties));
|
|
6
|
-
}
|
|
7
|
-
const projection = target.reduce((a, key) => {
|
|
8
|
-
if (key !== "_id" && description.properties[key].hidden) {
|
|
9
|
-
return a;
|
|
10
|
-
}
|
|
11
|
-
return {
|
|
12
|
-
...a,
|
|
13
|
-
[key]: 1
|
|
14
|
-
};
|
|
15
|
-
}, {});
|
|
16
|
-
return Object.keys(projection).length === 0 ? void 0 : projection;
|
|
17
|
-
};
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
import { getReferenceProperty, deepMerge, serialize } from "@aeriajs/common";
|
|
3
|
-
import { getCollectionAsset } from "../assets.mjs";
|
|
4
|
-
import { presets } from "../presets/index.mjs";
|
|
5
|
-
const preloadMemo = {};
|
|
6
|
-
const recurseProperty = async (_property, propName, description) => {
|
|
7
|
-
const property = Object.assign({}, _property);
|
|
8
|
-
if ("items" in property) {
|
|
9
|
-
property.items = await recurseProperty(property.items, propName, description);
|
|
10
|
-
return property;
|
|
11
|
-
}
|
|
12
|
-
if ("properties" in property) {
|
|
13
|
-
return preloadDescription(property, {
|
|
14
|
-
memoize: false,
|
|
15
|
-
timestamps: false
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
if ("getter" in property) {
|
|
19
|
-
return {
|
|
20
|
-
...property,
|
|
21
|
-
readOnly: true
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
const reference = getReferenceProperty(property);
|
|
25
|
-
if (reference) {
|
|
26
|
-
if (!reference.indexes && !reference.inline) {
|
|
27
|
-
const { error, result: referenceDescription } = await getCollectionAsset(reference.$ref, "description");
|
|
28
|
-
if (error) {
|
|
29
|
-
throw new Error(`description of ${reference.$ref} not found`);
|
|
30
|
-
}
|
|
31
|
-
const indexes = reference.indexes = referenceDescription.indexes?.filter((index) => {
|
|
32
|
-
return typeof index === "string";
|
|
33
|
-
});
|
|
34
|
-
if (!indexes) {
|
|
35
|
-
reference.indexes = Object.keys(referenceDescription.properties).slice(0, 1);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return property;
|
|
40
|
-
};
|
|
41
|
-
export const applyPreset = (entry, presetName, parentName) => {
|
|
42
|
-
const preset = presets[presetName];
|
|
43
|
-
const presetObject = Object.assign({}, parentName ? preset[parentName] : preset);
|
|
44
|
-
return deepMerge(entry, presetObject, {
|
|
45
|
-
callback: (_, left) => {
|
|
46
|
-
if (left === null) {
|
|
47
|
-
return left;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
};
|
|
52
|
-
export const preloadDescription = async (originalDescription, options) => {
|
|
53
|
-
const {
|
|
54
|
-
memoize = !!originalDescription.$id,
|
|
55
|
-
timestamps = true
|
|
56
|
-
} = options || {};
|
|
57
|
-
if (memoize && preloadMemo[originalDescription.$id]) {
|
|
58
|
-
const description2 = preloadMemo[originalDescription.$id];
|
|
59
|
-
return options?.serialize ? serialize(description2) : description2;
|
|
60
|
-
}
|
|
61
|
-
const description = Object.assign({}, originalDescription);
|
|
62
|
-
const descriptionPresets = [];
|
|
63
|
-
if (description.presets) {
|
|
64
|
-
descriptionPresets.push(...description.presets);
|
|
65
|
-
}
|
|
66
|
-
if (description.owned) {
|
|
67
|
-
descriptionPresets.push("owned");
|
|
68
|
-
}
|
|
69
|
-
if (description.timestamps !== false && timestamps !== false) {
|
|
70
|
-
descriptionPresets.push("timestamped");
|
|
71
|
-
}
|
|
72
|
-
if (descriptionPresets.length > 0) {
|
|
73
|
-
const merge = descriptionPresets.reduce(
|
|
74
|
-
(a, presetName) => applyPreset(a, presetName),
|
|
75
|
-
description
|
|
76
|
-
);
|
|
77
|
-
Object.assign(description, merge);
|
|
78
|
-
}
|
|
79
|
-
if (description.properties) {
|
|
80
|
-
for (const [propName, property] of Object.entries(description.properties)) {
|
|
81
|
-
description.properties[propName] = await recurseProperty(property, propName, description);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
if (memoize) {
|
|
85
|
-
preloadMemo[originalDescription.$id] = description;
|
|
86
|
-
}
|
|
87
|
-
return options?.serialize ? serialize(description) : description;
|
|
88
|
-
};
|
|
@@ -1,374 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
import { throwIfError, getReferenceProperty } from "@aeriajs/common";
|
|
3
|
-
import { getCollectionAsset } from "../assets.mjs";
|
|
4
|
-
const getTempName = (path) => {
|
|
5
|
-
return `_${path.map(([segment]) => segment).join("_")}`;
|
|
6
|
-
};
|
|
7
|
-
const referenceMemo = {};
|
|
8
|
-
const lookupMemo = {};
|
|
9
|
-
export const getReferences = async (properties, options = {}) => {
|
|
10
|
-
const {
|
|
11
|
-
depth = 0,
|
|
12
|
-
maxDepth = 3,
|
|
13
|
-
memoize,
|
|
14
|
-
populate,
|
|
15
|
-
isArrayOrArrayElement
|
|
16
|
-
} = options;
|
|
17
|
-
if (memoize) {
|
|
18
|
-
if (referenceMemo[memoize]) {
|
|
19
|
-
return referenceMemo[memoize];
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
const refMap = {};
|
|
23
|
-
for (const [propName, property] of Object.entries(properties)) {
|
|
24
|
-
const reference = {};
|
|
25
|
-
const refProperty = getReferenceProperty(property);
|
|
26
|
-
if (depth === maxDepth || populate && !populate.includes(propName)) {
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
if (refProperty) {
|
|
30
|
-
const description = throwIfError(await getCollectionAsset(refProperty.$ref, "description"));
|
|
31
|
-
if (refProperty.inline || refProperty.populate) {
|
|
32
|
-
if (refProperty.populate && refProperty.populate.length === 0) {
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
const deepReferences = await getReferences(description.properties, {
|
|
36
|
-
depth: depth + 1,
|
|
37
|
-
maxDepth: refProperty.populateDepth || maxDepth,
|
|
38
|
-
memoize: `${memoize}.${propName}`,
|
|
39
|
-
populate: refProperty.populate ? Array.from(refProperty.populate) : void 0,
|
|
40
|
-
isArrayOrArrayElement: "items" in property
|
|
41
|
-
});
|
|
42
|
-
if (Object.keys(deepReferences).length > 0) {
|
|
43
|
-
reference.deepReferences = deepReferences;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
const { indexes = description.indexes || [] } = refProperty;
|
|
47
|
-
reference.populate = (refProperty.populate || []).concat(indexes.filter((index) => typeof index === "string"));
|
|
48
|
-
} else {
|
|
49
|
-
const entrypoint = "items" in property ? property.items : property;
|
|
50
|
-
if ("properties" in entrypoint) {
|
|
51
|
-
const deepReferences = await getReferences(entrypoint.properties, {
|
|
52
|
-
memoize: `${memoize}.${propName}`
|
|
53
|
-
});
|
|
54
|
-
if (Object.keys(deepReferences).length > 0) {
|
|
55
|
-
reference.deepReferences ??= {};
|
|
56
|
-
reference.deepReferences = deepReferences;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
if (!refProperty && !reference.deepReferences) {
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
if ("items" in property) {
|
|
64
|
-
reference.isArray = true;
|
|
65
|
-
}
|
|
66
|
-
if ("items" in property || isArrayOrArrayElement) {
|
|
67
|
-
reference.isArrayOrArrayElement = true;
|
|
68
|
-
}
|
|
69
|
-
if (depth > 0) {
|
|
70
|
-
reference.isRecursive = true;
|
|
71
|
-
}
|
|
72
|
-
if (refProperty) {
|
|
73
|
-
if (refProperty.$ref) {
|
|
74
|
-
reference.referencedCollection = refProperty.$ref;
|
|
75
|
-
}
|
|
76
|
-
if (refProperty.inline) {
|
|
77
|
-
reference.isInline = true;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
refMap[propName] = reference;
|
|
81
|
-
}
|
|
82
|
-
if (memoize) {
|
|
83
|
-
referenceMemo[memoize] = refMap;
|
|
84
|
-
}
|
|
85
|
-
return refMap;
|
|
86
|
-
};
|
|
87
|
-
export const recurseSetStage = (reference, path, parentElem, options = {
|
|
88
|
-
noCond: false
|
|
89
|
-
}) => {
|
|
90
|
-
const [refName, isRef] = path.at(-1);
|
|
91
|
-
const shouldUseArrayIndex = reference.isRecursive && !(reference.isArrayOrArrayElement && reference.isArray === false);
|
|
92
|
-
let indexOfArray;
|
|
93
|
-
if (shouldUseArrayIndex) {
|
|
94
|
-
if (isRef) {
|
|
95
|
-
indexOfArray = {
|
|
96
|
-
$indexOfArray: [
|
|
97
|
-
`$${getTempName(path)}._id`,
|
|
98
|
-
{
|
|
99
|
-
$arrayElemAt: [
|
|
100
|
-
`$${getTempName(path.slice(0, -1))}.${refName}`,
|
|
101
|
-
{
|
|
102
|
-
$indexOfArray: [
|
|
103
|
-
`$${getTempName(path.slice(0, -1))}._id`,
|
|
104
|
-
parentElem
|
|
105
|
-
]
|
|
106
|
-
}
|
|
107
|
-
]
|
|
108
|
-
}
|
|
109
|
-
]
|
|
110
|
-
};
|
|
111
|
-
} else {
|
|
112
|
-
indexOfArray = {
|
|
113
|
-
$indexOfArray: [
|
|
114
|
-
`$${getTempName(path.slice(0, -1))}._id`,
|
|
115
|
-
parentElem
|
|
116
|
-
]
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
} else {
|
|
120
|
-
indexOfArray = {
|
|
121
|
-
$indexOfArray: [
|
|
122
|
-
`$${getTempName(path)}._id`,
|
|
123
|
-
parentElem
|
|
124
|
-
]
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
if (reference.isArray) {
|
|
128
|
-
const newElemName = `${refName}__elem`;
|
|
129
|
-
let mapIn;
|
|
130
|
-
if (reference.referencedCollection) {
|
|
131
|
-
mapIn = recurseSetStage({
|
|
132
|
-
...reference,
|
|
133
|
-
isArray: false
|
|
134
|
-
}, path, `$$${newElemName}`);
|
|
135
|
-
} else {
|
|
136
|
-
mapIn = {
|
|
137
|
-
$mergeObjects: [
|
|
138
|
-
`$$${newElemName}`,
|
|
139
|
-
recurseSetStage({
|
|
140
|
-
...reference,
|
|
141
|
-
isArray: false
|
|
142
|
-
}, path, `$$${newElemName}`)
|
|
143
|
-
]
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
let mapInput = parentElem;
|
|
147
|
-
if (reference.isRecursive) {
|
|
148
|
-
if (reference.isArrayOrArrayElement) {
|
|
149
|
-
mapInput = {
|
|
150
|
-
$arrayElemAt: [
|
|
151
|
-
`$${getTempName(path.slice(0, -1))}.${refName}`,
|
|
152
|
-
{
|
|
153
|
-
$indexOfArray: [
|
|
154
|
-
`$${getTempName(path.slice(0, -1))}._id`,
|
|
155
|
-
parentElem
|
|
156
|
-
]
|
|
157
|
-
}
|
|
158
|
-
]
|
|
159
|
-
};
|
|
160
|
-
} else {
|
|
161
|
-
mapInput = {
|
|
162
|
-
$arrayElemAt: [
|
|
163
|
-
`$${getTempName(path.slice(0, -1))}.${refName}`,
|
|
164
|
-
indexOfArray
|
|
165
|
-
]
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
return {
|
|
170
|
-
$filter: {
|
|
171
|
-
input: {
|
|
172
|
-
$map: {
|
|
173
|
-
input: mapInput,
|
|
174
|
-
as: newElemName,
|
|
175
|
-
in: mapIn
|
|
176
|
-
}
|
|
177
|
-
},
|
|
178
|
-
as: "elem",
|
|
179
|
-
cond: {
|
|
180
|
-
$ne: [
|
|
181
|
-
"$$elem",
|
|
182
|
-
null
|
|
183
|
-
]
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
if (reference.deepReferences) {
|
|
189
|
-
const stages = {};
|
|
190
|
-
for (const [subRefName, subReference] of Object.entries(reference.deepReferences)) {
|
|
191
|
-
let newElem;
|
|
192
|
-
if (shouldUseArrayIndex) {
|
|
193
|
-
if (isRef) {
|
|
194
|
-
newElem = {
|
|
195
|
-
$arrayElemAt: [
|
|
196
|
-
`$${getTempName(path.slice(0, -1))}.${refName}`,
|
|
197
|
-
{
|
|
198
|
-
$indexOfArray: [
|
|
199
|
-
`$${getTempName(path.slice(0, -1))}._id`,
|
|
200
|
-
parentElem
|
|
201
|
-
]
|
|
202
|
-
}
|
|
203
|
-
]
|
|
204
|
-
};
|
|
205
|
-
} else {
|
|
206
|
-
newElem = {
|
|
207
|
-
$arrayElemAt: [
|
|
208
|
-
`$${getTempName(path.slice(0, -1))}.${refName}.${subRefName}`,
|
|
209
|
-
indexOfArray
|
|
210
|
-
]
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
} else {
|
|
214
|
-
newElem = reference.referencedCollection ? parentElem : `${parentElem}.${subRefName}`;
|
|
215
|
-
}
|
|
216
|
-
const result = recurseSetStage(subReference, path.concat([
|
|
217
|
-
[
|
|
218
|
-
subRefName,
|
|
219
|
-
"referencedCollection" in subReference
|
|
220
|
-
]
|
|
221
|
-
]), newElem);
|
|
222
|
-
stages[subRefName] = result;
|
|
223
|
-
}
|
|
224
|
-
if (reference.referencedCollection) {
|
|
225
|
-
return {
|
|
226
|
-
$cond: [
|
|
227
|
-
{
|
|
228
|
-
$ne: [
|
|
229
|
-
indexOfArray,
|
|
230
|
-
-1
|
|
231
|
-
]
|
|
232
|
-
},
|
|
233
|
-
{
|
|
234
|
-
$mergeObjects: [
|
|
235
|
-
recurseSetStage({
|
|
236
|
-
...reference,
|
|
237
|
-
deepReferences: void 0
|
|
238
|
-
}, path, parentElem, {
|
|
239
|
-
noCond: true
|
|
240
|
-
}),
|
|
241
|
-
stages
|
|
242
|
-
]
|
|
243
|
-
},
|
|
244
|
-
null
|
|
245
|
-
]
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
return stages;
|
|
249
|
-
}
|
|
250
|
-
const arrayElemAt = {
|
|
251
|
-
$arrayElemAt: [
|
|
252
|
-
`$${getTempName(path)}`,
|
|
253
|
-
indexOfArray
|
|
254
|
-
]
|
|
255
|
-
};
|
|
256
|
-
if (options.noCond) {
|
|
257
|
-
return arrayElemAt;
|
|
258
|
-
}
|
|
259
|
-
return {
|
|
260
|
-
$cond: [
|
|
261
|
-
{
|
|
262
|
-
$ne: [
|
|
263
|
-
indexOfArray,
|
|
264
|
-
-1
|
|
265
|
-
]
|
|
266
|
-
},
|
|
267
|
-
arrayElemAt,
|
|
268
|
-
null
|
|
269
|
-
]
|
|
270
|
-
};
|
|
271
|
-
};
|
|
272
|
-
export const buildLookupPipeline = (refMap, options = {}) => {
|
|
273
|
-
const {
|
|
274
|
-
rootPipeline = [],
|
|
275
|
-
path = [],
|
|
276
|
-
tempNames = [],
|
|
277
|
-
project,
|
|
278
|
-
memoize: memoizeId
|
|
279
|
-
} = options;
|
|
280
|
-
const memoize = project ? `${memoizeId}-${project.sort().join("-")}` : memoizeId;
|
|
281
|
-
if (memoize) {
|
|
282
|
-
if (lookupMemo[memoize]) {
|
|
283
|
-
return lookupMemo[memoize];
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
const pipeline = [];
|
|
287
|
-
const setProperties = {};
|
|
288
|
-
for (const [refName, reference] of Object.entries(refMap)) {
|
|
289
|
-
if (project) {
|
|
290
|
-
if (!project.includes(refName)) {
|
|
291
|
-
continue;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
const newPath = path.concat([
|
|
295
|
-
[
|
|
296
|
-
refName,
|
|
297
|
-
"referencedCollection" in reference
|
|
298
|
-
]
|
|
299
|
-
]);
|
|
300
|
-
if (reference.deepReferences) {
|
|
301
|
-
buildLookupPipeline(reference.deepReferences, {
|
|
302
|
-
rootPipeline,
|
|
303
|
-
tempNames,
|
|
304
|
-
path: newPath
|
|
305
|
-
});
|
|
306
|
-
const result = recurseSetStage(reference, newPath, `$${refName}`);
|
|
307
|
-
setProperties[refName] = result;
|
|
308
|
-
}
|
|
309
|
-
if (reference.referencedCollection) {
|
|
310
|
-
const tempName = getTempName(newPath);
|
|
311
|
-
const lookupPipeline = [];
|
|
312
|
-
tempNames.unshift(tempName);
|
|
313
|
-
if (reference.populate && reference.populate.length > 0 && !reference.isInline) {
|
|
314
|
-
lookupPipeline.push({
|
|
315
|
-
$project: Object.fromEntries(reference.populate.map((index) => [
|
|
316
|
-
index,
|
|
317
|
-
1
|
|
318
|
-
]))
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
let localField;
|
|
322
|
-
if (reference.isRecursive) {
|
|
323
|
-
localField = `${getTempName(path)}.${refName}`;
|
|
324
|
-
} else {
|
|
325
|
-
let separator = "_";
|
|
326
|
-
localField = path[0] && path[0][1] ? "_" : "";
|
|
327
|
-
for (let i = 0; i < newPath.length; i++) {
|
|
328
|
-
localField += newPath[i][0];
|
|
329
|
-
if (newPath[i + 1]) {
|
|
330
|
-
if (!newPath[i][1] || !newPath[i + 1][1]) {
|
|
331
|
-
separator = ".";
|
|
332
|
-
}
|
|
333
|
-
localField += separator;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
rootPipeline.unshift({
|
|
338
|
-
$lookup: {
|
|
339
|
-
from: reference.referencedCollection,
|
|
340
|
-
foreignField: "_id",
|
|
341
|
-
localField,
|
|
342
|
-
as: tempName,
|
|
343
|
-
pipeline: lookupPipeline
|
|
344
|
-
}
|
|
345
|
-
});
|
|
346
|
-
if (!reference.deepReferences) {
|
|
347
|
-
const result = recurseSetStage(reference, newPath, `$${refName}`);
|
|
348
|
-
setProperties[refName] = result;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
if (path.length === 0) {
|
|
353
|
-
if (Object.keys(setProperties).length > 0) {
|
|
354
|
-
pipeline.push({
|
|
355
|
-
$set: setProperties
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
if (tempNames.length > 0) {
|
|
359
|
-
pipeline.push({
|
|
360
|
-
$unset: tempNames
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
const finalPipeline = rootPipeline.concat(pipeline);
|
|
364
|
-
if (memoize) {
|
|
365
|
-
lookupMemo[memoize] = finalPipeline;
|
|
366
|
-
}
|
|
367
|
-
return finalPipeline;
|
|
368
|
-
}
|
|
369
|
-
return pipeline;
|
|
370
|
-
};
|
|
371
|
-
export const getLookupPipeline = async (description, options) => {
|
|
372
|
-
const refMap = await getReferences(description.properties);
|
|
373
|
-
return buildLookupPipeline(refMap, options);
|
|
374
|
-
};
|