rawsql-ts 0.11.1-beta → 0.11.3-beta
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/README.md +735 -682
- package/dist/esm/index.js +8 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.min.js +46 -12
- package/dist/esm/index.min.js.map +4 -4
- package/dist/esm/src/index.js +8 -2
- package/dist/esm/src/index.js.map +1 -1
- package/dist/esm/src/models/BinarySelectQuery.js +9 -0
- package/dist/esm/src/models/BinarySelectQuery.js.map +1 -1
- package/dist/esm/src/models/CTEError.js +31 -0
- package/dist/esm/src/models/CTEError.js.map +1 -0
- package/dist/esm/src/models/SelectQuery.js +1 -0
- package/dist/esm/src/models/SelectQuery.js.map +1 -1
- package/dist/esm/src/models/SimpleSelectQuery.js +229 -0
- package/dist/esm/src/models/SimpleSelectQuery.js.map +1 -1
- package/dist/esm/src/models/ValuesQuery.js +1 -1
- package/dist/esm/src/models/ValuesQuery.js.map +1 -1
- package/dist/esm/src/parsers/ValueParser.js +86 -4
- package/dist/esm/src/parsers/ValueParser.js.map +1 -1
- package/dist/esm/src/transformers/DynamicQueryBuilder.js.map +1 -1
- package/dist/esm/src/transformers/EnhancedJsonMapping.js +217 -0
- package/dist/esm/src/transformers/EnhancedJsonMapping.js.map +1 -0
- package/dist/esm/src/transformers/JsonMappingConverter.js +388 -0
- package/dist/esm/src/transformers/JsonMappingConverter.js.map +1 -0
- package/dist/esm/src/transformers/JsonMappingUnifier.js +36 -46
- package/dist/esm/src/transformers/JsonMappingUnifier.js.map +1 -1
- package/dist/esm/src/transformers/ModelDrivenJsonMapping.js +14 -2
- package/dist/esm/src/transformers/ModelDrivenJsonMapping.js.map +1 -1
- package/dist/esm/src/transformers/PostgresArrayEntityCteBuilder.js +132 -97
- package/dist/esm/src/transformers/PostgresArrayEntityCteBuilder.js.map +1 -1
- package/dist/esm/src/transformers/PostgresJsonQueryBuilder.js +21 -11
- package/dist/esm/src/transformers/PostgresJsonQueryBuilder.js.map +1 -1
- package/dist/esm/src/transformers/PostgresObjectEntityCteBuilder.js +71 -14
- package/dist/esm/src/transformers/PostgresObjectEntityCteBuilder.js.map +1 -1
- package/dist/esm/src/transformers/QueryBuilder.js +2 -0
- package/dist/esm/src/transformers/QueryBuilder.js.map +1 -1
- package/dist/esm/src/transformers/SqlParamInjector.js +189 -108
- package/dist/esm/src/transformers/SqlParamInjector.js.map +1 -1
- package/dist/esm/src/transformers/UpstreamSelectQueryFinder.js +43 -2
- package/dist/esm/src/transformers/UpstreamSelectQueryFinder.js.map +1 -1
- package/dist/esm/tsconfig.browser.tsbuildinfo +1 -1
- package/dist/esm/types/src/index.d.ts +8 -2
- package/dist/esm/types/src/models/BinarySelectQuery.d.ts +7 -0
- package/dist/esm/types/src/models/CTEError.d.ts +21 -0
- package/dist/esm/types/src/models/SelectQuery.d.ts +12 -0
- package/dist/esm/types/src/models/SimpleSelectQuery.d.ts +166 -2
- package/dist/esm/types/src/models/ValuesQuery.d.ts +1 -1
- package/dist/esm/types/src/parsers/ValueParser.d.ts +8 -0
- package/dist/esm/types/src/transformers/DynamicQueryBuilder.d.ts +6 -0
- package/dist/esm/types/src/transformers/EnhancedJsonMapping.d.ts +194 -0
- package/dist/esm/types/src/transformers/JsonMappingConverter.d.ts +200 -0
- package/dist/esm/types/src/transformers/JsonMappingUnifier.d.ts +5 -0
- package/dist/esm/types/src/transformers/PostgresArrayEntityCteBuilder.d.ts +39 -77
- package/dist/esm/types/src/transformers/PostgresJsonQueryBuilder.d.ts +3 -2
- package/dist/esm/types/src/transformers/PostgresObjectEntityCteBuilder.d.ts +31 -6
- package/dist/esm/types/src/transformers/SqlParamInjector.d.ts +48 -0
- package/dist/esm/types/src/transformers/UpstreamSelectQueryFinder.d.ts +8 -0
- package/dist/index.min.js +46 -12
- package/dist/index.min.js.map +4 -4
- package/dist/src/index.d.ts +8 -2
- package/dist/src/index.js +8 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/models/BinarySelectQuery.d.ts +7 -0
- package/dist/src/models/BinarySelectQuery.js +9 -0
- package/dist/src/models/BinarySelectQuery.js.map +1 -1
- package/dist/src/models/CTEError.d.ts +21 -0
- package/dist/src/models/CTEError.js +37 -0
- package/dist/src/models/CTEError.js.map +1 -0
- package/dist/src/models/SelectQuery.d.ts +12 -0
- package/dist/src/models/SelectQuery.js +5 -1
- package/dist/src/models/SelectQuery.js.map +1 -1
- package/dist/src/models/SimpleSelectQuery.d.ts +166 -2
- package/dist/src/models/SimpleSelectQuery.js +229 -0
- package/dist/src/models/SimpleSelectQuery.js.map +1 -1
- package/dist/src/models/ValuesQuery.d.ts +1 -1
- package/dist/src/models/ValuesQuery.js +1 -1
- package/dist/src/models/ValuesQuery.js.map +1 -1
- package/dist/src/parsers/ValueParser.d.ts +8 -0
- package/dist/src/parsers/ValueParser.js +86 -4
- package/dist/src/parsers/ValueParser.js.map +1 -1
- package/dist/src/transformers/DynamicQueryBuilder.d.ts +6 -0
- package/dist/src/transformers/DynamicQueryBuilder.js.map +1 -1
- package/dist/src/transformers/EnhancedJsonMapping.d.ts +194 -0
- package/dist/src/transformers/EnhancedJsonMapping.js +223 -0
- package/dist/src/transformers/EnhancedJsonMapping.js.map +1 -0
- package/dist/src/transformers/JsonMappingConverter.d.ts +200 -0
- package/dist/src/transformers/JsonMappingConverter.js +392 -0
- package/dist/src/transformers/JsonMappingConverter.js.map +1 -0
- package/dist/src/transformers/JsonMappingUnifier.d.ts +5 -0
- package/dist/src/transformers/JsonMappingUnifier.js +36 -46
- package/dist/src/transformers/JsonMappingUnifier.js.map +1 -1
- package/dist/src/transformers/ModelDrivenJsonMapping.js +14 -2
- package/dist/src/transformers/ModelDrivenJsonMapping.js.map +1 -1
- package/dist/src/transformers/PostgresArrayEntityCteBuilder.d.ts +39 -77
- package/dist/src/transformers/PostgresArrayEntityCteBuilder.js +132 -97
- package/dist/src/transformers/PostgresArrayEntityCteBuilder.js.map +1 -1
- package/dist/src/transformers/PostgresJsonQueryBuilder.d.ts +3 -2
- package/dist/src/transformers/PostgresJsonQueryBuilder.js +21 -11
- package/dist/src/transformers/PostgresJsonQueryBuilder.js.map +1 -1
- package/dist/src/transformers/PostgresObjectEntityCteBuilder.d.ts +31 -6
- package/dist/src/transformers/PostgresObjectEntityCteBuilder.js +71 -14
- package/dist/src/transformers/PostgresObjectEntityCteBuilder.js.map +1 -1
- package/dist/src/transformers/QueryBuilder.js +2 -0
- package/dist/src/transformers/QueryBuilder.js.map +1 -1
- package/dist/src/transformers/SqlParamInjector.d.ts +48 -0
- package/dist/src/transformers/SqlParamInjector.js +189 -108
- package/dist/src/transformers/SqlParamInjector.js.map +1 -1
- package/dist/src/transformers/UpstreamSelectQueryFinder.d.ts +8 -0
- package/dist/src/transformers/UpstreamSelectQueryFinder.js +43 -2
- package/dist/src/transformers/UpstreamSelectQueryFinder.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Unified JSON Mapping processor that supports both legacy and model-driven formats.
|
|
3
3
|
*
|
|
4
|
+
* @deprecated Use JsonMappingConverter instead. This module is kept for backward compatibility.
|
|
4
5
|
* This module provides backward compatibility while encouraging migration to the model-driven format.
|
|
5
6
|
* It automatically detects the input format and normalizes to a consistent internal representation.
|
|
6
7
|
*/
|
|
7
|
-
import {
|
|
8
|
+
import { JsonMappingConverter } from './JsonMappingConverter';
|
|
8
9
|
/**
|
|
9
10
|
* Detects the format of a JSON mapping configuration.
|
|
10
11
|
*
|
|
@@ -95,6 +96,8 @@ function convertLegacyFormat(input) {
|
|
|
95
96
|
/**
|
|
96
97
|
* Main processor that unifies all JSON mapping formats into a consistent JsonMapping.
|
|
97
98
|
*
|
|
99
|
+
* @deprecated Use JsonMappingConverter.convert() instead.
|
|
100
|
+
*
|
|
98
101
|
* Features:
|
|
99
102
|
* - Automatic format detection
|
|
100
103
|
* - Backward compatibility with all existing formats
|
|
@@ -105,65 +108,52 @@ function convertLegacyFormat(input) {
|
|
|
105
108
|
* @returns Unified processing result with JsonMapping and metadata
|
|
106
109
|
*/
|
|
107
110
|
export function processJsonMapping(input) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (!input.typeInfo || !input.structure) {
|
|
116
|
-
throw new Error('Model-driven format requires typeInfo and structure fields');
|
|
117
|
-
}
|
|
118
|
-
// Convert model-driven to JsonMapping
|
|
119
|
-
const modelDrivenInput = {
|
|
120
|
-
typeInfo: input.typeInfo,
|
|
121
|
-
structure: input.structure
|
|
122
|
-
};
|
|
123
|
-
const converted = convertModelDrivenMapping(modelDrivenInput);
|
|
124
|
-
jsonMapping = converted.jsonMapping;
|
|
125
|
-
// Preserve metadata
|
|
126
|
-
metadata = {
|
|
127
|
-
typeInfo: input.typeInfo,
|
|
128
|
-
typeProtection: converted.typeProtection
|
|
129
|
-
};
|
|
130
|
-
break;
|
|
131
|
-
case 'unified':
|
|
132
|
-
// Validate unified input
|
|
133
|
-
if (!input.rootEntity) {
|
|
134
|
-
throw new Error('Unified format requires rootEntity field');
|
|
135
|
-
}
|
|
136
|
-
jsonMapping = convertUnifiedFormat(input);
|
|
137
|
-
break;
|
|
138
|
-
case 'legacy':
|
|
139
|
-
// Validate legacy input
|
|
140
|
-
if (!input.columns && !input.relationships) {
|
|
141
|
-
throw new Error('Legacy format requires at least columns or relationships field');
|
|
142
|
-
}
|
|
143
|
-
jsonMapping = convertLegacyFormat(input);
|
|
144
|
-
break;
|
|
145
|
-
default:
|
|
146
|
-
throw new Error(`Unsupported mapping format: ${format}`);
|
|
147
|
-
}
|
|
111
|
+
var _a;
|
|
112
|
+
// Runtime deprecation warning
|
|
113
|
+
console.warn('⚠️ DEPRECATED: processJsonMapping() is deprecated. Use JsonMappingConverter.convert() instead.');
|
|
114
|
+
console.warn('Migration guide: https://github.com/mk3008/rawsql-ts/blob/main/docs/migration-guide.md');
|
|
115
|
+
// Check for legacy format with columns and relationships
|
|
116
|
+
if ((input.columns || input.relationships) && !input.rootName && !input.rootEntity) {
|
|
117
|
+
const jsonMapping = convertLegacyFormat(input);
|
|
148
118
|
return {
|
|
149
|
-
format,
|
|
119
|
+
format: 'legacy',
|
|
150
120
|
jsonMapping,
|
|
151
121
|
originalInput: input,
|
|
152
|
-
metadata
|
|
122
|
+
metadata: {}
|
|
153
123
|
};
|
|
154
124
|
}
|
|
155
|
-
|
|
156
|
-
|
|
125
|
+
const converter = new JsonMappingConverter();
|
|
126
|
+
const result = converter.convert(input);
|
|
127
|
+
// Map converter formats to unifier formats for backward compatibility
|
|
128
|
+
let format = result.format;
|
|
129
|
+
// If it's detected as 'legacy' by converter but has rootName and rootEntity, it's 'unified' format
|
|
130
|
+
if (result.format === 'legacy' && input.rootName && input.rootEntity) {
|
|
131
|
+
format = 'unified';
|
|
157
132
|
}
|
|
133
|
+
return {
|
|
134
|
+
format,
|
|
135
|
+
jsonMapping: result.mapping,
|
|
136
|
+
originalInput: input,
|
|
137
|
+
metadata: {
|
|
138
|
+
typeInfo: (_a = result.metadata) === null || _a === void 0 ? void 0 : _a.typeInfo,
|
|
139
|
+
typeProtection: result.typeProtection
|
|
140
|
+
}
|
|
141
|
+
};
|
|
158
142
|
}
|
|
159
143
|
/**
|
|
160
144
|
* Convenience function for direct JsonMapping extraction.
|
|
161
145
|
*
|
|
146
|
+
* @deprecated Use JsonMappingConverter.toLegacyMapping() instead.
|
|
147
|
+
*
|
|
162
148
|
* @param input - Any supported JSON mapping format
|
|
163
149
|
* @returns JsonMapping ready for use with PostgresJsonQueryBuilder
|
|
164
150
|
*/
|
|
165
151
|
export function unifyJsonMapping(input) {
|
|
166
|
-
|
|
152
|
+
// Runtime deprecation warning
|
|
153
|
+
console.warn('⚠️ DEPRECATED: unifyJsonMapping() is deprecated. Use JsonMappingConverter.toLegacyMapping() instead.');
|
|
154
|
+
console.warn('Migration guide: https://github.com/mk3008/rawsql-ts/blob/main/docs/migration-guide.md');
|
|
155
|
+
const converter = new JsonMappingConverter();
|
|
156
|
+
return converter.toLegacyMapping(input);
|
|
167
157
|
}
|
|
168
158
|
/**
|
|
169
159
|
* Type guard to check if input uses model-driven format.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonMappingUnifier.js","sourceRoot":"","sources":["../../../../src/transformers/JsonMappingUnifier.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"JsonMappingUnifier.js","sourceRoot":"","sources":["../../../../src/transformers/JsonMappingUnifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,8 +9,17 @@
|
|
|
9
9
|
export function convertModelDrivenMapping(modelMapping) {
|
|
10
10
|
const protectedStringFields = [];
|
|
11
11
|
let entityIdCounter = 0;
|
|
12
|
+
const propertyNameCounters = {};
|
|
12
13
|
// Generate unique entity IDs
|
|
13
14
|
const generateEntityId = () => `entity_${++entityIdCounter}`;
|
|
15
|
+
// Generate unique property names to avoid JSON key conflicts
|
|
16
|
+
const generateUniquePropertyName = (baseName) => {
|
|
17
|
+
if (!propertyNameCounters[baseName]) {
|
|
18
|
+
propertyNameCounters[baseName] = 0;
|
|
19
|
+
}
|
|
20
|
+
propertyNameCounters[baseName]++;
|
|
21
|
+
return propertyNameCounters[baseName] === 1 ? baseName : `${baseName}_${propertyNameCounters[baseName]}`;
|
|
22
|
+
};
|
|
14
23
|
// Helper function to process structure fields and extract entities
|
|
15
24
|
const processStructure = (structure, parentId = null) => {
|
|
16
25
|
const columns = {};
|
|
@@ -43,13 +52,16 @@ export function convertModelDrivenMapping(modelMapping) {
|
|
|
43
52
|
else if ('type' in config && (config.type === 'object' || config.type === 'array')) {
|
|
44
53
|
// Nested structure: object or array
|
|
45
54
|
const nestedStructure = config;
|
|
55
|
+
const uniquePropertyName = generateUniquePropertyName(fieldName);
|
|
56
|
+
// Generate globally unique entity ID to ensure unique JSON column names
|
|
46
57
|
const entityId = generateEntityId();
|
|
47
58
|
const processedNested = processStructure(nestedStructure.structure, entityId);
|
|
48
59
|
nestedEntities.push({
|
|
49
|
-
id: entityId,
|
|
60
|
+
id: entityId, // Use unique ID to avoid column conflicts
|
|
50
61
|
name: fieldName.charAt(0).toUpperCase() + fieldName.slice(1), // Capitalize first letter
|
|
51
62
|
parentId: parentId || 'root',
|
|
52
|
-
propertyName:
|
|
63
|
+
propertyName: uniquePropertyName,
|
|
64
|
+
originalPropertyName: fieldName, // Store original name for final mapping
|
|
53
65
|
relationshipType: nestedStructure.type,
|
|
54
66
|
columns: processedNested.columns
|
|
55
67
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModelDrivenJsonMapping.js","sourceRoot":"","sources":["../../../../src/transformers/ModelDrivenJsonMapping.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuDH;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,YAAoC;IAI1E,MAAM,qBAAqB,GAAa,EAAE,CAAC;IAC3C,IAAI,eAAe,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"ModelDrivenJsonMapping.js","sourceRoot":"","sources":["../../../../src/transformers/ModelDrivenJsonMapping.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,42 +3,27 @@ import { SimpleSelectQuery } from '../models/SimpleSelectQuery';
|
|
|
3
3
|
import { IdentifierString, ColumnReference, FunctionCall, ValueList, LiteralValue, RawString } from '../models/ValueComponent';
|
|
4
4
|
import { SelectValueCollector } from './SelectValueCollector';
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* This class handles the creation of CTEs that build JSON/JSONB arrays for child entities,
|
|
8
|
-
* processing them from the deepest level up to ensure proper dependency ordering.
|
|
6
|
+
* Builds CTEs for array entities using depth-first processing and row compression.
|
|
9
7
|
*
|
|
10
|
-
*
|
|
11
|
-
* -
|
|
12
|
-
* - Row
|
|
13
|
-
* -
|
|
14
|
-
* -
|
|
15
|
-
* - Column exclusion to avoid duplication
|
|
16
|
-
*
|
|
17
|
-
* Why depth calculation is critical:
|
|
18
|
-
* 1. Array entities can be nested at multiple levels. We must process the deepest
|
|
19
|
-
* (most distant) arrays first to ensure their JSON representations are available
|
|
20
|
-
* when building their parent arrays.
|
|
21
|
-
* 2. Array entity processing is essentially a row compression operation using GROUP BY.
|
|
22
|
-
* Unlike parent entities which use column compression, arrays require grouping
|
|
23
|
-
* to aggregate multiple rows into JSON arrays.
|
|
24
|
-
*
|
|
25
|
-
* Example hierarchy:
|
|
26
|
-
* Order (root, depth 0)
|
|
27
|
-
* └─ Items (array, depth 1)
|
|
28
|
-
* └─ Details (array, depth 2)
|
|
29
|
-
*
|
|
30
|
-
* Processing order: depth 2 → depth 1 → depth 0
|
|
8
|
+
* Core concepts:
|
|
9
|
+
* - Column Compression: OBJECT relationships (user_id, user_name → user_json)
|
|
10
|
+
* - Row Compression: ARRAY relationships (multiple rows → JSON array via GROUP BY)
|
|
11
|
+
* - Depth-First: Process deepest arrays first for dependency ordering
|
|
12
|
+
* - GROUP BY Exclusion: Exclude array-internal columns to prevent over-grouping
|
|
31
13
|
*/
|
|
32
14
|
export class PostgresArrayEntityCteBuilder {
|
|
33
15
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
16
|
+
* Builds CTEs for all array entities using depth-first processing.
|
|
17
|
+
* Collects arrays by depth, processes deepest first, chains CTEs.
|
|
18
|
+
*
|
|
19
|
+
* @param ctesSoFar Array of CTEs built so far
|
|
20
|
+
* @param aliasOfCteToBuildUpon Alias of the CTE to build upon
|
|
37
21
|
* @param allEntities Map of all entities in the mapping
|
|
38
22
|
* @param mapping The JSON mapping configuration
|
|
39
|
-
* @
|
|
23
|
+
* @param columnMappings Optional mappings from object entity IDs to generated JSON column names
|
|
24
|
+
* @returns Object containing updated CTEs and last CTE alias
|
|
40
25
|
*/
|
|
41
|
-
buildArrayEntityCtes(ctesSoFar, aliasOfCteToBuildUpon, allEntities, mapping) {
|
|
26
|
+
buildArrayEntityCtes(ctesSoFar, aliasOfCteToBuildUpon, allEntities, mapping, columnMappings) {
|
|
42
27
|
let currentCtes = [...ctesSoFar];
|
|
43
28
|
let currentCteAlias = aliasOfCteToBuildUpon;
|
|
44
29
|
// Collect and sort array entities by depth
|
|
@@ -53,22 +38,19 @@ export class PostgresArrayEntityCteBuilder {
|
|
|
53
38
|
for (const depth of depths) {
|
|
54
39
|
const infos = entitiesByDepth.get(depth);
|
|
55
40
|
// Build CTE for all entities at this depth
|
|
56
|
-
const { cte, newCteAlias } = this.buildDepthCte(infos, currentCteAlias, currentCtes, depth, mapping);
|
|
41
|
+
const { cte, newCteAlias } = this.buildDepthCte(infos, currentCteAlias, currentCtes, depth, mapping, columnMappings);
|
|
57
42
|
currentCtes.push(cte);
|
|
58
43
|
currentCteAlias = newCteAlias;
|
|
59
44
|
}
|
|
60
45
|
return { updatedCtes: currentCtes, lastCteAlias: currentCteAlias };
|
|
61
46
|
}
|
|
62
47
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* Depth calculation ensures proper processing order where deeper nested
|
|
66
|
-
* arrays are processed first, making their aggregated data available
|
|
67
|
-
* for parent array processing.
|
|
48
|
+
* Collects array entities and calculates depth for dependency ordering.
|
|
49
|
+
* Depth = distance from root. Deeper arrays processed first.
|
|
68
50
|
*
|
|
69
51
|
* @param mapping The JSON mapping configuration
|
|
70
52
|
* @param allEntities Map of all entities in the mapping
|
|
71
|
-
* @returns Array of array entity information with
|
|
53
|
+
* @returns Array of array entity information with depths, sorted deepest first
|
|
72
54
|
*/
|
|
73
55
|
collectAndSortArrayEntities(mapping, allEntities) {
|
|
74
56
|
const arrayEntityInfos = [];
|
|
@@ -110,12 +92,7 @@ export class PostgresArrayEntityCteBuilder {
|
|
|
110
92
|
return arrayEntityInfos;
|
|
111
93
|
}
|
|
112
94
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* Grouping by depth allows us to:
|
|
116
|
-
* - Process all entities at the same level in a single CTE
|
|
117
|
-
* - Optimize query performance by reducing the number of CTEs
|
|
118
|
-
* - Maintain clear dependency ordering
|
|
95
|
+
* Groups array entities by depth level for batch processing.
|
|
119
96
|
*
|
|
120
97
|
* @param arrayInfos Array of array entity information with depths
|
|
121
98
|
* @returns Map of depth level to entities at that depth
|
|
@@ -132,19 +109,19 @@ export class PostgresArrayEntityCteBuilder {
|
|
|
132
109
|
return entitiesByDepth;
|
|
133
110
|
}
|
|
134
111
|
/**
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
* at the same depth, using GROUP BY to compress rows into JSON arrays.
|
|
112
|
+
* Builds CTE for specific depth level using row compression.
|
|
113
|
+
* Uses GROUP BY to aggregate multiple rows into JSON arrays.
|
|
114
|
+
* Excludes array-internal columns from GROUP BY to prevent over-grouping.
|
|
139
115
|
*
|
|
140
116
|
* @param infos Array entities at this depth level
|
|
141
117
|
* @param currentCteAlias Alias of the CTE to build upon
|
|
142
118
|
* @param currentCtes All CTEs built so far
|
|
143
119
|
* @param depth Current depth level being processed
|
|
144
120
|
* @param mapping JSON mapping configuration
|
|
121
|
+
* @param columnMappings Optional mappings from object entity IDs to generated JSON column names
|
|
145
122
|
* @returns The new CTE and its alias
|
|
146
123
|
*/
|
|
147
|
-
buildDepthCte(infos, currentCteAlias, currentCtes, depth, mapping) {
|
|
124
|
+
buildDepthCte(infos, currentCteAlias, currentCtes, depth, mapping, columnMappings) {
|
|
148
125
|
var _a;
|
|
149
126
|
// Collect columns that will be compressed into arrays
|
|
150
127
|
// This includes both direct columns and columns from nested entities within the array
|
|
@@ -183,12 +160,28 @@ export class PostgresArrayEntityCteBuilder {
|
|
|
183
160
|
});
|
|
184
161
|
// Collect array entity columns organized by depth for GROUP BY exclusion strategy
|
|
185
162
|
const arrayEntityColumns = this.collectArrayEntityColumnsByDepth(mapping, depth);
|
|
163
|
+
// Identify JSON columns from objects within the arrays being processed at this depth
|
|
164
|
+
const arrayInternalObjectColumns = new Set();
|
|
165
|
+
if (columnMappings) {
|
|
166
|
+
infos.forEach(info => {
|
|
167
|
+
// Find all object-type nested entities within this array entity
|
|
168
|
+
mapping.nestedEntities
|
|
169
|
+
.filter(ne => ne.parentId === info.entity.id && ne.relationshipType === "object")
|
|
170
|
+
.forEach(objectEntity => {
|
|
171
|
+
// Find the corresponding JSON column mapping for this object entity
|
|
172
|
+
const columnMapping = columnMappings.find(cm => cm.entityId === objectEntity.id);
|
|
173
|
+
if (columnMapping) {
|
|
174
|
+
arrayInternalObjectColumns.add(columnMapping.generatedColumnName);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
}
|
|
186
179
|
// Process existing SELECT variables to determine which should be included in GROUP BY
|
|
187
|
-
this.processSelectVariablesForGroupBy(prevSelects, arrayColumns, arrayEntityColumns, depth, selectItems, groupByItems);
|
|
180
|
+
this.processSelectVariablesForGroupBy(prevSelects, arrayColumns, arrayEntityColumns, depth, selectItems, groupByItems, arrayInternalObjectColumns);
|
|
188
181
|
// Add JSON aggregation columns for each array entity at this depth
|
|
189
182
|
for (const info of infos) {
|
|
190
|
-
const agg = this.buildAggregationDetailsForArrayEntity(info.entity, mapping.nestedEntities, new Map() // allEntities - not needed for array aggregation
|
|
191
|
-
);
|
|
183
|
+
const agg = this.buildAggregationDetailsForArrayEntity(info.entity, mapping.nestedEntities, new Map(), // allEntities - not needed for array aggregation
|
|
184
|
+
columnMappings);
|
|
192
185
|
selectItems.push(new SelectItem(agg.jsonAgg, info.entity.propertyName));
|
|
193
186
|
}
|
|
194
187
|
// Create the new CTE
|
|
@@ -202,20 +195,19 @@ export class PostgresArrayEntityCteBuilder {
|
|
|
202
195
|
return { cte, newCteAlias: cteAlias };
|
|
203
196
|
}
|
|
204
197
|
/**
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
* the entity's columns into a JSON array. It also handles nested relationships
|
|
209
|
-
* by including child entity properties in the JSON object.
|
|
198
|
+
* Creates jsonb_agg function for array entity.
|
|
199
|
+
* Handles entity columns and nested child relationships.
|
|
200
|
+
* Uses originalPropertyName to avoid sequential numbering.
|
|
210
201
|
*
|
|
211
202
|
* @param entity The array entity being processed
|
|
212
203
|
* @param nestedEntities All nested entities from the mapping
|
|
213
204
|
* @param allEntities Map of all entities (not used in current implementation)
|
|
205
|
+
* @param columnMappings Mappings from object entity IDs to generated JSON column names
|
|
214
206
|
* @returns Object containing the JSON aggregation function
|
|
215
207
|
*/
|
|
216
|
-
buildAggregationDetailsForArrayEntity(entity, nestedEntities, allEntities) {
|
|
208
|
+
buildAggregationDetailsForArrayEntity(entity, nestedEntities, allEntities, columnMappings) {
|
|
217
209
|
// Build JSON object for array elements using JSONB functions
|
|
218
|
-
const jsonBuildFunction =
|
|
210
|
+
const jsonBuildFunction = PostgresArrayEntityCteBuilder.JSON_FUNCTIONS.BUILD_OBJECT;
|
|
219
211
|
const args = [];
|
|
220
212
|
// Add the entity's own columns
|
|
221
213
|
Object.entries(entity.columns).forEach(([jsonKey, sqlColumn]) => {
|
|
@@ -225,12 +217,54 @@ export class PostgresArrayEntityCteBuilder {
|
|
|
225
217
|
// Find and process child entities (both object and array types)
|
|
226
218
|
const childEntities = nestedEntities.filter((ne) => ne.parentId === entity.id);
|
|
227
219
|
childEntities.forEach((childEntity) => {
|
|
228
|
-
|
|
220
|
+
// Use originalPropertyName if available to avoid sequential numbering in final JSON
|
|
221
|
+
const propertyNameForJson = childEntity.originalPropertyName || childEntity.propertyName;
|
|
222
|
+
args.push(new LiteralValue(propertyNameForJson));
|
|
229
223
|
if (childEntity.relationshipType === "object") {
|
|
230
|
-
// For object relationships, use pre-computed JSON column
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
224
|
+
// For object relationships, use pre-computed JSON column from column mappings
|
|
225
|
+
if (!columnMappings) {
|
|
226
|
+
throw new Error(`❌ PostgresArrayEntityCteBuilder Error: Column mappings not provided\n` +
|
|
227
|
+
`\n` +
|
|
228
|
+
`🔍 Details:\n` +
|
|
229
|
+
` - Entity ID: ${childEntity.id}\n` +
|
|
230
|
+
` - Entity Name: ${childEntity.name || 'unknown'}\n` +
|
|
231
|
+
` - Property Name: ${childEntity.propertyName}\n` +
|
|
232
|
+
` - Relationship Type: ${childEntity.relationshipType}\n` +
|
|
233
|
+
`\n` +
|
|
234
|
+
`💡 Solution:\n` +
|
|
235
|
+
` Column mappings are required for hybrid JSON column naming.\n` +
|
|
236
|
+
` This error indicates that PostgresObjectEntityCteBuilder did not\n` +
|
|
237
|
+
` pass column mappings to PostgresArrayEntityCteBuilder.\n` +
|
|
238
|
+
`\n` +
|
|
239
|
+
`🔧 Check:\n` +
|
|
240
|
+
` 1. Ensure PostgresJsonQueryBuilder.buildJsonWithCteStrategy() passes columnMappings\n` +
|
|
241
|
+
` 2. Verify PostgresObjectEntityCteBuilder.buildObjectEntityCtes() returns columnMappings\n` +
|
|
242
|
+
` 3. Check that Model-driven mapping conversion generates unique entity IDs`);
|
|
243
|
+
}
|
|
244
|
+
const mapping = columnMappings.find(m => m.entityId === childEntity.id);
|
|
245
|
+
if (!mapping) {
|
|
246
|
+
const availableMappings = columnMappings.map(m => `${m.entityId} → ${m.generatedColumnName}`).join(', ');
|
|
247
|
+
throw new Error(`❌ PostgresArrayEntityCteBuilder Error: Column mapping not found\n` +
|
|
248
|
+
`\n` +
|
|
249
|
+
`🔍 Details:\n` +
|
|
250
|
+
` - Looking for Entity ID: ${childEntity.id}\n` +
|
|
251
|
+
` - Entity Name: ${childEntity.name || 'unknown'}\n` +
|
|
252
|
+
` - Property Name: ${childEntity.propertyName}\n` +
|
|
253
|
+
` - Relationship Type: ${childEntity.relationshipType}\n` +
|
|
254
|
+
`\n` +
|
|
255
|
+
`📋 Available Mappings:\n` +
|
|
256
|
+
` ${availableMappings || 'None'}\n` +
|
|
257
|
+
`\n` +
|
|
258
|
+
`💡 Solution:\n` +
|
|
259
|
+
` Entity IDs must match between mapping generation and usage.\n` +
|
|
260
|
+
` This suggests a mismatch in entity ID generation or processing.\n` +
|
|
261
|
+
`\n` +
|
|
262
|
+
`🔧 Check:\n` +
|
|
263
|
+
` 1. Model-driven mapping conversion generates consistent entity IDs\n` +
|
|
264
|
+
` 2. PostgresObjectEntityCteBuilder processes all entities correctly\n` +
|
|
265
|
+
` 3. Entity hierarchy and parentId relationships are correct`);
|
|
266
|
+
}
|
|
267
|
+
args.push(new ColumnReference(null, new IdentifierString(mapping.generatedColumnName)));
|
|
234
268
|
}
|
|
235
269
|
else if (childEntity.relationshipType === "array") {
|
|
236
270
|
// For array relationships, use the column directly
|
|
@@ -241,7 +275,7 @@ export class PostgresArrayEntityCteBuilder {
|
|
|
241
275
|
const jsonObject = new FunctionCall(null, new RawString(jsonBuildFunction), new ValueList(args), null);
|
|
242
276
|
// Create JSON aggregation using JSONB with NULL filtering
|
|
243
277
|
// Use FILTER clause to exclude rows where primary key is NULL (no actual data)
|
|
244
|
-
const jsonAggFunction =
|
|
278
|
+
const jsonAggFunction = PostgresArrayEntityCteBuilder.JSON_FUNCTIONS.AGGREGATE;
|
|
245
279
|
// Find the primary column (typically the first column) to use for NULL filtering
|
|
246
280
|
const primaryColumn = Object.values(entity.columns)[0];
|
|
247
281
|
// For now, create standard jsonb_agg and handle NULL filtering in post-processing
|
|
@@ -250,11 +284,7 @@ export class PostgresArrayEntityCteBuilder {
|
|
|
250
284
|
return { jsonAgg };
|
|
251
285
|
}
|
|
252
286
|
/**
|
|
253
|
-
* Collects array entity columns
|
|
254
|
-
*
|
|
255
|
-
* This method creates a mapping from depth levels to sets of column names that belong to
|
|
256
|
-
* array entities at each depth. This is used to determine which columns should be excluded
|
|
257
|
-
* from GROUP BY clauses when performing array aggregation at specific depths.
|
|
287
|
+
* Collects array entity columns by depth for GROUP BY exclusion strategy.
|
|
258
288
|
*
|
|
259
289
|
* @param mapping The JSON mapping configuration containing all entities
|
|
260
290
|
* @param currentDepth The current aggregation depth being processed
|
|
@@ -263,7 +293,7 @@ export class PostgresArrayEntityCteBuilder {
|
|
|
263
293
|
collectArrayEntityColumnsByDepth(mapping, currentDepth) {
|
|
264
294
|
const arrayEntitiesByDepth = new Map(); // Initialize depth maps for current and deeper levels
|
|
265
295
|
// Use a reasonable maximum depth limit to avoid infinite loops
|
|
266
|
-
const maxDepth = Math.max(currentDepth + 3, 5);
|
|
296
|
+
const maxDepth = Math.max(currentDepth + 3, 5);
|
|
267
297
|
for (let d = currentDepth; d <= maxDepth; d++) {
|
|
268
298
|
arrayEntitiesByDepth.set(d, new Set());
|
|
269
299
|
}
|
|
@@ -284,7 +314,7 @@ export class PostgresArrayEntityCteBuilder {
|
|
|
284
314
|
return arrayEntitiesByDepth;
|
|
285
315
|
}
|
|
286
316
|
/**
|
|
287
|
-
* Calculates
|
|
317
|
+
* Calculates entity depth by traversing up to root.
|
|
288
318
|
*
|
|
289
319
|
* @param entity The entity to calculate depth for
|
|
290
320
|
* @param mapping The JSON mapping containing all entities
|
|
@@ -300,7 +330,7 @@ export class PostgresArrayEntityCteBuilder {
|
|
|
300
330
|
return entityDepth;
|
|
301
331
|
}
|
|
302
332
|
/**
|
|
303
|
-
* Adds
|
|
333
|
+
* Adds entity columns to depth set.
|
|
304
334
|
*
|
|
305
335
|
* @param entity The entity whose columns should be added
|
|
306
336
|
* @param depth The depth level to add columns to
|
|
@@ -313,10 +343,7 @@ export class PostgresArrayEntityCteBuilder {
|
|
|
313
343
|
});
|
|
314
344
|
}
|
|
315
345
|
/**
|
|
316
|
-
* Recursively collects columns from
|
|
317
|
-
*
|
|
318
|
-
* This method ensures that all nested entities (at any depth) under an array entity
|
|
319
|
-
* have their columns properly categorized by the array entity's depth level.
|
|
346
|
+
* Recursively collects columns from descendant entities.
|
|
320
347
|
*
|
|
321
348
|
* @param parentEntityId The ID of the parent entity
|
|
322
349
|
* @param targetDepth The depth level to assign collected columns to
|
|
@@ -334,11 +361,8 @@ export class PostgresArrayEntityCteBuilder {
|
|
|
334
361
|
});
|
|
335
362
|
}
|
|
336
363
|
/**
|
|
337
|
-
*
|
|
338
|
-
*
|
|
339
|
-
* This method implements the core logic for deciding which columns from previous CTEs
|
|
340
|
-
* should be included in the GROUP BY clause when performing array aggregation. It handles
|
|
341
|
-
* special cases for JSON columns and applies depth-based filtering to prevent over-grouping.
|
|
364
|
+
* Implements GROUP BY exclusion strategy for array aggregation.
|
|
365
|
+
* Excludes current array columns and array-internal object JSON columns.
|
|
342
366
|
*
|
|
343
367
|
* @param prevSelects SELECT variables from the previous CTE
|
|
344
368
|
* @param arrayColumns Columns that are being aggregated (should be excluded from GROUP BY)
|
|
@@ -346,24 +370,30 @@ export class PostgresArrayEntityCteBuilder {
|
|
|
346
370
|
* @param currentDepth The current aggregation depth being processed
|
|
347
371
|
* @param selectItems Output array for SELECT items
|
|
348
372
|
* @param groupByItems Output array for GROUP BY items
|
|
373
|
+
* @param arrayInternalObjectColumns JSON columns from objects within arrays being processed
|
|
349
374
|
*/
|
|
350
|
-
processSelectVariablesForGroupBy(prevSelects, arrayColumns, arrayEntitiesByDepth, currentDepth, selectItems, groupByItems) {
|
|
375
|
+
processSelectVariablesForGroupBy(prevSelects, arrayColumns, arrayEntitiesByDepth, currentDepth, selectItems, groupByItems, arrayInternalObjectColumns) {
|
|
351
376
|
prevSelects.forEach(sv => {
|
|
352
377
|
if (!arrayColumns.has(sv.name)) {
|
|
378
|
+
// Exclude JSON columns from objects within arrays being processed
|
|
379
|
+
if (arrayInternalObjectColumns && arrayInternalObjectColumns.has(sv.name)) {
|
|
380
|
+
// Skip this column - it's an object within the array being aggregated
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
353
383
|
const shouldInclude = this.shouldIncludeColumnInGroupBy(sv.name, arrayEntitiesByDepth, currentDepth);
|
|
354
384
|
if (shouldInclude) {
|
|
355
385
|
selectItems.push(new SelectItem(new ColumnReference(null, new IdentifierString(sv.name)), sv.name));
|
|
356
|
-
|
|
386
|
+
// Exclude JSON columns from GROUP BY as PostgreSQL doesn't support equality operators for JSON type
|
|
387
|
+
if (!sv.name.endsWith('_json')) {
|
|
388
|
+
groupByItems.push(new ColumnReference(null, new IdentifierString(sv.name)));
|
|
389
|
+
}
|
|
357
390
|
}
|
|
358
391
|
}
|
|
359
392
|
});
|
|
360
393
|
}
|
|
361
394
|
/**
|
|
362
|
-
* Determines
|
|
363
|
-
*
|
|
364
|
-
* This method applies depth-based filtering and special handling for JSON columns
|
|
365
|
-
* to prevent over-grouping during array aggregation. It implements heuristics for
|
|
366
|
-
* excluding columns that belong to nested entities within array contexts.
|
|
395
|
+
* Determines if column should be included in GROUP BY clause.
|
|
396
|
+
* Applies depth-based filtering and special handling for JSON columns.
|
|
367
397
|
*
|
|
368
398
|
* @param columnName The name of the column to evaluate
|
|
369
399
|
* @param arrayEntitiesByDepth Map of depth levels to their column sets
|
|
@@ -381,19 +411,19 @@ export class PostgresArrayEntityCteBuilder {
|
|
|
381
411
|
break;
|
|
382
412
|
}
|
|
383
413
|
}
|
|
384
|
-
//
|
|
385
|
-
|
|
386
|
-
|
|
414
|
+
// Critical: JSON columns from objects within arrays being processed
|
|
415
|
+
// must be excluded from GROUP BY as they are aggregated within the array
|
|
416
|
+
if (isJsonColumn) {
|
|
417
|
+
// Legacy handling for entity_ prefixed JSON columns
|
|
418
|
+
if (columnName.startsWith('entity_')) {
|
|
419
|
+
shouldInclude = this.shouldIncludeJsonColumn(columnName, currentDepth);
|
|
420
|
+
}
|
|
387
421
|
}
|
|
388
|
-
|
|
389
|
-
return shouldInclude || (isJsonColumn && !columnName.startsWith('entity_'));
|
|
422
|
+
return shouldInclude;
|
|
390
423
|
}
|
|
391
424
|
/**
|
|
392
|
-
* Applies heuristics
|
|
393
|
-
*
|
|
394
|
-
* This method uses entity numbering patterns to identify deeply nested entities
|
|
395
|
-
* that should be excluded from GROUP BY when processing array aggregations.
|
|
396
|
-
* This is a simplified heuristic approach that works for current use cases.
|
|
425
|
+
* Applies heuristics for entity JSON column inclusion in GROUP BY.
|
|
426
|
+
* Uses entity numbering patterns to identify deeply nested entities.
|
|
397
427
|
*
|
|
398
428
|
* @param columnName The JSON column name (expected format: entity_N_json)
|
|
399
429
|
* @param currentDepth The current aggregation depth
|
|
@@ -416,4 +446,9 @@ export class PostgresArrayEntityCteBuilder {
|
|
|
416
446
|
}
|
|
417
447
|
// Constants for consistent naming conventions
|
|
418
448
|
PostgresArrayEntityCteBuilder.CTE_ARRAY_PREFIX = 'cte_array_depth_';
|
|
449
|
+
// JSON function names for PostgreSQL aggregation
|
|
450
|
+
PostgresArrayEntityCteBuilder.JSON_FUNCTIONS = {
|
|
451
|
+
BUILD_OBJECT: 'jsonb_build_object',
|
|
452
|
+
AGGREGATE: 'jsonb_agg'
|
|
453
|
+
};
|
|
419
454
|
//# sourceMappingURL=PostgresArrayEntityCteBuilder.js.map
|