@boostercloud/framework-provider-azure 2.10.1 → 2.11.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.
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { CosmosClient } from '@azure/cosmos';
|
|
2
|
-
import { BoosterConfig, FilterFor, ReadModelListResult, SortFor } from '@boostercloud/framework-types';
|
|
3
|
-
export declare function search<TResult>(cosmosDb: CosmosClient, config: BoosterConfig, containerName: string, filters: FilterFor<unknown>, limit?: number | undefined, afterCursor?: Record<string, string> | undefined, paginatedVersion?: boolean, order?: SortFor<unknown>, projections?: string): Promise<Array<TResult> | ReadModelListResult<TResult>>;
|
|
2
|
+
import { BoosterConfig, FilterFor, ProjectionFor, ReadModelListResult, SortFor } from '@boostercloud/framework-types';
|
|
3
|
+
export declare function search<TResult>(cosmosDb: CosmosClient, config: BoosterConfig, containerName: string, filters: FilterFor<unknown>, limit?: number | undefined, afterCursor?: Record<string, string> | undefined, paginatedVersion?: boolean, order?: SortFor<unknown>, projections?: ProjectionFor<unknown> | string): Promise<Array<TResult> | ReadModelListResult<TResult>>;
|
|
@@ -6,7 +6,8 @@ const framework_common_helpers_1 = require("@boostercloud/framework-common-helpe
|
|
|
6
6
|
async function search(cosmosDb, config, containerName, filters, limit, afterCursor, paginatedVersion = false, order, projections = '*') {
|
|
7
7
|
const logger = (0, framework_common_helpers_1.getLogger)(config, 'query-helper#search');
|
|
8
8
|
const filterExpression = buildFilterExpression(filters);
|
|
9
|
-
const
|
|
9
|
+
const projectionsExpression = buildProjections(projections);
|
|
10
|
+
const queryDefinition = `SELECT ${projectionsExpression} FROM c ${filterExpression !== '' ? `WHERE ${filterExpression}` : filterExpression}`;
|
|
10
11
|
const queryWithOrder = queryDefinition + buildOrderExpression(order);
|
|
11
12
|
let finalQuery = queryWithOrder;
|
|
12
13
|
if (paginatedVersion && limit) {
|
|
@@ -22,11 +23,12 @@ async function search(cosmosDb, config, containerName, filters, limit, afterCurs
|
|
|
22
23
|
parameters: buildExpressionAttributeValues(filters),
|
|
23
24
|
};
|
|
24
25
|
logger.debug('Running search with the following params: \n', querySpec);
|
|
25
|
-
|
|
26
|
+
let { resources } = await cosmosDb
|
|
26
27
|
.database(config.resourceNames.applicationStack)
|
|
27
28
|
.container(containerName)
|
|
28
29
|
.items.query(querySpec)
|
|
29
30
|
.fetchAll();
|
|
31
|
+
resources = nestProperties(resources);
|
|
30
32
|
if (paginatedVersion) {
|
|
31
33
|
return {
|
|
32
34
|
items: resources !== null && resources !== void 0 ? resources : [],
|
|
@@ -178,3 +180,148 @@ function toLocalSortFor(sortBy, parentKey = '', sortedList = []) {
|
|
|
178
180
|
});
|
|
179
181
|
return sortedList;
|
|
180
182
|
}
|
|
183
|
+
function buildProjections(projections = '*') {
|
|
184
|
+
if (typeof projections !== 'object') {
|
|
185
|
+
return projections;
|
|
186
|
+
}
|
|
187
|
+
// Group fields by the root property
|
|
188
|
+
const groupedFields = {};
|
|
189
|
+
Object.values(projections).forEach((field) => {
|
|
190
|
+
const root = field.split('.')[0];
|
|
191
|
+
if (!groupedFields[root]) {
|
|
192
|
+
groupedFields[root] = [];
|
|
193
|
+
}
|
|
194
|
+
groupedFields[root].push(field);
|
|
195
|
+
});
|
|
196
|
+
return Object.keys(groupedFields)
|
|
197
|
+
.map((root) => {
|
|
198
|
+
const fields = groupedFields[root];
|
|
199
|
+
if (root.endsWith('[]')) {
|
|
200
|
+
const arrayRoot = root.slice(0, -2);
|
|
201
|
+
const subFields = fields.map((f) => f.replace(`${root}.`, 'item.')).join(', ');
|
|
202
|
+
return `ARRAY(SELECT ${subFields} FROM item IN c.${arrayRoot}) AS ${arrayRoot}`;
|
|
203
|
+
}
|
|
204
|
+
else if (fields.length === 1 && !fields[0].includes('.')) {
|
|
205
|
+
// Simple field
|
|
206
|
+
return `c.${fields[0]}`;
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
// Nested object fields
|
|
210
|
+
const nestedFields = {};
|
|
211
|
+
fields.forEach((f) => {
|
|
212
|
+
const parts = f.split('.').slice(1);
|
|
213
|
+
if (parts.length > 0) {
|
|
214
|
+
const nestedRoot = parts[0];
|
|
215
|
+
if (!nestedFields[nestedRoot]) {
|
|
216
|
+
nestedFields[nestedRoot] = [];
|
|
217
|
+
}
|
|
218
|
+
nestedFields[nestedRoot].push(parts.join('.'));
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
return Object.keys(nestedFields)
|
|
222
|
+
.map((nestedRoot) => {
|
|
223
|
+
const subFields = nestedFields[nestedRoot].map((f) => `c.${root}.${f} AS "${root}.${f}"`).join(', ');
|
|
224
|
+
if (nestedRoot.endsWith('[]')) {
|
|
225
|
+
const arrayNestedRoot = nestedRoot.slice(0, -2);
|
|
226
|
+
const subArrayFields = nestedFields[nestedRoot]
|
|
227
|
+
.map((f) => `item.${f.split('.').slice(1).join('.')}`)
|
|
228
|
+
.join(', ');
|
|
229
|
+
return `ARRAY(SELECT ${subArrayFields} FROM item IN c.${root}.${arrayNestedRoot}) AS "${root}.${arrayNestedRoot}"`;
|
|
230
|
+
}
|
|
231
|
+
return subFields;
|
|
232
|
+
})
|
|
233
|
+
.join(', ');
|
|
234
|
+
}
|
|
235
|
+
})
|
|
236
|
+
.join(', ');
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Transforms the flat properties returned by Cosmos DB into a nested structure. For example, the following object:
|
|
240
|
+
*
|
|
241
|
+
* ```json
|
|
242
|
+
* {
|
|
243
|
+
* "foo.bar": "baz",
|
|
244
|
+
* "items": [{"qux.quux": "corge"}]
|
|
245
|
+
* }
|
|
246
|
+
* ```
|
|
247
|
+
*
|
|
248
|
+
* is transformed to this:
|
|
249
|
+
*
|
|
250
|
+
* ```json
|
|
251
|
+
* {
|
|
252
|
+
* "foo": {
|
|
253
|
+
* "bar": "baz"
|
|
254
|
+
* },
|
|
255
|
+
* "items": [
|
|
256
|
+
* {
|
|
257
|
+
* "qux": {
|
|
258
|
+
* "quux": "corge"
|
|
259
|
+
* }
|
|
260
|
+
* }
|
|
261
|
+
* ]
|
|
262
|
+
* }
|
|
263
|
+
* ```
|
|
264
|
+
*
|
|
265
|
+
* @param {any} obj - The object to be nested.
|
|
266
|
+
* @returns {any} - The nested object.
|
|
267
|
+
*/
|
|
268
|
+
function nestProperties(obj) {
|
|
269
|
+
const result = {};
|
|
270
|
+
/**
|
|
271
|
+
* Sets a nested property on an object.
|
|
272
|
+
* @param {any} obj - The object on which to set the property.
|
|
273
|
+
* @param {string[]} path - The path to the property.
|
|
274
|
+
* @param {any} value - The value to set.
|
|
275
|
+
*/
|
|
276
|
+
function setNestedProperty(obj, path, value) {
|
|
277
|
+
let current = obj;
|
|
278
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
279
|
+
if (!current[path[i]]) {
|
|
280
|
+
current[path[i]] = {};
|
|
281
|
+
}
|
|
282
|
+
current = current[path[i]];
|
|
283
|
+
}
|
|
284
|
+
current[path[path.length - 1]] = value;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Processes an object, nesting its properties.
|
|
288
|
+
* @param {any} input - The object to process.
|
|
289
|
+
* @param {any} output - The object to output.
|
|
290
|
+
*/
|
|
291
|
+
function processObject(input, output) {
|
|
292
|
+
for (const key in input) {
|
|
293
|
+
if (Object.prototype.hasOwnProperty.call(input, key)) {
|
|
294
|
+
const value = input[key];
|
|
295
|
+
const keys = key.split('.');
|
|
296
|
+
setNestedProperty(output, keys, value);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Processes an array, nesting its properties.
|
|
302
|
+
* @param {any[]} arr - The array to process.
|
|
303
|
+
* @returns {any[]} - The processed array.
|
|
304
|
+
*/
|
|
305
|
+
function processArray(arr) {
|
|
306
|
+
return arr.map((item) => {
|
|
307
|
+
if (Array.isArray(item)) {
|
|
308
|
+
return processArray(item);
|
|
309
|
+
}
|
|
310
|
+
else if (item !== null && typeof item === 'object') {
|
|
311
|
+
const nestedItem = {};
|
|
312
|
+
processObject(item, nestedItem);
|
|
313
|
+
return nestedItem;
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
return item;
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
if (Array.isArray(obj)) {
|
|
321
|
+
return processArray(obj);
|
|
322
|
+
}
|
|
323
|
+
else if (obj !== null && typeof obj === 'object') {
|
|
324
|
+
processObject(obj, result);
|
|
325
|
+
}
|
|
326
|
+
return result;
|
|
327
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { CosmosClient } from '@azure/cosmos';
|
|
2
|
-
import { BoosterConfig, FilterFor, ReadModelListResult, SortFor } from '@boostercloud/framework-types';
|
|
3
|
-
export declare function searchReadModel(cosmosDb: CosmosClient, config: BoosterConfig, readModelName: string, filters: FilterFor<unknown>, sortBy?: SortFor<unknown>, limit?: number, afterCursor?: Record<string, string> | undefined, paginatedVersion?: boolean): Promise<Array<any> | ReadModelListResult<any>>;
|
|
2
|
+
import { BoosterConfig, FilterFor, ProjectionFor, ReadModelListResult, SortFor } from '@boostercloud/framework-types';
|
|
3
|
+
export declare function searchReadModel(cosmosDb: CosmosClient, config: BoosterConfig, readModelName: string, filters: FilterFor<unknown>, sortBy?: SortFor<unknown>, limit?: number, afterCursor?: Record<string, string> | undefined, paginatedVersion?: boolean, select?: ProjectionFor<unknown>): Promise<Array<any> | ReadModelListResult<any>>;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.searchReadModel = void 0;
|
|
4
4
|
const queryHelper = require("../helpers/query-helper");
|
|
5
|
-
async function searchReadModel(cosmosDb, config, readModelName, filters, sortBy, limit, afterCursor, paginatedVersion = false) {
|
|
6
|
-
return await queryHelper.search(cosmosDb, config, config.resourceNames.forReadModel(readModelName), filters, limit, afterCursor, paginatedVersion, sortBy);
|
|
5
|
+
async function searchReadModel(cosmosDb, config, readModelName, filters, sortBy, limit, afterCursor, paginatedVersion = false, select) {
|
|
6
|
+
return await queryHelper.search(cosmosDb, config, config.resourceNames.forReadModel(readModelName), filters, limit, afterCursor, paginatedVersion, sortBy, select);
|
|
7
7
|
}
|
|
8
8
|
exports.searchReadModel = searchReadModel;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boostercloud/framework-provider-azure",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"description": "Handle Booster's integration with Azure",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework-provider-azure"
|
|
@@ -27,14 +27,14 @@
|
|
|
27
27
|
"@azure/functions": "^1.2.2",
|
|
28
28
|
"@azure/identity": "~2.1.0",
|
|
29
29
|
"@azure/event-hubs": "5.11.1",
|
|
30
|
-
"@boostercloud/framework-common-helpers": "^2.
|
|
31
|
-
"@boostercloud/framework-types": "^2.
|
|
30
|
+
"@boostercloud/framework-common-helpers": "^2.11.0",
|
|
31
|
+
"@boostercloud/framework-types": "^2.11.0",
|
|
32
32
|
"tslib": "^2.4.0",
|
|
33
33
|
"@effect-ts/core": "^0.60.4",
|
|
34
34
|
"@azure/web-pubsub": "~1.1.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@boostercloud/eslint-config": "^2.
|
|
37
|
+
"@boostercloud/eslint-config": "^2.11.0",
|
|
38
38
|
"@types/chai": "4.2.18",
|
|
39
39
|
"@types/chai-as-promised": "7.1.4",
|
|
40
40
|
"@types/faker": "5.1.5",
|