rawsql-ts 0.9.0-beta → 0.10.1-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.
Files changed (56) hide show
  1. package/README.md +90 -7
  2. package/dist/esm/index.js +2 -0
  3. package/dist/esm/index.js.map +1 -1
  4. package/dist/esm/models/SqlPrintToken.js +2 -0
  5. package/dist/esm/models/SqlPrintToken.js.map +1 -1
  6. package/dist/esm/models/ValueComponent.js +13 -12
  7. package/dist/esm/models/ValueComponent.js.map +1 -1
  8. package/dist/esm/parsers/SqlPrintTokenParser.js +24 -6
  9. package/dist/esm/parsers/SqlPrintTokenParser.js.map +1 -1
  10. package/dist/esm/transformers/PostgresArrayEntityCteBuilder.js +231 -0
  11. package/dist/esm/transformers/PostgresArrayEntityCteBuilder.js.map +1 -0
  12. package/dist/esm/transformers/PostgresJsonQueryBuilder.js +226 -0
  13. package/dist/esm/transformers/PostgresJsonQueryBuilder.js.map +1 -0
  14. package/dist/esm/transformers/PostgresObjectEntityCteBuilder.js +283 -0
  15. package/dist/esm/transformers/PostgresObjectEntityCteBuilder.js.map +1 -0
  16. package/dist/esm/transformers/SqlPrinter.js +9 -3
  17. package/dist/esm/transformers/SqlPrinter.js.map +1 -1
  18. package/dist/esm/types/index.d.ts +2 -0
  19. package/dist/esm/types/models/SqlPrintToken.d.ts +2 -0
  20. package/dist/esm/types/models/ValueComponent.d.ts +2 -2
  21. package/dist/esm/types/transformers/PostgresArrayEntityCteBuilder.d.ts +97 -0
  22. package/dist/esm/types/transformers/PostgresJsonQueryBuilder.d.ts +86 -0
  23. package/dist/esm/types/transformers/PostgresObjectEntityCteBuilder.d.ts +140 -0
  24. package/dist/esm/types/utils/SchemaManager.d.ts +132 -0
  25. package/dist/esm/utils/SchemaManager.js +194 -0
  26. package/dist/esm/utils/SchemaManager.js.map +1 -0
  27. package/dist/index.d.ts +2 -0
  28. package/dist/index.js +2 -0
  29. package/dist/index.js.map +1 -1
  30. package/dist/models/SqlPrintToken.d.ts +2 -0
  31. package/dist/models/SqlPrintToken.js +2 -0
  32. package/dist/models/SqlPrintToken.js.map +1 -1
  33. package/dist/models/ValueComponent.d.ts +2 -2
  34. package/dist/models/ValueComponent.js +13 -12
  35. package/dist/models/ValueComponent.js.map +1 -1
  36. package/dist/parsers/SelectQueryParser.js +3 -14
  37. package/dist/parsers/SelectQueryParser.js.map +1 -1
  38. package/dist/parsers/SqlPrintTokenParser.js +25 -7
  39. package/dist/parsers/SqlPrintTokenParser.js.map +1 -1
  40. package/dist/transformers/PostgresArrayEntityCteBuilder.d.ts +97 -0
  41. package/dist/transformers/PostgresArrayEntityCteBuilder.js +235 -0
  42. package/dist/transformers/PostgresArrayEntityCteBuilder.js.map +1 -0
  43. package/dist/transformers/PostgresJsonQueryBuilder.d.ts +86 -0
  44. package/dist/transformers/PostgresJsonQueryBuilder.js +230 -0
  45. package/dist/transformers/PostgresJsonQueryBuilder.js.map +1 -0
  46. package/dist/transformers/PostgresObjectEntityCteBuilder.d.ts +140 -0
  47. package/dist/transformers/PostgresObjectEntityCteBuilder.js +287 -0
  48. package/dist/transformers/PostgresObjectEntityCteBuilder.js.map +1 -0
  49. package/dist/transformers/SqlFormatter.js +6 -1
  50. package/dist/transformers/SqlFormatter.js.map +1 -1
  51. package/dist/transformers/SqlPrinter.js +9 -3
  52. package/dist/transformers/SqlPrinter.js.map +1 -1
  53. package/dist/utils/SchemaManager.d.ts +132 -0
  54. package/dist/utils/SchemaManager.js +201 -0
  55. package/dist/utils/SchemaManager.js.map +1 -0
  56. package/package.json +1 -1
@@ -0,0 +1,97 @@
1
+ import { CommonTable } from '../models/Clause';
2
+ import { JsonMapping } from './PostgresJsonQueryBuilder';
3
+ import { ProcessableEntity } from './PostgresObjectEntityCteBuilder';
4
+ /**
5
+ * PostgreSQL-specific builder for creating CTEs for array entities (array relationships).
6
+ * This class handles the creation of CTEs that build JSON/JSONB arrays for child entities,
7
+ * processing them from the deepest level up to ensure proper dependency ordering.
8
+ *
9
+ * Features:
10
+ * - Depth-based CTE naming (cte_array_depth_N)
11
+ * - Row compression using GROUP BY operations
12
+ * - JSONB/JSON array aggregation
13
+ * - Hierarchical processing of nested arrays
14
+ * - Column exclusion to avoid duplication
15
+ *
16
+ * Why depth calculation is critical:
17
+ * 1. Array entities can be nested at multiple levels. We must process the deepest
18
+ * (most distant) arrays first to ensure their JSON representations are available
19
+ * when building their parent arrays.
20
+ * 2. Array entity processing is essentially a row compression operation using GROUP BY.
21
+ * Unlike parent entities which use column compression, arrays require grouping
22
+ * to aggregate multiple rows into JSON arrays.
23
+ *
24
+ * Example hierarchy:
25
+ * Order (root, depth 0)
26
+ * └─ Items (array, depth 1)
27
+ * └─ Details (array, depth 2)
28
+ *
29
+ * Processing order: depth 2 → depth 1 → depth 0
30
+ */
31
+ export declare class PostgresArrayEntityCteBuilder {
32
+ private static readonly CTE_ARRAY_PREFIX;
33
+ /**
34
+ * Build CTEs for all array entities in the correct dependency order
35
+ * @param ctesSoFar Array of CTEs built so far (starts with the initial CTE)
36
+ * @param aliasOfCteToBuildUpon Alias of the CTE from which the current array CTE will select
37
+ * @param allEntities Map of all entities in the mapping
38
+ * @param mapping The JSON mapping configuration
39
+ * @returns Object containing the updated list of all CTEs and the alias of the last CTE created
40
+ */
41
+ buildArrayEntityCtes(ctesSoFar: CommonTable[], aliasOfCteToBuildUpon: string, allEntities: Map<string, ProcessableEntity>, mapping: JsonMapping): {
42
+ updatedCtes: CommonTable[];
43
+ lastCteAlias: string;
44
+ };
45
+ /**
46
+ * Collect all array entities and calculate their depth from root.
47
+ *
48
+ * Depth calculation ensures proper processing order where deeper nested
49
+ * arrays are processed first, making their aggregated data available
50
+ * for parent array processing.
51
+ *
52
+ * @param mapping The JSON mapping configuration
53
+ * @param allEntities Map of all entities in the mapping
54
+ * @returns Array of array entity information with calculated depths, sorted deepest first
55
+ */
56
+ private collectAndSortArrayEntities;
57
+ /**
58
+ * Group array entities by their depth level.
59
+ *
60
+ * Grouping by depth allows us to:
61
+ * - Process all entities at the same level in a single CTE
62
+ * - Optimize query performance by reducing the number of CTEs
63
+ * - Maintain clear dependency ordering
64
+ *
65
+ * @param arrayInfos Array of array entity information with depths
66
+ * @returns Map of depth level to entities at that depth
67
+ */
68
+ private groupEntitiesByDepth;
69
+ /**
70
+ * Build a CTE that processes all array entities at a specific depth level.
71
+ *
72
+ * This method creates a single CTE that aggregates multiple array entities
73
+ * at the same depth, using GROUP BY to compress rows into JSON arrays.
74
+ *
75
+ * @param infos Array entities at this depth level
76
+ * @param currentCteAlias Alias of the CTE to build upon
77
+ * @param currentCtes All CTEs built so far
78
+ * @param depth Current depth level being processed
79
+ * @param mapping JSON mapping configuration
80
+ * @returns The new CTE and its alias
81
+ */
82
+ private buildDepthCte;
83
+ /**
84
+ * Build JSON aggregation function for an array entity.
85
+ *
86
+ * This method creates a jsonb_agg or json_agg function call that aggregates
87
+ * the entity's columns into a JSON array. It also handles nested relationships
88
+ * by including child entity properties in the JSON object.
89
+ *
90
+ * @param entity The array entity being processed
91
+ * @param nestedEntities All nested entities from the mapping
92
+ * @param allEntities Map of all entities (not used in current implementation)
93
+ * @param useJsonb Whether to use JSONB functions
94
+ * @returns Object containing the JSON aggregation function
95
+ */
96
+ private buildAggregationDetailsForArrayEntity;
97
+ }
@@ -0,0 +1,235 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PostgresArrayEntityCteBuilder = void 0;
4
+ const Clause_1 = require("../models/Clause");
5
+ const SimpleSelectQuery_1 = require("../models/SimpleSelectQuery");
6
+ const ValueComponent_1 = require("../models/ValueComponent");
7
+ const SelectValueCollector_1 = require("./SelectValueCollector");
8
+ /**
9
+ * PostgreSQL-specific builder for creating CTEs for array entities (array relationships).
10
+ * This class handles the creation of CTEs that build JSON/JSONB arrays for child entities,
11
+ * processing them from the deepest level up to ensure proper dependency ordering.
12
+ *
13
+ * Features:
14
+ * - Depth-based CTE naming (cte_array_depth_N)
15
+ * - Row compression using GROUP BY operations
16
+ * - JSONB/JSON array aggregation
17
+ * - Hierarchical processing of nested arrays
18
+ * - Column exclusion to avoid duplication
19
+ *
20
+ * Why depth calculation is critical:
21
+ * 1. Array entities can be nested at multiple levels. We must process the deepest
22
+ * (most distant) arrays first to ensure their JSON representations are available
23
+ * when building their parent arrays.
24
+ * 2. Array entity processing is essentially a row compression operation using GROUP BY.
25
+ * Unlike parent entities which use column compression, arrays require grouping
26
+ * to aggregate multiple rows into JSON arrays.
27
+ *
28
+ * Example hierarchy:
29
+ * Order (root, depth 0)
30
+ * └─ Items (array, depth 1)
31
+ * └─ Details (array, depth 2)
32
+ *
33
+ * Processing order: depth 2 → depth 1 → depth 0
34
+ */
35
+ class PostgresArrayEntityCteBuilder {
36
+ /**
37
+ * Build CTEs for all array entities in the correct dependency order
38
+ * @param ctesSoFar Array of CTEs built so far (starts with the initial CTE)
39
+ * @param aliasOfCteToBuildUpon Alias of the CTE from which the current array CTE will select
40
+ * @param allEntities Map of all entities in the mapping
41
+ * @param mapping The JSON mapping configuration
42
+ * @returns Object containing the updated list of all CTEs and the alias of the last CTE created
43
+ */
44
+ buildArrayEntityCtes(ctesSoFar, aliasOfCteToBuildUpon, allEntities, mapping) {
45
+ let currentCtes = [...ctesSoFar];
46
+ let currentCteAlias = aliasOfCteToBuildUpon;
47
+ // Collect and sort array entities by depth
48
+ const sortedArrayInfos = this.collectAndSortArrayEntities(mapping, allEntities);
49
+ if (sortedArrayInfos.length === 0) {
50
+ return { updatedCtes: currentCtes, lastCteAlias: currentCteAlias };
51
+ }
52
+ // Group array entities by depth level for batch processing
53
+ const entitiesByDepth = this.groupEntitiesByDepth(sortedArrayInfos);
54
+ // Process from deepest to shallowest (depth-first)
55
+ const depths = Array.from(entitiesByDepth.keys()).sort((a, b) => b - a);
56
+ for (const depth of depths) {
57
+ const infos = entitiesByDepth.get(depth);
58
+ // Build CTE for all entities at this depth
59
+ const { cte, newCteAlias } = this.buildDepthCte(infos, currentCteAlias, currentCtes, depth, mapping);
60
+ currentCtes.push(cte);
61
+ currentCteAlias = newCteAlias;
62
+ }
63
+ return { updatedCtes: currentCtes, lastCteAlias: currentCteAlias };
64
+ }
65
+ /**
66
+ * Collect all array entities and calculate their depth from root.
67
+ *
68
+ * Depth calculation ensures proper processing order where deeper nested
69
+ * arrays are processed first, making their aggregated data available
70
+ * for parent array processing.
71
+ *
72
+ * @param mapping The JSON mapping configuration
73
+ * @param allEntities Map of all entities in the mapping
74
+ * @returns Array of array entity information with calculated depths, sorted deepest first
75
+ */
76
+ collectAndSortArrayEntities(mapping, allEntities) {
77
+ const arrayEntityInfos = [];
78
+ // Helper function to calculate depth for an entity
79
+ const getDepth = (entityId) => {
80
+ const entity = allEntities.get(entityId);
81
+ if (!entity || entity.isRoot)
82
+ return 0;
83
+ if (!entity.parentId)
84
+ return 1;
85
+ return 1 + getDepth(entity.parentId);
86
+ };
87
+ // Collect all array-type nested entities
88
+ mapping.nestedEntities.forEach(ne => {
89
+ if (ne.relationshipType === "array") {
90
+ const currentArrayEntity = allEntities.get(ne.id);
91
+ const parentEntity = allEntities.get(ne.parentId);
92
+ if (!currentArrayEntity || !parentEntity) {
93
+ throw new Error(`Configuration error: Array entity '${ne.id}' or its parent '${ne.parentId}' not found.`);
94
+ }
95
+ // Determine the linking column from parent entity
96
+ // This assumes the first column of the parent is a suitable key for linking.
97
+ // More robust linking might require explicit configuration in the mapping.
98
+ const parentSqlColumns = Object.values(parentEntity.columns);
99
+ if (parentSqlColumns.length === 0) {
100
+ throw new Error(`Configuration error: Parent entity '${parentEntity.name}' (ID: ${parentEntity.id}) must have at least one column defined to serve as a linking key for child array '${ne.name}'.`);
101
+ }
102
+ const parentIdColumnSqlName = parentSqlColumns[0];
103
+ arrayEntityInfos.push({
104
+ entity: currentArrayEntity,
105
+ parentEntity: parentEntity,
106
+ parentIdColumnSqlName: parentIdColumnSqlName,
107
+ depth: getDepth(ne.id)
108
+ });
109
+ }
110
+ });
111
+ // Sort by depth, deepest arrays (higher depth number) processed first (bottom-up for arrays)
112
+ arrayEntityInfos.sort((a, b) => b.depth - a.depth);
113
+ return arrayEntityInfos;
114
+ }
115
+ /**
116
+ * Group array entities by their depth level.
117
+ *
118
+ * Grouping by depth allows us to:
119
+ * - Process all entities at the same level in a single CTE
120
+ * - Optimize query performance by reducing the number of CTEs
121
+ * - Maintain clear dependency ordering
122
+ *
123
+ * @param arrayInfos Array of array entity information with depths
124
+ * @returns Map of depth level to entities at that depth
125
+ */
126
+ groupEntitiesByDepth(arrayInfos) {
127
+ const entitiesByDepth = new Map();
128
+ arrayInfos.forEach(info => {
129
+ const depth = info.depth;
130
+ if (!entitiesByDepth.has(depth)) {
131
+ entitiesByDepth.set(depth, []);
132
+ }
133
+ entitiesByDepth.get(depth).push(info);
134
+ });
135
+ return entitiesByDepth;
136
+ }
137
+ /**
138
+ * Build a CTE that processes all array entities at a specific depth level.
139
+ *
140
+ * This method creates a single CTE that aggregates multiple array entities
141
+ * at the same depth, using GROUP BY to compress rows into JSON arrays.
142
+ *
143
+ * @param infos Array entities at this depth level
144
+ * @param currentCteAlias Alias of the CTE to build upon
145
+ * @param currentCtes All CTEs built so far
146
+ * @param depth Current depth level being processed
147
+ * @param mapping JSON mapping configuration
148
+ * @returns The new CTE and its alias
149
+ */
150
+ buildDepthCte(infos, currentCteAlias, currentCtes, depth, mapping) {
151
+ var _a;
152
+ // Collect columns that will be compressed into arrays
153
+ const arrayColumns = new Set();
154
+ infos.forEach(info => {
155
+ Object.values(info.entity.columns).forEach(col => arrayColumns.add(col));
156
+ });
157
+ // Get columns from previous CTE
158
+ const prevCte = (_a = currentCtes.find(c => c.aliasExpression.table.name === currentCteAlias)) === null || _a === void 0 ? void 0 : _a.query;
159
+ if (!prevCte) {
160
+ throw new Error(`CTE not found: ${currentCteAlias}`);
161
+ }
162
+ const prevSelects = new SelectValueCollector_1.SelectValueCollector(null, currentCtes).collect(prevCte);
163
+ // Build SELECT items: columns that are NOT being compressed (for GROUP BY)
164
+ const groupByItems = [];
165
+ const selectItems = [];
166
+ prevSelects.forEach(sv => {
167
+ if (!arrayColumns.has(sv.name)) {
168
+ selectItems.push(new Clause_1.SelectItem(new ValueComponent_1.ColumnReference(null, new ValueComponent_1.IdentifierString(sv.name)), sv.name));
169
+ groupByItems.push(new ValueComponent_1.ColumnReference(null, new ValueComponent_1.IdentifierString(sv.name)));
170
+ }
171
+ });
172
+ // Add JSON aggregation columns for each array entity at this depth
173
+ for (const info of infos) {
174
+ const agg = this.buildAggregationDetailsForArrayEntity(info.entity, mapping.nestedEntities, new Map(), // allEntities - not needed for array aggregation
175
+ mapping.useJsonb);
176
+ selectItems.push(new Clause_1.SelectItem(agg.jsonAgg, info.entity.propertyName));
177
+ }
178
+ // Create the new CTE
179
+ const cteAlias = `${PostgresArrayEntityCteBuilder.CTE_ARRAY_PREFIX}${depth}`;
180
+ const cteSelect = new SimpleSelectQuery_1.SimpleSelectQuery({
181
+ selectClause: new Clause_1.SelectClause(selectItems),
182
+ fromClause: new Clause_1.FromClause(new Clause_1.SourceExpression(new Clause_1.TableSource(null, new ValueComponent_1.IdentifierString(currentCteAlias)), null), null),
183
+ groupByClause: groupByItems.length > 0 ? new Clause_1.GroupByClause(groupByItems) : null,
184
+ });
185
+ const cte = new Clause_1.CommonTable(cteSelect, new Clause_1.SourceAliasExpression(cteAlias, null), null);
186
+ return { cte, newCteAlias: cteAlias };
187
+ }
188
+ /**
189
+ * Build JSON aggregation function for an array entity.
190
+ *
191
+ * This method creates a jsonb_agg or json_agg function call that aggregates
192
+ * the entity's columns into a JSON array. It also handles nested relationships
193
+ * by including child entity properties in the JSON object.
194
+ *
195
+ * @param entity The array entity being processed
196
+ * @param nestedEntities All nested entities from the mapping
197
+ * @param allEntities Map of all entities (not used in current implementation)
198
+ * @param useJsonb Whether to use JSONB functions
199
+ * @returns Object containing the JSON aggregation function
200
+ */
201
+ buildAggregationDetailsForArrayEntity(entity, nestedEntities, allEntities, useJsonb = false) {
202
+ // Build JSON object for array elements
203
+ const jsonBuildFunction = useJsonb ? "jsonb_build_object" : "json_build_object";
204
+ const args = [];
205
+ // Add the entity's own columns
206
+ Object.entries(entity.columns).forEach(([jsonKey, sqlColumn]) => {
207
+ args.push(new ValueComponent_1.LiteralValue(jsonKey));
208
+ args.push(new ValueComponent_1.ColumnReference(null, new ValueComponent_1.IdentifierString(sqlColumn)));
209
+ });
210
+ // Find and process child entities (both object and array types)
211
+ const childEntities = nestedEntities.filter((ne) => ne.parentId === entity.id);
212
+ childEntities.forEach((childEntity) => {
213
+ args.push(new ValueComponent_1.LiteralValue(childEntity.propertyName));
214
+ if (childEntity.relationshipType === "object") {
215
+ // For object relationships, use pre-computed JSON column
216
+ const jsonColumnName = `${childEntity.name.toLowerCase()}_json`;
217
+ args.push(new ValueComponent_1.ColumnReference(null, new ValueComponent_1.IdentifierString(jsonColumnName)));
218
+ }
219
+ else if (childEntity.relationshipType === "array") {
220
+ // For array relationships, use the column directly
221
+ args.push(new ValueComponent_1.ColumnReference(null, new ValueComponent_1.IdentifierString(childEntity.propertyName)));
222
+ }
223
+ });
224
+ // Create JSON object
225
+ const jsonObject = new ValueComponent_1.FunctionCall(null, new ValueComponent_1.RawString(jsonBuildFunction), new ValueComponent_1.ValueList(args), null);
226
+ // Create JSON aggregation
227
+ const jsonAggFunction = useJsonb ? "jsonb_agg" : "json_agg";
228
+ const jsonAgg = new ValueComponent_1.FunctionCall(null, new ValueComponent_1.RawString(jsonAggFunction), new ValueComponent_1.ValueList([jsonObject]), null);
229
+ return { jsonAgg };
230
+ }
231
+ }
232
+ exports.PostgresArrayEntityCteBuilder = PostgresArrayEntityCteBuilder;
233
+ // Constants for consistent naming conventions
234
+ PostgresArrayEntityCteBuilder.CTE_ARRAY_PREFIX = 'cte_array_depth_';
235
+ //# sourceMappingURL=PostgresArrayEntityCteBuilder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PostgresArrayEntityCteBuilder.js","sourceRoot":"","sources":["../../src/transformers/PostgresArrayEntityCteBuilder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ import { SimpleSelectQuery } from '../models/SimpleSelectQuery';
2
+ /**
3
+ * Universal JSON mapping definition for creating any level of JSON structures.
4
+ * Supports flat arrays, nested objects, and unlimited hierarchical structures.
5
+ */
6
+ export interface JsonMapping {
7
+ rootName: string;
8
+ rootEntity: {
9
+ id: string;
10
+ name: string;
11
+ columns: {
12
+ [jsonKey: string]: string;
13
+ };
14
+ };
15
+ nestedEntities: Array<{
16
+ id: string;
17
+ name: string;
18
+ parentId: string;
19
+ propertyName: string;
20
+ relationshipType?: "object" | "array";
21
+ columns: {
22
+ [jsonKey: string]: string;
23
+ };
24
+ }>;
25
+ useJsonb?: boolean;
26
+ resultFormat?: "array" | "single";
27
+ emptyResult?: string;
28
+ }
29
+ /**
30
+ * PostgreSQL JSON query builder that transforms SimpleSelectQuery into queries
31
+ * that return JSON arrays or single JSON objects using PostgreSQL JSON functions.
32
+ */
33
+ export declare class PostgresJsonQueryBuilder {
34
+ private selectValueCollector;
35
+ private objectEntityCteBuilder;
36
+ private arrayEntityCteBuilder;
37
+ constructor();
38
+ /**
39
+ * Validates the JSON mapping and the original query.
40
+ * @param query Original query to transform
41
+ * @param mapping JSON mapping configuration
42
+ */
43
+ private validateMapping;
44
+ /**
45
+ * Build JSON query from original query and mapping configuration.
46
+ * @param originalQuery Original query to transform
47
+ * @param mapping JSON mapping configuration
48
+ * @returns Transformed query with JSON aggregation
49
+ */
50
+ buildJsonQuery(originalQuery: SimpleSelectQuery, mapping: JsonMapping): SimpleSelectQuery;
51
+ /**
52
+ * Build JSON query from original query and mapping configuration.
53
+ * @deprecated Use buildJsonQuery instead. This method will be removed in a future version.
54
+ * @param originalQuery Original query to transform
55
+ * @param mapping JSON mapping configuration
56
+ * @returns Transformed query with JSON aggregation
57
+ */
58
+ buildJson(originalQuery: SimpleSelectQuery, mapping: JsonMapping): SimpleSelectQuery;
59
+ /**
60
+ * Builds the JSON structure using a unified CTE-based strategy.
61
+ * @param originalQuery Original query
62
+ * @param mapping JSON mapping configuration
63
+ * @returns Query with CTE-based JSON aggregation
64
+ */
65
+ private buildJsonWithCteStrategy;
66
+ /**
67
+ * Creates the initial Common Table Expression (CTE) from the original query.
68
+ * @param originalQuery The base SimpleSelectQuery.
69
+ * @returns An object containing the initial CTE and its alias.
70
+ */
71
+ private createInitialCte;
72
+ /**
73
+ * Builds the final SELECT query that constructs the root JSON object (or array of objects).
74
+ * This query uses all previously generated CTEs.
75
+ * @param finalCtesList The complete list of all CTEs (initial and array CTEs).
76
+ * @param lastCteAliasForFromClause Alias of the final CTE from which the root object will be built.
77
+ * @param allEntities Map of all processable entities.
78
+ * @param mapping JSON mapping configuration.
79
+ * @returns The final SimpleSelectQuery.
80
+ */
81
+ private buildFinalSelectQuery;
82
+ /**
83
+ * Build JSON object for entity, using parent JSON columns when available
84
+ */
85
+ private buildEntityJsonObject;
86
+ }
@@ -0,0 +1,230 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PostgresJsonQueryBuilder = void 0;
4
+ const Clause_1 = require("../models/Clause");
5
+ const SimpleSelectQuery_1 = require("../models/SimpleSelectQuery");
6
+ const ValueComponent_1 = require("../models/ValueComponent");
7
+ const SelectValueCollector_1 = require("./SelectValueCollector");
8
+ const PostgresObjectEntityCteBuilder_1 = require("./PostgresObjectEntityCteBuilder");
9
+ const PostgresArrayEntityCteBuilder_1 = require("./PostgresArrayEntityCteBuilder");
10
+ /**
11
+ * PostgreSQL JSON query builder that transforms SimpleSelectQuery into queries
12
+ * that return JSON arrays or single JSON objects using PostgreSQL JSON functions.
13
+ */
14
+ class PostgresJsonQueryBuilder {
15
+ constructor() {
16
+ this.selectValueCollector = new SelectValueCollector_1.SelectValueCollector(null);
17
+ this.objectEntityCteBuilder = new PostgresObjectEntityCteBuilder_1.PostgresObjectEntityCteBuilder();
18
+ this.arrayEntityCteBuilder = new PostgresArrayEntityCteBuilder_1.PostgresArrayEntityCteBuilder();
19
+ }
20
+ /**
21
+ * Validates the JSON mapping and the original query.
22
+ * @param query Original query to transform
23
+ * @param mapping JSON mapping configuration
24
+ */
25
+ validateMapping(query, mapping) {
26
+ var _a, _b;
27
+ const collector = new SelectValueCollector_1.SelectValueCollector();
28
+ const selectedValues = collector.collect(query);
29
+ // sv.name is the alias or derived name
30
+ const availableColumns = new Set(selectedValues.map(sv => sv.name));
31
+ // Check root entity columns
32
+ for (const jsonKey in mapping.rootEntity.columns) {
33
+ const sourceColumn = mapping.rootEntity.columns[jsonKey];
34
+ if (!availableColumns.has(sourceColumn)) {
35
+ throw new Error(`Validation Error: Column "${sourceColumn}" for JSON key "${jsonKey}" in root entity "${mapping.rootEntity.name}" not found in the query's select list.`);
36
+ }
37
+ }
38
+ // Check nested entity columns and parent-child relationships
39
+ const entityIds = new Set([mapping.rootEntity.id]);
40
+ const parentToChildrenMap = new Map();
41
+ mapping.nestedEntities.forEach(ne => {
42
+ entityIds.add(ne.id);
43
+ if (!parentToChildrenMap.has(ne.parentId)) {
44
+ parentToChildrenMap.set(ne.parentId, []);
45
+ }
46
+ parentToChildrenMap.get(ne.parentId).push(ne.id);
47
+ });
48
+ for (const entity of mapping.nestedEntities) {
49
+ if (!entityIds.has(entity.parentId)) {
50
+ throw new Error(`Validation Error: Parent entity with ID "${entity.parentId}" for nested entity "${entity.name}" (ID: ${entity.id}) not found.`);
51
+ }
52
+ for (const jsonKey in entity.columns) {
53
+ const sourceColumn = entity.columns[jsonKey];
54
+ if (!availableColumns.has(sourceColumn)) {
55
+ throw new Error(`Validation Error: Column "${sourceColumn}" for JSON key "${jsonKey}" in nested entity "${entity.name}" (ID: ${entity.id}) not found in the query's select list.`);
56
+ }
57
+ }
58
+ }
59
+ // Validate: An entity should not have multiple direct array children.
60
+ // Validate: Child propertyNames under a single parent must be unique.
61
+ const allParentIds = new Set([mapping.rootEntity.id, ...mapping.nestedEntities.map(ne => ne.parentId)]);
62
+ for (const parentId of allParentIds) {
63
+ const directChildren = mapping.nestedEntities.filter(ne => ne.parentId === parentId);
64
+ const directArrayChildrenCount = directChildren.filter(c => c.relationshipType === 'array').length;
65
+ if (directArrayChildrenCount > 1) {
66
+ const parentName = parentId === mapping.rootEntity.id ? mapping.rootEntity.name : (_a = mapping.nestedEntities.find(ne => ne.id === parentId)) === null || _a === void 0 ? void 0 : _a.name;
67
+ throw new Error(`Validation Error: Parent entity "${parentName}" (ID: ${parentId}) has multiple direct array children. This is not supported.`);
68
+ }
69
+ const propertyNames = new Set();
70
+ for (const child of directChildren) {
71
+ if (propertyNames.has(child.propertyName)) {
72
+ const parentName = parentId === mapping.rootEntity.id ? mapping.rootEntity.name : (_b = mapping.nestedEntities.find(ne => ne.id === parentId)) === null || _b === void 0 ? void 0 : _b.name;
73
+ throw new Error(`Validation Error: Parent entity "${parentName}" (ID: ${parentId}) has duplicate property name "${child.propertyName}" for its children.`);
74
+ }
75
+ propertyNames.add(child.propertyName);
76
+ }
77
+ }
78
+ }
79
+ /**
80
+ * Build JSON query from original query and mapping configuration.
81
+ * @param originalQuery Original query to transform
82
+ * @param mapping JSON mapping configuration
83
+ * @returns Transformed query with JSON aggregation
84
+ */
85
+ buildJsonQuery(originalQuery, mapping) {
86
+ return this.buildJsonWithCteStrategy(originalQuery, mapping);
87
+ }
88
+ /**
89
+ * Build JSON query from original query and mapping configuration.
90
+ * @deprecated Use buildJsonQuery instead. This method will be removed in a future version.
91
+ * @param originalQuery Original query to transform
92
+ * @param mapping JSON mapping configuration
93
+ * @returns Transformed query with JSON aggregation
94
+ */
95
+ buildJson(originalQuery, mapping) {
96
+ console.warn('buildJson is deprecated. Use buildJsonQuery instead.');
97
+ return this.buildJsonQuery(originalQuery, mapping);
98
+ }
99
+ /**
100
+ * Builds the JSON structure using a unified CTE-based strategy.
101
+ * @param originalQuery Original query
102
+ * @param mapping JSON mapping configuration
103
+ * @returns Query with CTE-based JSON aggregation
104
+ */
105
+ buildJsonWithCteStrategy(originalQuery, mapping) {
106
+ this.validateMapping(originalQuery, mapping);
107
+ // Step 1: Create the initial CTE from the original query
108
+ const { initialCte, initialCteAlias } = this.createInitialCte(originalQuery);
109
+ let ctesForProcessing = [initialCte];
110
+ let currentAliasToBuildUpon = initialCteAlias;
111
+ // Step 2: Prepare entity information
112
+ const allEntities = new Map();
113
+ allEntities.set(mapping.rootEntity.id, { ...mapping.rootEntity, isRoot: true, propertyName: mapping.rootName });
114
+ mapping.nestedEntities.forEach(ne => allEntities.set(ne.id, { ...ne, isRoot: false, propertyName: ne.propertyName })); // Step 2.5: Build CTEs for object entities using dedicated builder
115
+ const objectEntityResult = this.objectEntityCteBuilder.buildObjectEntityCtes(initialCte, allEntities, mapping);
116
+ // Important: Replace the entire CTE list with the result from object entity builder
117
+ // The object entity builder returns all CTEs including the initial one
118
+ ctesForProcessing = objectEntityResult.ctes;
119
+ currentAliasToBuildUpon = objectEntityResult.lastCteAlias;
120
+ // Step 3: Build CTEs for array entities using dedicated builder
121
+ const arrayCteBuildResult = this.arrayEntityCteBuilder.buildArrayEntityCtes(ctesForProcessing, currentAliasToBuildUpon, allEntities, mapping);
122
+ ctesForProcessing = arrayCteBuildResult.updatedCtes;
123
+ currentAliasToBuildUpon = arrayCteBuildResult.lastCteAlias;
124
+ // Step 4: Build the final SELECT query using all generated CTEs
125
+ return this.buildFinalSelectQuery(ctesForProcessing, currentAliasToBuildUpon, allEntities, mapping);
126
+ }
127
+ /**
128
+ * Creates the initial Common Table Expression (CTE) from the original query.
129
+ * @param originalQuery The base SimpleSelectQuery.
130
+ * @returns An object containing the initial CTE and its alias.
131
+ */
132
+ createInitialCte(originalQuery) {
133
+ const originCteAlias = "origin_query";
134
+ const originCte = new Clause_1.CommonTable(originalQuery, new Clause_1.SourceAliasExpression(originCteAlias, null), null);
135
+ return { initialCte: originCte, initialCteAlias: originCteAlias };
136
+ }
137
+ /**
138
+ * Builds the final SELECT query that constructs the root JSON object (or array of objects).
139
+ * This query uses all previously generated CTEs.
140
+ * @param finalCtesList The complete list of all CTEs (initial and array CTEs).
141
+ * @param lastCteAliasForFromClause Alias of the final CTE from which the root object will be built.
142
+ * @param allEntities Map of all processable entities.
143
+ * @param mapping JSON mapping configuration.
144
+ * @returns The final SimpleSelectQuery.
145
+ */
146
+ buildFinalSelectQuery(finalCtesList, lastCteAliasForFromClause, allEntities, mapping) {
147
+ const currentCtes = [...finalCtesList];
148
+ // Define rootObjectCteAlias outside of if block
149
+ const rootObjectCteAlias = `cte_root_${mapping.rootName.toLowerCase().replace(/[^a-z0-9_]/g, '_')}`;
150
+ const rootEntity = allEntities.get(mapping.rootEntity.id);
151
+ if (!rootEntity) {
152
+ throw new Error(`Root entity ${mapping.rootEntity.id} not found`);
153
+ }
154
+ if (mapping.resultFormat === "array" || !mapping.resultFormat) {
155
+ // Step 4.1a: Create a CTE that wraps the final result as the root object
156
+ // No alias needed for single table SELECT
157
+ const rootObjectBuilderExpression = this.buildEntityJsonObject(rootEntity, null, // No source alias for single table
158
+ mapping.nestedEntities, allEntities, mapping.useJsonb);
159
+ const rootObjectSelectItem = new Clause_1.SelectItem(rootObjectBuilderExpression, mapping.rootName);
160
+ const rootObjectCte = new Clause_1.CommonTable(new SimpleSelectQuery_1.SimpleSelectQuery({
161
+ selectClause: new Clause_1.SelectClause([rootObjectSelectItem]),
162
+ fromClause: new Clause_1.FromClause(new Clause_1.SourceExpression(new Clause_1.TableSource(null, new ValueComponent_1.IdentifierString(lastCteAliasForFromClause)), null // No alias
163
+ ), null),
164
+ }), new Clause_1.SourceAliasExpression(rootObjectCteAlias, null), null);
165
+ currentCtes.push(rootObjectCte);
166
+ // Step 4.1b: Aggregate all the root objects
167
+ const aggregationFunc = mapping.useJsonb ? "jsonb_agg" : "json_agg";
168
+ const aggregateExpression = new ValueComponent_1.FunctionCall(null, new ValueComponent_1.RawString(aggregationFunc), new ValueComponent_1.ValueList([new ValueComponent_1.ColumnReference(null, new ValueComponent_1.IdentifierString(mapping.rootName))]), null);
169
+ return new SimpleSelectQuery_1.SimpleSelectQuery({
170
+ withClause: new Clause_1.WithClause(false, currentCtes),
171
+ selectClause: new Clause_1.SelectClause([
172
+ new Clause_1.SelectItem(aggregateExpression, `${mapping.rootName}_array`)
173
+ ]),
174
+ fromClause: new Clause_1.FromClause(new Clause_1.SourceExpression(new Clause_1.TableSource(null, new ValueComponent_1.IdentifierString(rootObjectCteAlias)), null), null),
175
+ });
176
+ }
177
+ else {
178
+ // For a single object result, create root object CTE without alias
179
+ const rootObjectBuilderExpression = this.buildEntityJsonObject(rootEntity, null, // No source alias for single table
180
+ mapping.nestedEntities, allEntities, mapping.useJsonb);
181
+ const rootObjectSelectItem = new Clause_1.SelectItem(rootObjectBuilderExpression, mapping.rootName);
182
+ const rootObjectCte = new Clause_1.CommonTable(new SimpleSelectQuery_1.SimpleSelectQuery({
183
+ selectClause: new Clause_1.SelectClause([rootObjectSelectItem]),
184
+ fromClause: new Clause_1.FromClause(new Clause_1.SourceExpression(new Clause_1.TableSource(null, new ValueComponent_1.IdentifierString(lastCteAliasForFromClause)), null // No alias
185
+ ), null),
186
+ }), new Clause_1.SourceAliasExpression(rootObjectCteAlias, null), null);
187
+ currentCtes.push(rootObjectCte);
188
+ // Select directly from the root_object_cte with LIMIT 1
189
+ return new SimpleSelectQuery_1.SimpleSelectQuery({
190
+ withClause: new Clause_1.WithClause(false, currentCtes),
191
+ selectClause: new Clause_1.SelectClause([
192
+ new Clause_1.SelectItem(new ValueComponent_1.ColumnReference(null, new ValueComponent_1.IdentifierString(mapping.rootName)), mapping.rootName)
193
+ ]),
194
+ fromClause: new Clause_1.FromClause(new Clause_1.SourceExpression(new Clause_1.TableSource(null, new ValueComponent_1.IdentifierString(rootObjectCteAlias)), null), null),
195
+ limitClause: new Clause_1.LimitClause(new ValueComponent_1.LiteralValue(1)) // Correctly use LimitClause
196
+ });
197
+ }
198
+ }
199
+ /**
200
+ * Build JSON object for entity, using parent JSON columns when available
201
+ */
202
+ buildEntityJsonObject(entity, sourceAlias, nestedEntities, allEntities, useJsonb = false) {
203
+ const jsonBuildFunction = useJsonb ? "jsonb_build_object" : "json_build_object";
204
+ const args = []; // Add the entity's own columns
205
+ Object.entries(entity.columns).forEach(([jsonKey, sqlColumn]) => {
206
+ args.push(new ValueComponent_1.LiteralValue(jsonKey));
207
+ args.push(new ValueComponent_1.ColumnReference(null, new ValueComponent_1.IdentifierString(sqlColumn)));
208
+ });
209
+ // Find and process child entities (both object and array types)
210
+ const childEntities = nestedEntities.filter((ne) => ne.parentId === entity.id);
211
+ childEntities.forEach((childEntity) => {
212
+ const child = allEntities.get(childEntity.id);
213
+ if (!child)
214
+ return;
215
+ args.push(new ValueComponent_1.LiteralValue(childEntity.propertyName));
216
+ if (childEntity.relationshipType === "object") {
217
+ // For object relationships, use pre-computed JSON column
218
+ const jsonColumnName = `${child.name.toLowerCase()}_json`;
219
+ args.push(new ValueComponent_1.ColumnReference(null, new ValueComponent_1.IdentifierString(jsonColumnName)));
220
+ }
221
+ else if (childEntity.relationshipType === "array") {
222
+ // For array relationships, use the column directly
223
+ args.push(new ValueComponent_1.ColumnReference(null, new ValueComponent_1.IdentifierString(childEntity.propertyName)));
224
+ }
225
+ });
226
+ return new ValueComponent_1.FunctionCall(null, new ValueComponent_1.RawString(jsonBuildFunction), new ValueComponent_1.ValueList(args), null);
227
+ }
228
+ }
229
+ exports.PostgresJsonQueryBuilder = PostgresJsonQueryBuilder;
230
+ //# sourceMappingURL=PostgresJsonQueryBuilder.js.map