@forestadmin-experimental/datasource-cosmos 1.2.1 → 1.3.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/array-collection.d.ts +75 -0
- package/dist/array-collection.d.ts.map +1 -0
- package/dist/array-collection.js +510 -0
- package/dist/collection.d.ts +5 -0
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +23 -4
- package/dist/datasource.d.ts.map +1 -1
- package/dist/datasource.js +2 -3
- package/dist/index.d.ts +11 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +185 -14
- package/dist/introspection/container-introspector.d.ts +11 -2
- package/dist/introspection/container-introspector.d.ts.map +1 -1
- package/dist/introspection/container-introspector.js +77 -87
- package/dist/introspection/introspector.d.ts +18 -1
- package/dist/introspection/introspector.d.ts.map +1 -1
- package/dist/introspection/introspector.js +68 -5
- package/dist/model-builder/model.d.ts +1 -0
- package/dist/model-builder/model.d.ts.map +1 -1
- package/dist/model-builder/model.js +16 -11
- package/dist/utils/aggregation-converter.d.ts +1 -1
- package/dist/utils/aggregation-converter.d.ts.map +1 -1
- package/dist/utils/aggregation-converter.js +5 -6
- package/dist/utils/model-to-collection-schema-converter.js +2 -2
- package/dist/utils/query-converter.d.ts.map +1 -1
- package/dist/utils/query-converter.js +9 -3
- package/dist/utils/serializer.d.ts.map +1 -1
- package/dist/utils/serializer.js +6 -8
- package/dist/utils/type-converter.d.ts +11 -3
- package/dist/utils/type-converter.d.ts.map +1 -1
- package/dist/utils/type-converter.js +60 -15
- package/package.json +1 -1
|
@@ -6,86 +6,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const model_1 = __importDefault(require("../model-builder/model"));
|
|
7
7
|
const type_converter_1 = __importDefault(require("../utils/type-converter"));
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
* with support for complex nested objects
|
|
11
|
-
*/
|
|
12
|
-
async function introspectContainerV2(cosmosClient, collectionName, databaseName, containerName, partitionKeyPath, sampleSize = 100, overrideTypeConverter, enableCount, options = {}) {
|
|
13
|
-
const { flattenNestedObjects = true, maxDepth = 5, introspectArrayItems = false } = options;
|
|
14
|
-
const database = cosmosClient.database(databaseName);
|
|
15
|
-
const container = database.container(containerName);
|
|
16
|
-
// Get container metadata to determine partition key if not provided
|
|
17
|
-
let actualPartitionKeyPath = partitionKeyPath;
|
|
18
|
-
if (!actualPartitionKeyPath) {
|
|
19
|
-
const { resource: containerDef } = await container.read();
|
|
20
|
-
actualPartitionKeyPath = containerDef.partitionKey?.paths?.[0] || '/id';
|
|
21
|
-
}
|
|
22
|
-
// Sample documents to infer schema
|
|
23
|
-
const querySpec = {
|
|
24
|
-
query: `SELECT TOP ${sampleSize} * FROM c`,
|
|
25
|
-
};
|
|
26
|
-
const { resources: sampleDocuments } = await container.items.query(querySpec).fetchAll();
|
|
27
|
-
// Infer schema from sample documents with nested object support
|
|
28
|
-
const schema = inferSchemaFromDocuments(sampleDocuments, flattenNestedObjects, maxDepth, introspectArrayItems);
|
|
29
|
-
return new model_1.default(cosmosClient, collectionName, databaseName, containerName, actualPartitionKeyPath, schema, overrideTypeConverter, enableCount);
|
|
30
|
-
}
|
|
31
|
-
exports.default = introspectContainerV2;
|
|
32
|
-
/**
|
|
33
|
-
* Infer schema from a collection of sample documents with nested support
|
|
9
|
+
* Check if an object is a GeoJSON Point
|
|
34
10
|
*/
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (documents.length === 0) {
|
|
39
|
-
return {};
|
|
11
|
+
function isGeoPointInternal(value) {
|
|
12
|
+
if (!value || typeof value !== 'object') {
|
|
13
|
+
return false;
|
|
40
14
|
}
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
const fieldPresence = {}; // Track how many docs have each field
|
|
44
|
-
// Analyze each document to collect field types
|
|
45
|
-
for (const doc of documents) {
|
|
46
|
-
const fieldsInDoc = new Set();
|
|
47
|
-
analyzeDocument(doc, fieldTypes, '', 0, maxDepth, flattenNestedObjects, introspectArrayItems, fieldsInDoc);
|
|
48
|
-
// Track field presence
|
|
49
|
-
for (const field of fieldsInDoc) {
|
|
50
|
-
fieldPresence[field] = (fieldPresence[field] || 0) + 1;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
// Convert collected field types to schema
|
|
54
|
-
for (const [fieldName, types] of Object.entries(fieldTypes)) {
|
|
55
|
-
// Skip Cosmos DB system fields (start with _)
|
|
56
|
-
if (!fieldName.startsWith('_') || fieldName === '_id') {
|
|
57
|
-
// Skip parent fields if we have child fields (when flattening is enabled)
|
|
58
|
-
if (flattenNestedObjects) {
|
|
59
|
-
const childFieldPattern = `${fieldName}->`;
|
|
60
|
-
const hasDirectChildFields = Object.keys(fieldTypes).some(otherField => otherField !== fieldName && otherField.startsWith(childFieldPattern));
|
|
61
|
-
if (hasDirectChildFields) {
|
|
62
|
-
// Don't skip if it's an array or other type that doesn't get flattened
|
|
63
|
-
const wasFlattened = types.includes('object');
|
|
64
|
-
if (wasFlattened) {
|
|
65
|
-
// eslint-disable-next-line no-continue
|
|
66
|
-
continue; // Skip this parent field since it was flattened
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
// Get the most specific common type
|
|
71
|
-
const commonType = type_converter_1.default.getMostSpecificType(types);
|
|
72
|
-
// Field is nullable if it contains null OR is not present in all documents
|
|
73
|
-
const nullable = types.includes('null') || fieldPresence[fieldName] < documents.length;
|
|
74
|
-
schema[fieldName] = {
|
|
75
|
-
type: commonType,
|
|
76
|
-
nullable,
|
|
77
|
-
indexed: true, // Assume all fields can be indexed in Cosmos DB
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return schema;
|
|
15
|
+
const obj = value;
|
|
16
|
+
return obj.type === 'Point' && Array.isArray(obj.coordinates) && obj.coordinates.length === 2;
|
|
82
17
|
}
|
|
83
18
|
/**
|
|
84
19
|
* Recursively analyze a document to collect field types with nested object support
|
|
85
20
|
*/
|
|
86
|
-
function
|
|
87
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
88
|
-
obj, fieldTypes, prefix, depth, maxDepth, flattenNestedObjects, introspectArrayItems, fieldsInDoc) {
|
|
21
|
+
function analyzeDocumentInternal(obj, fieldTypes, prefix, depth, maxDepth, flattenNestedObjects, introspectArrayItems, fieldsInDoc) {
|
|
89
22
|
// Helper to record a field type
|
|
90
23
|
const recordField = (fieldName, type) => {
|
|
91
24
|
if (!fieldTypes[fieldName]) {
|
|
@@ -120,7 +53,7 @@ obj, fieldTypes, prefix, depth, maxDepth, flattenNestedObjects, introspectArrayI
|
|
|
120
53
|
const itemsToAnalyze = obj.slice(0, Math.min(5, obj.length));
|
|
121
54
|
for (const item of itemsToAnalyze) {
|
|
122
55
|
if (typeof item === 'object' && item !== null) {
|
|
123
|
-
|
|
56
|
+
analyzeDocumentInternal(item, fieldTypes, `${prefix}[]`, depth + 1, maxDepth, flattenNestedObjects, introspectArrayItems, fieldsInDoc);
|
|
124
57
|
}
|
|
125
58
|
}
|
|
126
59
|
}
|
|
@@ -135,7 +68,7 @@ obj, fieldTypes, prefix, depth, maxDepth, flattenNestedObjects, introspectArrayI
|
|
|
135
68
|
}
|
|
136
69
|
return;
|
|
137
70
|
}
|
|
138
|
-
if (
|
|
71
|
+
if (isGeoPointInternal(obj)) {
|
|
139
72
|
if (prefix) {
|
|
140
73
|
recordField(prefix, 'point');
|
|
141
74
|
}
|
|
@@ -149,9 +82,9 @@ obj, fieldTypes, prefix, depth, maxDepth, flattenNestedObjects, introspectArrayI
|
|
|
149
82
|
!Array.isArray(value) &&
|
|
150
83
|
flattenNestedObjects &&
|
|
151
84
|
!(value instanceof Date) &&
|
|
152
|
-
!
|
|
85
|
+
!isGeoPointInternal(value)) {
|
|
153
86
|
// Recursively analyze nested objects if flattening is enabled
|
|
154
|
-
|
|
87
|
+
analyzeDocumentInternal(value, fieldTypes, fieldName, depth + 1, maxDepth, flattenNestedObjects, introspectArrayItems, fieldsInDoc);
|
|
155
88
|
}
|
|
156
89
|
else {
|
|
157
90
|
// For non-nested or non-flatten mode
|
|
@@ -168,14 +101,71 @@ obj, fieldTypes, prefix, depth, maxDepth, flattenNestedObjects, introspectArrayI
|
|
|
168
101
|
}
|
|
169
102
|
}
|
|
170
103
|
/**
|
|
171
|
-
*
|
|
104
|
+
* Infer schema from a collection of sample documents with nested support
|
|
172
105
|
*/
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
106
|
+
function inferSchemaFromDocumentsInternal(documents, flattenNestedObjects, maxDepth, introspectArrayItems) {
|
|
107
|
+
if (documents.length === 0) {
|
|
108
|
+
return {};
|
|
109
|
+
}
|
|
110
|
+
const schema = {};
|
|
111
|
+
const fieldTypes = {};
|
|
112
|
+
const fieldPresence = {}; // Track how many docs have each field
|
|
113
|
+
// Analyze each document to collect field types
|
|
114
|
+
for (const doc of documents) {
|
|
115
|
+
const fieldsInDoc = new Set();
|
|
116
|
+
analyzeDocumentInternal(doc, fieldTypes, '', 0, maxDepth, flattenNestedObjects, introspectArrayItems, fieldsInDoc);
|
|
117
|
+
// Track field presence
|
|
118
|
+
for (const field of fieldsInDoc) {
|
|
119
|
+
fieldPresence[field] = (fieldPresence[field] || 0) + 1;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Convert collected field types to schema
|
|
123
|
+
for (const [fieldName, types] of Object.entries(fieldTypes)) {
|
|
124
|
+
// Skip Cosmos DB system fields (start with _)
|
|
125
|
+
if (!fieldName.startsWith('_') || fieldName === '_id') {
|
|
126
|
+
// Skip parent fields if we have child fields (when flattening is enabled)
|
|
127
|
+
if (flattenNestedObjects) {
|
|
128
|
+
const childFieldPattern = `${fieldName}->`;
|
|
129
|
+
const hasDirectChildFields = Object.keys(fieldTypes).some(otherField => otherField !== fieldName && otherField.startsWith(childFieldPattern));
|
|
130
|
+
const wasFlattened = types.includes('object');
|
|
131
|
+
if (!(hasDirectChildFields && wasFlattened)) {
|
|
132
|
+
// Get the most specific common type
|
|
133
|
+
const commonType = type_converter_1.default.getMostSpecificType(types);
|
|
134
|
+
// Field is nullable if it contains null OR is not present in all documents
|
|
135
|
+
const nullable = types.includes('null') || fieldPresence[fieldName] < documents.length;
|
|
136
|
+
schema[fieldName] = {
|
|
137
|
+
type: commonType,
|
|
138
|
+
nullable,
|
|
139
|
+
indexed: true, // Assume all fields can be indexed in Cosmos DB
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return schema;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Introspect a Cosmos DB container to infer the schema from sample documents
|
|
149
|
+
* with support for complex nested objects
|
|
150
|
+
*/
|
|
151
|
+
async function introspectContainer(cosmosClient, collectionName, databaseName, containerName, partitionKeyPath, sampleSize = 100, overrideTypeConverter, enableCount, options = {}) {
|
|
152
|
+
const { flattenNestedObjects = true, maxDepth = 5, introspectArrayItems = false } = options;
|
|
153
|
+
const database = cosmosClient.database(databaseName);
|
|
154
|
+
const container = database.container(containerName);
|
|
155
|
+
// Get container metadata to determine partition key if not provided
|
|
156
|
+
let actualPartitionKeyPath = partitionKeyPath;
|
|
157
|
+
if (!actualPartitionKeyPath) {
|
|
158
|
+
const { resource: containerDef } = await container.read();
|
|
159
|
+
actualPartitionKeyPath = containerDef.partitionKey?.paths?.[0] || '/id';
|
|
160
|
+
}
|
|
161
|
+
// Sample documents to infer schema
|
|
162
|
+
const querySpec = {
|
|
163
|
+
query: `SELECT TOP ${sampleSize} * FROM c`,
|
|
164
|
+
};
|
|
165
|
+
const { resources: sampleDocuments } = await container.items.query(querySpec).fetchAll();
|
|
166
|
+
// Infer schema from sample documents with nested object support
|
|
167
|
+
const schema = inferSchemaFromDocumentsInternal(sampleDocuments, flattenNestedObjects, maxDepth, introspectArrayItems);
|
|
168
|
+
return new model_1.default(cosmosClient, collectionName, databaseName, containerName, actualPartitionKeyPath, schema, overrideTypeConverter, enableCount);
|
|
180
169
|
}
|
|
181
|
-
|
|
170
|
+
exports.default = introspectContainer;
|
|
171
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGFpbmVyLWludHJvc3BlY3Rvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9pbnRyb3NwZWN0aW9uL2NvbnRhaW5lci1pbnRyb3NwZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFHQSxtRUFBbUU7QUFDbkUsNkVBQXdFO0FBa0N4RTs7R0FFRztBQUNILFNBQVMsa0JBQWtCLENBQUMsS0FBYztJQUN4QyxJQUFJLENBQUMsS0FBSyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQ3hDLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVELE1BQU0sR0FBRyxHQUFHLEtBQWdDLENBQUM7SUFFN0MsT0FBTyxHQUFHLENBQUMsSUFBSSxLQUFLLE9BQU8sSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsSUFBSSxHQUFHLENBQUMsV0FBVyxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUM7QUFDaEcsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBUyx1QkFBdUIsQ0FDOUIsR0FBWSxFQUNaLFVBQTRDLEVBQzVDLE1BQWMsRUFDZCxLQUFhLEVBQ2IsUUFBZ0IsRUFDaEIsb0JBQTZCLEVBQzdCLG9CQUE2QixFQUM3QixXQUF5QjtJQUV6QixnQ0FBZ0M7SUFDaEMsTUFBTSxXQUFXLEdBQUcsQ0FBQyxTQUFpQixFQUFFLElBQW9CLEVBQUUsRUFBRTtRQUM5RCxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7WUFDM0IsVUFBVSxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUM3QixDQUFDO1FBRUQsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUVqQyxJQUFJLFdBQVcsSUFBSSxTQUFTLEVBQUUsQ0FBQztZQUM3QixXQUFXLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzdCLENB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
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { CosmosClient } from '@azure/cosmos';
|
|
2
2
|
import { Logger } from '@forestadmin/datasource-toolkit';
|
|
3
|
-
import ModelCosmos from '../model-builder/model';
|
|
3
|
+
import ModelCosmos, { CosmosSchema } from '../model-builder/model';
|
|
4
|
+
export interface VirtualArrayCollectionConfig {
|
|
5
|
+
parentContainerName: string;
|
|
6
|
+
collectionName: string;
|
|
7
|
+
arrayFieldPath: string;
|
|
8
|
+
}
|
|
9
|
+
export interface IntrospectionResult {
|
|
10
|
+
models: ModelCosmos[];
|
|
11
|
+
virtualArrayCollections: Array<{
|
|
12
|
+
config: VirtualArrayCollectionConfig;
|
|
13
|
+
schema: CosmosSchema;
|
|
14
|
+
parentModel: ModelCosmos;
|
|
15
|
+
}>;
|
|
16
|
+
}
|
|
4
17
|
export default class Introspector {
|
|
5
18
|
/**
|
|
6
19
|
* Introspect all containers in a Cosmos DB database
|
|
@@ -14,5 +27,9 @@ export default class Introspector {
|
|
|
14
27
|
* Introspect a specific container
|
|
15
28
|
*/
|
|
16
29
|
static introspectContainer(cosmosClient: CosmosClient, databaseName: string, containerName: string, sampleSize?: number, logger?: Logger): Promise<ModelCosmos>;
|
|
30
|
+
/**
|
|
31
|
+
* Introspect array fields in documents to create virtual collection schemas
|
|
32
|
+
*/
|
|
33
|
+
static introspectArrayField(cosmosClient: CosmosClient, databaseName: string, containerName: string, arrayFieldPath: string, sampleSize?: number): Promise<CosmosSchema>;
|
|
17
34
|
}
|
|
18
35
|
//# sourceMappingURL=introspector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"introspector.d.ts","sourceRoot":"","sources":["../../src/introspection/introspector.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"introspector.d.ts","sourceRoot":"","sources":["../../src/introspection/introspector.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAGzD,OAAO,WAAW,EAAE,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAGnE,MAAM,WAAW,4BAA4B;IAC3C,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,uBAAuB,EAAE,KAAK,CAAC;QAC7B,MAAM,EAAE,4BAA4B,CAAC;QACrC,MAAM,EAAE,YAAY,CAAC;QACrB,WAAW,EAAE,WAAW,CAAC;KAC1B,CAAC,CAAC;CACJ;AAED,MAAM,CAAC,OAAO,OAAO,YAAY;IAC/B;;OAEG;WACU,UAAU,CACrB,YAAY,EAAE,YAAY,EAC1B,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,WAAW,EAAE,CAAC;IAMzB;;OAEG;mBACkB,aAAa;IAoElC;;OAEG;WACU,mBAAmB,CAC9B,YAAY,EAAE,YAAY,EAC1B,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,UAAU,CAAC,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,WAAW,CAAC;IAiBvB;;OAEG;WACU,oBAAoB,CAC/B,YAAY,EAAE,YAAY,EAC1B,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,EACtB,UAAU,SAAM,GACf,OAAO,CAAC,YAAY,CAAC;CAgEzB"}
|
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const container_introspector_1 = __importDefault(require("./container-introspector"));
|
|
7
|
+
const type_converter_1 = __importDefault(require("../utils/type-converter"));
|
|
7
8
|
class Introspector {
|
|
8
9
|
/**
|
|
9
10
|
* Introspect all containers in a Cosmos DB database
|
|
@@ -23,17 +24,26 @@ class Introspector {
|
|
|
23
24
|
// Filter out system containers if needed
|
|
24
25
|
const userContainers = containers.filter(container => !container.id.startsWith('_'));
|
|
25
26
|
logger?.('Info', `Introspector - Found ${userContainers.length} containers in database '${databaseName}'`);
|
|
26
|
-
//
|
|
27
|
-
|
|
27
|
+
// Sequential execution required: introspecting containers one at a time
|
|
28
|
+
// ensures consistent resource usage and provides better error context per container
|
|
29
|
+
const introspectionResults = await Promise.all(userContainers.map(async (containerInfo) => {
|
|
28
30
|
try {
|
|
29
31
|
const model = await (0, container_introspector_1.default)(cosmosClient, containerInfo.id, // Use container name as collection name
|
|
30
32
|
databaseName, containerInfo.id, undefined, // Let introspector determine partition key
|
|
31
33
|
100);
|
|
32
|
-
results.push(model);
|
|
33
34
|
logger?.('Info', `Introspector - Successfully introspected container '${containerInfo.id}'`);
|
|
35
|
+
return { success: true, model };
|
|
34
36
|
}
|
|
35
37
|
catch (error) {
|
|
36
|
-
|
|
38
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
39
|
+
logger?.('Warn', `Introspector - Failed to introspect container '${containerInfo.id}': ${errorMessage}`);
|
|
40
|
+
return { success: false, model: null };
|
|
41
|
+
}
|
|
42
|
+
}));
|
|
43
|
+
// Collect successful results
|
|
44
|
+
for (const result of introspectionResults) {
|
|
45
|
+
if (result.success && result.model) {
|
|
46
|
+
results.push(result.model);
|
|
37
47
|
}
|
|
38
48
|
}
|
|
39
49
|
logger?.('Info', `Introspector - The following containers have been loaded: ${userContainers
|
|
@@ -50,6 +60,59 @@ class Introspector {
|
|
|
50
60
|
logger?.('Info', `Introspector - Successfully introspected container '${containerName}'`);
|
|
51
61
|
return model;
|
|
52
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Introspect array fields in documents to create virtual collection schemas
|
|
65
|
+
*/
|
|
66
|
+
static async introspectArrayField(cosmosClient, databaseName, containerName, arrayFieldPath, sampleSize = 100) {
|
|
67
|
+
const database = cosmosClient.database(databaseName);
|
|
68
|
+
const container = database.container(containerName);
|
|
69
|
+
// Build query to fetch documents with the array field
|
|
70
|
+
const fieldPathForQuery = arrayFieldPath.replace(/->/g, '.');
|
|
71
|
+
const querySpec = {
|
|
72
|
+
query: `SELECT TOP ${sampleSize} c.id, c.${fieldPathForQuery} as arrayField FROM c ` +
|
|
73
|
+
`WHERE IS_DEFINED(c.${fieldPathForQuery}) AND IS_ARRAY(c.${fieldPathForQuery})`,
|
|
74
|
+
};
|
|
75
|
+
const { resources: sampleDocuments } = await container.items.query(querySpec).fetchAll();
|
|
76
|
+
if (sampleDocuments.length === 0) {
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
// Collect all array items from the sample documents
|
|
80
|
+
const arrayItems = [];
|
|
81
|
+
for (const doc of sampleDocuments) {
|
|
82
|
+
if (Array.isArray(doc.arrayField)) {
|
|
83
|
+
arrayItems.push(...doc.arrayField);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (arrayItems.length === 0) {
|
|
87
|
+
return {};
|
|
88
|
+
}
|
|
89
|
+
// Analyze array items to infer schema
|
|
90
|
+
const fieldTypes = {};
|
|
91
|
+
for (const item of arrayItems) {
|
|
92
|
+
if (typeof item === 'object' && item !== null) {
|
|
93
|
+
for (const [key, value] of Object.entries(item)) {
|
|
94
|
+
if (!fieldTypes[key]) {
|
|
95
|
+
fieldTypes[key] = [];
|
|
96
|
+
}
|
|
97
|
+
const type = type_converter_1.default.inferTypeFromValue(value);
|
|
98
|
+
fieldTypes[key].push(type);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Build schema from inferred types
|
|
103
|
+
const schema = {};
|
|
104
|
+
for (const [fieldName, types] of Object.entries(fieldTypes)) {
|
|
105
|
+
const uniqueTypes = Array.from(new Set(types));
|
|
106
|
+
const commonType = type_converter_1.default.getMostSpecificType(uniqueTypes);
|
|
107
|
+
const nullable = uniqueTypes.includes('null');
|
|
108
|
+
schema[fieldName] = {
|
|
109
|
+
type: commonType,
|
|
110
|
+
nullable,
|
|
111
|
+
indexed: true,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
return schema;
|
|
115
|
+
}
|
|
53
116
|
}
|
|
54
117
|
exports.default = Introspector;
|
|
55
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
118
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50cm9zcGVjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ludHJvc3BlY3Rpb24vaW50cm9zcGVjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBS0Esc0ZBQTJEO0FBRTNELDZFQUFvRDtBQWlCcEQsTUFBcUIsWUFBWTtJQUMvQjs7T0FFRztJQUNILE1BQU0sQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUNyQixZQUEwQixFQUMxQixZQUFvQixFQUNwQixNQUFlO1FBRWYsTUFBTSxFQUFFLENBQUMsTUFBTSxFQUFFLHFDQUFxQyxDQUFDLENBQUM7UUFFeEQsT0FBTyxZQUFZLENBQUMsYUFBYSxDQUFDLFlBQVksRUFBRSxZQUFZLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDeEUsQ0FBQztJQUVEOztPQUVHO0lBQ0ssTUFBTSxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQ2hDLFlBQTBCLEVBQzFCLFlBQW9CLEVBQ3BCLE1BQWU7UUFFZixNQUFNLE9BQU8sR0FBa0IsRUFBRSxDQUFDO1FBQ2xDLE1BQU0sUUFBUSxHQUFHLFlBQVksQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLENBQUM7UUFFckQscUNBQXFDO1FBQ3JDLE1BQU0sRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLEdBQUcsTUFBTSxRQUFRLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBRWpGLHlDQUF5QztRQUN6QyxNQUFNLGNBQWMsR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBRXJGLE1BQU0sRUFBRSxDQUNOLE1BQU0sRUFDTix3QkFBd0IsY0FBYyxDQUFDLE1BQU0sNEJBQTRCLFlBQVksR0FBRyxDQUN6RixDQUFDO1FBRUYsd0VBQXdFO1FBQ3hFLG9GQUFvRjtRQUNwRixNQUFNLG9C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
|
|
@@ -37,6 +37,7 @@ export default class ModelCosmos {
|
|
|
37
37
|
overrideTypeConverter?: OverrideTypeConverter;
|
|
38
38
|
enableCount?: boolean;
|
|
39
39
|
constructor(cosmosClient: CosmosClient, name: string, databaseName: string, containerName: string, partitionKeyPath: string, schema: CosmosSchema, overrideTypeConverter?: OverrideTypeConverter, enableCount?: boolean);
|
|
40
|
+
getCosmosClient(): CosmosClient;
|
|
40
41
|
create(data: RecordData[]): Promise<RecordData[]>;
|
|
41
42
|
update(ids: string[], patch: RecordData): Promise<void>;
|
|
42
43
|
delete(ids: string[]): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/model-builder/model.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/model-builder/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAkB,YAAY,EAAE,MAAM,eAAe,CAAC;AACtF,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAE7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAGjE,MAAM,WAAW,YAAY;IAC3B,CAAC,GAAG,EAAE,MAAM,GAAG;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;CACH;AAED,MAAM,CAAC,OAAO,OAAO,WAAW;IACvB,IAAI,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,OAAO,CAAC,YAAY,CAAS;IAE7B;;OAEG;IACH,OAAO,CAAC,aAAa,CAAS;IAE9B;;OAEG;IACH,OAAO,CAAC,gBAAgB,CAAS;IAEjC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAe;IAE7B;;OAEG;IACH,OAAO,CAAC,YAAY,CAAe;IAEnC;;OAEG;IACH,OAAO,CAAC,SAAS,CAAY;IAEtB,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAE9C,WAAW,CAAC,EAAE,OAAO,CAAC;gBAG3B,YAAY,EAAE,YAAY,EAC1B,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,gBAAgB,EAAE,MAAM,EACxB,MAAM,EAAE,YAAY,EACpB,qBAAqB,CAAC,EAAE,qBAAqB,EAC7C,WAAW,CAAC,EAAE,OAAO;IAchB,eAAe,IAAI,YAAY;IAIzB,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAiCjD,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBvD,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAcpC,KAAK,CAChB,SAAS,EAAE,YAAY,EACvB,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,EAAE,CAAC;IAsBX,cAAc,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAM9D,KAAK,CAAC,SAAS,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAmB7D;;OAEG;YACW,aAAa;IAgB3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAmB5B;;OAEG;IACH,OAAO,CAAC,UAAU;IAIlB;;OAEG;IACI,aAAa,IAAI,YAAY;IAIpC;;OAEG;IACI,YAAY,IAAI,SAAS;IAIhC;;OAEG;IACI,mBAAmB,IAAI,MAAM;IAIpC;;OAEG;IACI,eAAe,IAAI,MAAM;IAIhC;;OAEG;IACI,gBAAgB,IAAI,MAAM;CAGlC"}
|
|
@@ -16,6 +16,9 @@ class ModelCosmos {
|
|
|
16
16
|
this.cosmosClient = cosmosClient;
|
|
17
17
|
this.container = this.cosmosClient.database(databaseName).container(containerName);
|
|
18
18
|
}
|
|
19
|
+
getCosmosClient() {
|
|
20
|
+
return this.cosmosClient;
|
|
21
|
+
}
|
|
19
22
|
async create(data) {
|
|
20
23
|
const createdRecords = [];
|
|
21
24
|
// Add timestamps if schema includes them
|
|
@@ -24,9 +27,10 @@ class ModelCosmos {
|
|
|
24
27
|
newRecord.createdAt = new Date().toISOString();
|
|
25
28
|
});
|
|
26
29
|
}
|
|
27
|
-
// Cosmos DB doesn't have a native bulk create
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
+
// Sequential execution required: Cosmos DB doesn't have a native bulk create API.
|
|
31
|
+
// While we could parallelize with Promise.all, we keep this sequential to maintain
|
|
32
|
+
// insertion order and ensure consistent error handling. This allows us to return
|
|
33
|
+
// partial results and provide better error context for each record.
|
|
30
34
|
for (const record of data) {
|
|
31
35
|
// Unflatten the record to restore nested structure for Cosmos DB
|
|
32
36
|
const unflattenedRecord = serializer_1.default.unflatten(record);
|
|
@@ -35,7 +39,7 @@ class ModelCosmos {
|
|
|
35
39
|
id: unflattenedRecord.id || this.generateId(),
|
|
36
40
|
...unflattenedRecord,
|
|
37
41
|
};
|
|
38
|
-
// eslint-disable-next-line no-await-in-loop
|
|
42
|
+
// eslint-disable-next-line no-await-in-loop -- Sequential execution maintains order
|
|
39
43
|
const { resource } = await this.container.items.create(itemToCreate);
|
|
40
44
|
// Flatten and serialize the response
|
|
41
45
|
createdRecords.push(serializer_1.default.serialize(resource));
|
|
@@ -48,22 +52,24 @@ class ModelCosmos {
|
|
|
48
52
|
const itemsToUpdate = await this.getItemsByIds(ids);
|
|
49
53
|
// Unflatten the patch to restore nested structure for Cosmos DB
|
|
50
54
|
const unflattenedPatch = serializer_1.default.unflatten(patch);
|
|
51
|
-
//
|
|
55
|
+
// Sequential execution required: Cosmos DB updates must be performed one at a time
|
|
56
|
+
// to ensure consistency and prevent conflicts with optimistic concurrency control
|
|
52
57
|
for (const item of itemsToUpdate) {
|
|
53
58
|
const partitionKeyValue = this.getPartitionKeyValue(item);
|
|
54
59
|
// Deep merge the unflattened patch with the existing item
|
|
55
60
|
const updatedItem = serializer_1.default.deepMerge(item, unflattenedPatch);
|
|
56
|
-
// eslint-disable-next-line no-await-in-loop
|
|
61
|
+
// eslint-disable-next-line no-await-in-loop -- Sequential maintains consistency
|
|
57
62
|
await this.container.item(item.id, partitionKeyValue).replace(updatedItem);
|
|
58
63
|
}
|
|
59
64
|
}
|
|
60
65
|
async delete(ids) {
|
|
61
66
|
// Similar to update, we need partition keys for deletion
|
|
62
67
|
const itemsToDelete = await this.getItemsByIds(ids);
|
|
63
|
-
//
|
|
68
|
+
// Sequential execution required: Cosmos DB deletes must be performed one at a time
|
|
69
|
+
// to ensure consistency and prevent conflicts
|
|
64
70
|
for (const item of itemsToDelete) {
|
|
65
71
|
const partitionKeyValue = this.getPartitionKeyValue(item);
|
|
66
|
-
// eslint-disable-next-line no-await-in-loop
|
|
72
|
+
// eslint-disable-next-line no-await-in-loop -- Sequential maintains consistency
|
|
67
73
|
await this.container.item(item.id, partitionKeyValue).delete();
|
|
68
74
|
}
|
|
69
75
|
}
|
|
@@ -125,10 +131,9 @@ class ModelCosmos {
|
|
|
125
131
|
const keyPath = this.partitionKeyPath.replace(/^\//, '');
|
|
126
132
|
// Handle nested paths (e.g., "/address/city")
|
|
127
133
|
const keys = keyPath.split('/');
|
|
128
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
129
134
|
let value = item;
|
|
130
135
|
for (const key of keys) {
|
|
131
|
-
if (value && typeof value === 'object') {
|
|
136
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
132
137
|
value = value[key];
|
|
133
138
|
}
|
|
134
139
|
else {
|
|
@@ -175,4 +180,4 @@ class ModelCosmos {
|
|
|
175
180
|
}
|
|
176
181
|
}
|
|
177
182
|
exports.default = ModelCosmos;
|
|
178
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
183
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kZWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbW9kZWwtYnVpbGRlci9tb2RlbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUlBLHFFQUE2QztBQVU3QyxNQUFxQixXQUFXO0lBcUM5QixZQUNFLFlBQTBCLEVBQzFCLElBQVksRUFDWixZQUFvQixFQUNwQixhQUFxQixFQUNyQixnQkFBd0IsRUFDeEIsTUFBb0IsRUFDcEIscUJBQTZDLEVBQzdDLFdBQXFCO1FBRXJCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBQ2pCLElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO1FBQ2pDLElBQUksQ0FBQyxhQUFhLEdBQUcsYUFBYSxDQUFDO1FBQ25DLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxnQkFBZ0IsQ0FBQztRQUN6QyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJQUFJLENBQUMscUJBQXFCLEdBQUcscUJBQXFCLENBQUM7UUFDbkQsSUFBSSxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUM7UUFFL0IsSUFBSSxDQUFDLFlBQVksR0FBRyxZQUFZLENBQUM7UUFDakMsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQyxTQUFTLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDckYsQ0FBQztJQUVNLGVBQWU7UUFDcEIsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDO0lBQzNCLENBQUM7SUFFTSxLQUFLLENBQUMsTUFBTSxDQUFDLElBQWtCO1FBQ3BDLE1BQU0sY0FBYyxHQUFpQixFQUFFLENBQUM7UUFFeEMseUNBQXlDO1FBQ3pDLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUMxQixJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFO2dCQUN2QixTQUFTLENBQUMsU0FBUyxHQUFHLElB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
|
|
@@ -25,7 +25,7 @@ export default class AggregationConverter {
|
|
|
25
25
|
/**
|
|
26
26
|
* Process raw aggregation results into Forest Admin format
|
|
27
27
|
*/
|
|
28
|
-
static processAggregationResults(rawResults:
|
|
28
|
+
static processAggregationResults(rawResults: Array<Record<string, unknown>>, aggregation: Aggregation): AggregateResult[];
|
|
29
29
|
/**
|
|
30
30
|
* Build a simpler aggregation query for single-group scenarios
|
|
31
31
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aggregation-converter.d.ts","sourceRoot":"","sources":["../../src/utils/aggregation-converter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,YAAY,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EACL,eAAe,EACf,WAAW,EACX,oBAAoB,EACpB,aAAa,EAEd,MAAM,iCAAiC,CAAC;AAKzC,MAAM,CAAC,OAAO,OAAO,oBAAoB;IACvC,OAAO,CAAC,MAAM,CAAC,qBAAqB,CAMlC;IAEF;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IAI5B;;OAEG;IACH,MAAM,CAAC,qBAAqB,CAC1B,WAAW,EAAE,WAAW,EACxB,aAAa,CAAC,EAAE,aAAa,EAC7B,KAAK,CAAC,EAAE,MAAM,GACb,YAAY;IAiBf;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAavC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,4BAA4B;IA8D3C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,wBAAwB;IA0BvC;;OAEG;IACH,MAAM,CAAC,yBAAyB,
|
|
1
|
+
{"version":3,"file":"aggregation-converter.d.ts","sourceRoot":"","sources":["../../src/utils/aggregation-converter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,YAAY,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EACL,eAAe,EACf,WAAW,EACX,oBAAoB,EACpB,aAAa,EAEd,MAAM,iCAAiC,CAAC;AAKzC,MAAM,CAAC,OAAO,OAAO,oBAAoB;IACvC,OAAO,CAAC,MAAM,CAAC,qBAAqB,CAMlC;IAEF;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IAI5B;;OAEG;IACH,MAAM,CAAC,qBAAqB,CAC1B,WAAW,EAAE,WAAW,EACxB,aAAa,CAAC,EAAE,aAAa,EAC7B,KAAK,CAAC,EAAE,MAAM,GACb,YAAY;IAiBf;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAavC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,4BAA4B;IA8D3C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,wBAAwB;IA0BvC;;OAEG;IACH,MAAM,CAAC,yBAAyB,CAC9B,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC1C,WAAW,EAAE,WAAW,GACvB,eAAe,EAAE;IAoCpB;;OAEG;IACH,MAAM,CAAC,2BAA2B,CAChC,SAAS,EAAE,oBAAoB,EAC/B,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,aAAa,CAAC,EAAE,aAAa,EAC7B,KAAK,CAAC,EAAE,MAAM,GACb,YAAY;CAuChB"}
|
|
@@ -114,24 +114,23 @@ class AggregationConverter {
|
|
|
114
114
|
/**
|
|
115
115
|
* Process raw aggregation results into Forest Admin format
|
|
116
116
|
*/
|
|
117
|
-
static processAggregationResults(
|
|
118
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
119
|
-
rawResults, aggregation) {
|
|
117
|
+
static processAggregationResults(rawResults, aggregation) {
|
|
120
118
|
// Handle simple aggregation without grouping
|
|
121
119
|
if (!aggregation.groups || aggregation.groups.length === 0) {
|
|
122
120
|
if (rawResults.length === 0) {
|
|
123
121
|
return [{ value: 0, group: {} }];
|
|
124
122
|
}
|
|
123
|
+
const firstResult = rawResults[0];
|
|
124
|
+
const resultValue = (firstResult.aggregateValue ?? firstResult.value);
|
|
125
125
|
return [
|
|
126
126
|
{
|
|
127
|
-
value: serializer_1.default.serializeValue(
|
|
127
|
+
value: serializer_1.default.serializeValue(resultValue),
|
|
128
128
|
group: {},
|
|
129
129
|
},
|
|
130
130
|
];
|
|
131
131
|
}
|
|
132
132
|
// Handle grouped aggregation
|
|
133
133
|
return rawResults.map(result => {
|
|
134
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
135
134
|
const group = {};
|
|
136
135
|
if (aggregation.groups) {
|
|
137
136
|
aggregation.groups.forEach((groupDef, index) => {
|
|
@@ -189,4 +188,4 @@ AggregationConverter.AGGREGATION_OPERATION = {
|
|
|
189
188
|
Min: 'MIN',
|
|
190
189
|
};
|
|
191
190
|
exports.default = AggregationConverter;
|
|
192
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
191
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdncmVnYXRpb24tY29udmVydGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL2FnZ3JlZ2F0aW9uLWNvbnZlcnRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQVNBLHdFQUErQztBQUMvQyw4REFBc0M7QUFFdEMsTUFBcUIsb0JBQW9CO0lBU3ZDOztPQUVHO0lBQ0ssTUFBTSxDQUFDLGFBQWEsQ0FBQyxLQUFhO1FBQ3hDLE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDbkMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLHFCQUFxQixDQUMxQixXQUF3QixFQUN4QixhQUE2QixFQUM3QixLQUFjO1FBRWQsTUFBTSxjQUFjLEdBQUcsSUFBSSx5QkFBYyxFQUFFLENBQUM7UUFDNUMsTUFBTSxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsR0FBRyxjQUFjLENBQUMsY0FBYyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQzNFLE1BQU0sYUFBYSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsU0FBUyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBRXBELDZDQUE2QztRQUM3QyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sSUFBSSxXQUFXLENBQUMsTUFBTSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUMzRCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsd0JBQXdCLENBQUMsV0FBVyxDQUFDLENBQUM7WUFDaEUsTUFBTSxLQUFLLEdBQUcsVUFBVSxZQUFZLDZCQUE2QixhQUFhLEVBQUUsQ0FBQztZQUVqRixPQUFPLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBRSxDQUFDO1FBQy9CLENBQUM7UUFFRCxtQ0FBbUM7UUFDbkMsT0FBTyxJQUFJLENBQUMsNEJBQTRCLENBQUMsV0FBVyxFQUFFLGFBQWEsRUFBRSxVQUFVLEVBQUUsS0FB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
|