@relq/orm 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +236 -0
  3. package/dist/cjs/__test-types.cjs +17 -0
  4. package/dist/cjs/addon/cursor.cjs +1473 -0
  5. package/dist/cjs/addon/pg.cjs +4969 -0
  6. package/dist/cjs/cache/index.cjs +9 -0
  7. package/dist/cjs/cache/query-cache.cjs +311 -0
  8. package/dist/cjs/condition/array-condition-builder.cjs +527 -0
  9. package/dist/cjs/condition/array-numeric-condition-builder.cjs +186 -0
  10. package/dist/cjs/condition/array-specialized-condition-builder.cjs +206 -0
  11. package/dist/cjs/condition/array-string-condition-builder.cjs +146 -0
  12. package/dist/cjs/condition/base-condition-builder.cjs +2 -0
  13. package/dist/cjs/condition/condition-collector.cjs +461 -0
  14. package/dist/cjs/condition/fulltext-condition-builder.cjs +61 -0
  15. package/dist/cjs/condition/geometric-condition-builder.cjs +228 -0
  16. package/dist/cjs/condition/index.cjs +29 -0
  17. package/dist/cjs/condition/jsonb-condition-builder.cjs +448 -0
  18. package/dist/cjs/condition/network-condition-builder.cjs +237 -0
  19. package/dist/cjs/condition/postgis-condition-builder.cjs +188 -0
  20. package/dist/cjs/condition/range-condition-builder.cjs +98 -0
  21. package/dist/cjs/core/helpers/ConnectedAggregateBuilder.cjs +132 -0
  22. package/dist/cjs/core/helpers/ConnectedCTEBuilder.cjs +53 -0
  23. package/dist/cjs/core/helpers/ConnectedCountBuilder.cjs +73 -0
  24. package/dist/cjs/core/helpers/ConnectedDeleteBuilder.cjs +65 -0
  25. package/dist/cjs/core/helpers/ConnectedInsertBuilder.cjs +112 -0
  26. package/dist/cjs/core/helpers/ConnectedInsertFromSelectBuilder.cjs +66 -0
  27. package/dist/cjs/core/helpers/ConnectedQueryBuilder.cjs +146 -0
  28. package/dist/cjs/core/helpers/ConnectedRawQueryBuilder.cjs +46 -0
  29. package/dist/cjs/core/helpers/ConnectedSelectBuilder.cjs +331 -0
  30. package/dist/cjs/core/helpers/ConnectedTransactionBuilder.cjs +105 -0
  31. package/dist/cjs/core/helpers/ConnectedUpdateBuilder.cjs +79 -0
  32. package/dist/cjs/core/helpers/PaginateBuilder.cjs +178 -0
  33. package/dist/cjs/core/helpers/ReturningExecutor.cjs +70 -0
  34. package/dist/cjs/core/helpers/capability-guard.cjs +10 -0
  35. package/dist/cjs/core/helpers/index.cjs +31 -0
  36. package/dist/cjs/core/helpers/methods.cjs +10 -0
  37. package/dist/cjs/core/helpers/query-convenience.cjs +238 -0
  38. package/dist/cjs/core/helpers/select-joins.cjs +251 -0
  39. package/dist/cjs/core/helpers/select-pagination.cjs +233 -0
  40. package/dist/cjs/core/helpers/select-types.cjs +2 -0
  41. package/dist/cjs/core/pg-family/cockroachdb-client/capabilities.cjs +31 -0
  42. package/dist/cjs/core/pg-family/cockroachdb-client/index.cjs +7 -0
  43. package/dist/cjs/core/pg-family/cockroachdb-client/relq-cockroach.cjs +16 -0
  44. package/dist/cjs/core/pg-family/dsql-client/capabilities.cjs +31 -0
  45. package/dist/cjs/core/pg-family/dsql-client/index.cjs +7 -0
  46. package/dist/cjs/core/pg-family/dsql-client/relq-dsql.cjs +16 -0
  47. package/dist/cjs/core/pg-family/index.cjs +19 -0
  48. package/dist/cjs/core/pg-family/nile-client/capabilities.cjs +31 -0
  49. package/dist/cjs/core/pg-family/nile-client/index.cjs +7 -0
  50. package/dist/cjs/core/pg-family/nile-client/relq-nile.cjs +36 -0
  51. package/dist/cjs/core/pg-family/nile-client/tenant-context.cjs +44 -0
  52. package/dist/cjs/core/pg-family/pg-client/capabilities.cjs +31 -0
  53. package/dist/cjs/core/pg-family/pg-client/index.cjs +7 -0
  54. package/dist/cjs/core/pg-family/pg-client/relq-postgres.cjs +43 -0
  55. package/dist/cjs/core/pg-family/shared/pg-base.cjs +385 -0
  56. package/dist/cjs/core/pg-family/shared/pg-dialect.cjs +67 -0
  57. package/dist/cjs/core/pg-family/shared/pg-error-parser.cjs +34 -0
  58. package/dist/cjs/core/pg-family/shared/pg-type-coercion.cjs +14 -0
  59. package/dist/cjs/core/relq-base.cjs +307 -0
  60. package/dist/cjs/core/relq-client.cjs +56 -0
  61. package/dist/cjs/core/shared/cleanup.cjs +36 -0
  62. package/dist/cjs/core/shared/column-mapping.cjs +97 -0
  63. package/dist/cjs/core/shared/errors.cjs +17 -0
  64. package/dist/cjs/core/shared/index.cjs +24 -0
  65. package/dist/cjs/core/shared/table-accessor.cjs +22 -0
  66. package/dist/cjs/core/shared/transform.cjs +35 -0
  67. package/dist/cjs/core/shared/types.cjs +2 -0
  68. package/dist/cjs/core/shared/validation.cjs +140 -0
  69. package/dist/cjs/core/types/core.types.cjs +2 -0
  70. package/dist/cjs/count/count-builder.cjs +88 -0
  71. package/dist/cjs/count/index.cjs +5 -0
  72. package/dist/cjs/delete/delete-builder.cjs +176 -0
  73. package/dist/cjs/delete/index.cjs +5 -0
  74. package/dist/cjs/explain/explain-builder.cjs +99 -0
  75. package/dist/cjs/explain/index.cjs +5 -0
  76. package/dist/cjs/index.cjs +26 -0
  77. package/dist/cjs/insert/conflict-builder.cjs +213 -0
  78. package/dist/cjs/insert/index.cjs +5 -0
  79. package/dist/cjs/insert/insert-builder.cjs +320 -0
  80. package/dist/cjs/insert/insert-from-select-builder.cjs +86 -0
  81. package/dist/cjs/pubsub/index.cjs +7 -0
  82. package/dist/cjs/pubsub/listen-notify-builder.cjs +57 -0
  83. package/dist/cjs/pubsub/listener-connection.cjs +180 -0
  84. package/dist/cjs/raw/index.cjs +8 -0
  85. package/dist/cjs/raw/raw-query-builder.cjs +27 -0
  86. package/dist/cjs/raw/sql-template.cjs +73 -0
  87. package/dist/cjs/select/aggregate-builder.cjs +179 -0
  88. package/dist/cjs/select/index.cjs +16 -0
  89. package/dist/cjs/select/join-builder.cjs +192 -0
  90. package/dist/cjs/select/join-condition-builder.cjs +189 -0
  91. package/dist/cjs/select/join-internals.cjs +5 -0
  92. package/dist/cjs/select/join-many-condition-builder.cjs +159 -0
  93. package/dist/cjs/select/scalar-query-builder.cjs +134 -0
  94. package/dist/cjs/select/scalar-select-builder.cjs +78 -0
  95. package/dist/cjs/select/select-builder.cjs +426 -0
  96. package/dist/cjs/select/sql-expression.cjs +38 -0
  97. package/dist/cjs/select/table-proxy.cjs +99 -0
  98. package/dist/cjs/shared/aws-dsql.cjs +181 -0
  99. package/dist/cjs/shared/errors/relq-errors.cjs +361 -0
  100. package/dist/cjs/shared/pg-format.cjs +383 -0
  101. package/dist/cjs/shared/types/config-types.cjs +51 -0
  102. package/dist/cjs/transaction/index.cjs +6 -0
  103. package/dist/cjs/transaction/transaction-builder.cjs +78 -0
  104. package/dist/cjs/types/aggregate-types.cjs +2 -0
  105. package/dist/cjs/types/inference-types.cjs +18 -0
  106. package/dist/cjs/types/pagination-types.cjs +7 -0
  107. package/dist/cjs/types/result-types.cjs +2 -0
  108. package/dist/cjs/types/scalar-types.cjs +2 -0
  109. package/dist/cjs/types/schema-types.cjs +2 -0
  110. package/dist/cjs/types/subscription-types.cjs +2 -0
  111. package/dist/cjs/types.cjs +2 -0
  112. package/dist/cjs/update/array-update-builder.cjs +232 -0
  113. package/dist/cjs/update/index.cjs +16 -0
  114. package/dist/cjs/update/jsonb-update-builder.cjs +219 -0
  115. package/dist/cjs/update/update-builder.cjs +274 -0
  116. package/dist/cjs/utils/addon/pg/cursor.cjs +8 -0
  117. package/dist/cjs/utils/addon/pg/pg.cjs +23 -0
  118. package/dist/cjs/utils/case-converter.cjs +58 -0
  119. package/dist/cjs/utils/env-resolver.cjs +226 -0
  120. package/dist/cjs/utils/environment-detection.cjs +124 -0
  121. package/dist/cjs/utils/fk-resolver.cjs +186 -0
  122. package/dist/cjs/utils/index.cjs +25 -0
  123. package/dist/cjs/utils/pool-defaults.cjs +91 -0
  124. package/dist/cjs/utils/type-coercion.cjs +120 -0
  125. package/dist/cjs/window/index.cjs +5 -0
  126. package/dist/cjs/window/window-builder.cjs +80 -0
  127. package/dist/esm/__test-types.js +15 -0
  128. package/dist/esm/addon/cursor.js +1440 -0
  129. package/dist/esm/addon/pg.js +4931 -0
  130. package/dist/esm/cache/index.js +1 -0
  131. package/dist/esm/cache/query-cache.js +303 -0
  132. package/dist/esm/condition/array-condition-builder.js +519 -0
  133. package/dist/esm/condition/array-numeric-condition-builder.js +182 -0
  134. package/dist/esm/condition/array-specialized-condition-builder.js +200 -0
  135. package/dist/esm/condition/array-string-condition-builder.js +142 -0
  136. package/dist/esm/condition/base-condition-builder.js +1 -0
  137. package/dist/esm/condition/condition-collector.js +452 -0
  138. package/dist/esm/condition/fulltext-condition-builder.js +53 -0
  139. package/dist/esm/condition/geometric-condition-builder.js +220 -0
  140. package/dist/esm/condition/index.js +8 -0
  141. package/dist/esm/condition/jsonb-condition-builder.js +439 -0
  142. package/dist/esm/condition/network-condition-builder.js +229 -0
  143. package/dist/esm/condition/postgis-condition-builder.js +180 -0
  144. package/dist/esm/condition/range-condition-builder.js +90 -0
  145. package/dist/esm/core/helpers/ConnectedAggregateBuilder.js +128 -0
  146. package/dist/esm/core/helpers/ConnectedCTEBuilder.js +49 -0
  147. package/dist/esm/core/helpers/ConnectedCountBuilder.js +69 -0
  148. package/dist/esm/core/helpers/ConnectedDeleteBuilder.js +61 -0
  149. package/dist/esm/core/helpers/ConnectedInsertBuilder.js +108 -0
  150. package/dist/esm/core/helpers/ConnectedInsertFromSelectBuilder.js +62 -0
  151. package/dist/esm/core/helpers/ConnectedQueryBuilder.js +142 -0
  152. package/dist/esm/core/helpers/ConnectedRawQueryBuilder.js +42 -0
  153. package/dist/esm/core/helpers/ConnectedSelectBuilder.js +327 -0
  154. package/dist/esm/core/helpers/ConnectedTransactionBuilder.js +100 -0
  155. package/dist/esm/core/helpers/ConnectedUpdateBuilder.js +75 -0
  156. package/dist/esm/core/helpers/PaginateBuilder.js +174 -0
  157. package/dist/esm/core/helpers/ReturningExecutor.js +66 -0
  158. package/dist/esm/core/helpers/capability-guard.js +7 -0
  159. package/dist/esm/core/helpers/index.js +13 -0
  160. package/dist/esm/core/helpers/methods.js +6 -0
  161. package/dist/esm/core/helpers/query-convenience.js +194 -0
  162. package/dist/esm/core/helpers/select-joins.js +246 -0
  163. package/dist/esm/core/helpers/select-pagination.js +226 -0
  164. package/dist/esm/core/helpers/select-types.js +1 -0
  165. package/dist/esm/core/pg-family/cockroachdb-client/capabilities.js +28 -0
  166. package/dist/esm/core/pg-family/cockroachdb-client/index.js +2 -0
  167. package/dist/esm/core/pg-family/cockroachdb-client/relq-cockroach.js +12 -0
  168. package/dist/esm/core/pg-family/dsql-client/capabilities.js +28 -0
  169. package/dist/esm/core/pg-family/dsql-client/index.js +2 -0
  170. package/dist/esm/core/pg-family/dsql-client/relq-dsql.js +12 -0
  171. package/dist/esm/core/pg-family/index.js +6 -0
  172. package/dist/esm/core/pg-family/nile-client/capabilities.js +28 -0
  173. package/dist/esm/core/pg-family/nile-client/index.js +2 -0
  174. package/dist/esm/core/pg-family/nile-client/relq-nile.js +32 -0
  175. package/dist/esm/core/pg-family/nile-client/tenant-context.js +40 -0
  176. package/dist/esm/core/pg-family/pg-client/capabilities.js +28 -0
  177. package/dist/esm/core/pg-family/pg-client/index.js +2 -0
  178. package/dist/esm/core/pg-family/pg-client/relq-postgres.js +39 -0
  179. package/dist/esm/core/pg-family/shared/pg-base.js +347 -0
  180. package/dist/esm/core/pg-family/shared/pg-dialect.js +63 -0
  181. package/dist/esm/core/pg-family/shared/pg-error-parser.js +29 -0
  182. package/dist/esm/core/pg-family/shared/pg-type-coercion.js +6 -0
  183. package/dist/esm/core/relq-base.js +270 -0
  184. package/dist/esm/core/relq-client.js +48 -0
  185. package/dist/esm/core/shared/cleanup.js +27 -0
  186. package/dist/esm/core/shared/column-mapping.js +90 -0
  187. package/dist/esm/core/shared/errors.js +13 -0
  188. package/dist/esm/core/shared/index.js +6 -0
  189. package/dist/esm/core/shared/table-accessor.js +19 -0
  190. package/dist/esm/core/shared/transform.js +30 -0
  191. package/dist/esm/core/shared/types.js +1 -0
  192. package/dist/esm/core/shared/validation.js +136 -0
  193. package/dist/esm/core/types/core.types.js +1 -0
  194. package/dist/esm/count/count-builder.js +81 -0
  195. package/dist/esm/count/index.js +1 -0
  196. package/dist/esm/delete/delete-builder.js +169 -0
  197. package/dist/esm/delete/index.js +1 -0
  198. package/dist/esm/explain/explain-builder.js +95 -0
  199. package/dist/esm/explain/index.js +1 -0
  200. package/dist/esm/index.js +7 -0
  201. package/dist/esm/insert/conflict-builder.js +202 -0
  202. package/dist/esm/insert/index.js +1 -0
  203. package/dist/esm/insert/insert-builder.js +313 -0
  204. package/dist/esm/insert/insert-from-select-builder.js +79 -0
  205. package/dist/esm/pubsub/index.js +1 -0
  206. package/dist/esm/pubsub/listen-notify-builder.js +48 -0
  207. package/dist/esm/pubsub/listener-connection.js +173 -0
  208. package/dist/esm/raw/index.js +2 -0
  209. package/dist/esm/raw/raw-query-builder.js +20 -0
  210. package/dist/esm/raw/sql-template.js +66 -0
  211. package/dist/esm/select/aggregate-builder.js +172 -0
  212. package/dist/esm/select/index.js +4 -0
  213. package/dist/esm/select/join-builder.js +184 -0
  214. package/dist/esm/select/join-condition-builder.js +181 -0
  215. package/dist/esm/select/join-internals.js +2 -0
  216. package/dist/esm/select/join-many-condition-builder.js +151 -0
  217. package/dist/esm/select/scalar-query-builder.js +126 -0
  218. package/dist/esm/select/scalar-select-builder.js +70 -0
  219. package/dist/esm/select/select-builder.js +419 -0
  220. package/dist/esm/select/sql-expression.js +33 -0
  221. package/dist/esm/select/table-proxy.js +91 -0
  222. package/dist/esm/shared/aws-dsql.js +140 -0
  223. package/dist/esm/shared/errors/relq-errors.js +339 -0
  224. package/dist/esm/shared/pg-format.js +375 -0
  225. package/dist/esm/shared/types/config-types.js +46 -0
  226. package/dist/esm/transaction/index.js +1 -0
  227. package/dist/esm/transaction/transaction-builder.js +70 -0
  228. package/dist/esm/types/aggregate-types.js +1 -0
  229. package/dist/esm/types/inference-types.js +12 -0
  230. package/dist/esm/types/pagination-types.js +4 -0
  231. package/dist/esm/types/result-types.js +1 -0
  232. package/dist/esm/types/scalar-types.js +1 -0
  233. package/dist/esm/types/schema-types.js +1 -0
  234. package/dist/esm/types/subscription-types.js +1 -0
  235. package/dist/esm/types.js +1 -0
  236. package/dist/esm/update/array-update-builder.js +219 -0
  237. package/dist/esm/update/index.js +3 -0
  238. package/dist/esm/update/jsonb-update-builder.js +211 -0
  239. package/dist/esm/update/update-builder.js +267 -0
  240. package/dist/esm/utils/addon/pg/cursor.js +1 -0
  241. package/dist/esm/utils/addon/pg/pg.js +2 -0
  242. package/dist/esm/utils/case-converter.js +55 -0
  243. package/dist/esm/utils/env-resolver.js +213 -0
  244. package/dist/esm/utils/environment-detection.js +114 -0
  245. package/dist/esm/utils/fk-resolver.js +178 -0
  246. package/dist/esm/utils/index.js +4 -0
  247. package/dist/esm/utils/pool-defaults.js +85 -0
  248. package/dist/esm/utils/type-coercion.js +112 -0
  249. package/dist/esm/window/index.js +1 -0
  250. package/dist/esm/window/window-builder.js +73 -0
  251. package/dist/index.cjs +1 -0
  252. package/dist/index.d.ts +7281 -0
  253. package/dist/index.js +1 -0
  254. package/package.json +52 -0
@@ -0,0 +1,419 @@
1
+ import format from "../shared/pg-format.js";
2
+ import { ConditionCollector, buildConditionsSQL } from "../condition/condition-collector.js";
3
+ export class SelectBuilder {
4
+ tableName;
5
+ tableAlias;
6
+ selectColumns = ['*'];
7
+ whereConditions = [];
8
+ havingConditions = [];
9
+ joinClauses = [];
10
+ structuredJoins = [];
11
+ groupByColumns = [];
12
+ orderByColumns = [];
13
+ limitValue;
14
+ offsetValue;
15
+ distinctOnColumns = [];
16
+ isDistinct = false;
17
+ lockingClause;
18
+ unionQueries = [];
19
+ includeExpressions = [];
20
+ columnResolver;
21
+ constructor(tableName, columns) {
22
+ this.tableName = tableName;
23
+ if (columns) {
24
+ this.selectColumns = Array.isArray(columns) ? columns : [columns];
25
+ }
26
+ }
27
+ setColumnResolver(resolver) {
28
+ this.columnResolver = resolver;
29
+ return this;
30
+ }
31
+ transformConditionColumns(conditions) {
32
+ if (!this.columnResolver) {
33
+ return conditions;
34
+ }
35
+ return conditions.map(cond => {
36
+ if (cond.method === 'or' || cond.method === 'and') {
37
+ return {
38
+ ...cond,
39
+ values: this.transformConditionColumns(cond.values)
40
+ };
41
+ }
42
+ if (!cond.column) {
43
+ return cond;
44
+ }
45
+ if (cond.method === 'raw') {
46
+ return cond;
47
+ }
48
+ if (cond.column.includes('.')) {
49
+ const [tableRef, colName] = cond.column.split('.');
50
+ return {
51
+ ...cond,
52
+ column: `${tableRef}.${this.columnResolver(colName)}`
53
+ };
54
+ }
55
+ return {
56
+ ...cond,
57
+ column: this.columnResolver(cond.column)
58
+ };
59
+ });
60
+ }
61
+ setTableAlias(alias) {
62
+ this.tableAlias = alias;
63
+ return this;
64
+ }
65
+ getTableIdentifier() {
66
+ return this.tableAlias || this.tableName;
67
+ }
68
+ distinct() {
69
+ this.isDistinct = true;
70
+ return this;
71
+ }
72
+ where(callback) {
73
+ const conditionBuilder = new ConditionCollector();
74
+ callback(conditionBuilder);
75
+ this.whereConditions.push(...conditionBuilder.getConditions());
76
+ return this;
77
+ }
78
+ join(table, condition) {
79
+ this.joinClauses.push(`JOIN ${format.ident(table)} ON ${condition}`);
80
+ return this;
81
+ }
82
+ leftJoin(table, condition) {
83
+ this.joinClauses.push(`LEFT JOIN ${format.ident(table)} ON ${condition}`);
84
+ return this;
85
+ }
86
+ rightJoin(table, condition) {
87
+ this.joinClauses.push(`RIGHT JOIN ${format.ident(table)} ON ${condition}`);
88
+ return this;
89
+ }
90
+ innerJoin(table, condition) {
91
+ this.joinClauses.push(`INNER JOIN ${format.ident(table)} ON ${condition}`);
92
+ return this;
93
+ }
94
+ addRawJoin(joinSQL) {
95
+ this.joinClauses.push(joinSQL);
96
+ return this;
97
+ }
98
+ groupBy(...columns) {
99
+ this.groupByColumns.push(...columns);
100
+ return this;
101
+ }
102
+ having(callback) {
103
+ const conditionBuilder = new ConditionCollector();
104
+ callback(conditionBuilder);
105
+ this.havingConditions.push(...conditionBuilder.getConditions());
106
+ return this;
107
+ }
108
+ orderBy(column, direction = 'ASC') {
109
+ this.orderByColumns.push({ column, direction });
110
+ return this;
111
+ }
112
+ orderByNulls(column, direction, nulls) {
113
+ this.orderByColumns.push({ column, direction, nulls });
114
+ return this;
115
+ }
116
+ orderAsc(column) {
117
+ return this.orderBy(column, 'ASC');
118
+ }
119
+ orderDesc(column) {
120
+ return this.orderBy(column, 'DESC');
121
+ }
122
+ limit(count) {
123
+ this.limitValue = count;
124
+ return this;
125
+ }
126
+ offset(count) {
127
+ this.offsetValue = count;
128
+ return this;
129
+ }
130
+ distinctOn(...columns) {
131
+ this.distinctOnColumns.push(...columns);
132
+ return this;
133
+ }
134
+ forUpdate() {
135
+ this.lockingClause = 'FOR UPDATE';
136
+ return this;
137
+ }
138
+ forUpdateNoWait() {
139
+ this.lockingClause = 'FOR UPDATE NOWAIT';
140
+ return this;
141
+ }
142
+ forUpdateSkipLocked() {
143
+ this.lockingClause = 'FOR UPDATE SKIP LOCKED';
144
+ return this;
145
+ }
146
+ forShare() {
147
+ this.lockingClause = 'FOR SHARE';
148
+ return this;
149
+ }
150
+ forShareNoWait() {
151
+ this.lockingClause = 'FOR SHARE NOWAIT';
152
+ return this;
153
+ }
154
+ forShareSkipLocked() {
155
+ this.lockingClause = 'FOR SHARE SKIP LOCKED';
156
+ return this;
157
+ }
158
+ union(query) {
159
+ this.unionQueries.push({
160
+ query: typeof query === 'string' ? query : query.toString(),
161
+ type: 'UNION'
162
+ });
163
+ return this;
164
+ }
165
+ unionAll(query) {
166
+ this.unionQueries.push({
167
+ query: typeof query === 'string' ? query : query.toString(),
168
+ type: 'UNION ALL'
169
+ });
170
+ return this;
171
+ }
172
+ intersect(query) {
173
+ this.unionQueries.push({
174
+ query: typeof query === 'string' ? query : query.toString(),
175
+ type: 'INTERSECT'
176
+ });
177
+ return this;
178
+ }
179
+ except(query) {
180
+ this.unionQueries.push({
181
+ query: typeof query === 'string' ? query : query.toString(),
182
+ type: 'EXCEPT'
183
+ });
184
+ return this;
185
+ }
186
+ fullOuterJoin(table, condition) {
187
+ this.joinClauses.push(`FULL OUTER JOIN ${format.ident(table)} ON ${condition}`);
188
+ return this;
189
+ }
190
+ crossJoin(table) {
191
+ this.joinClauses.push(`CROSS JOIN ${format.ident(table)}`);
192
+ return this;
193
+ }
194
+ lateralJoin(subquery, left = false) {
195
+ const joinType = left ? 'LEFT JOIN LATERAL' : 'JOIN LATERAL';
196
+ this.joinClauses.push(`${joinType} ${subquery}`);
197
+ return this;
198
+ }
199
+ addStructuredJoin(join) {
200
+ this.structuredJoins.push(join);
201
+ return this;
202
+ }
203
+ getStructuredJoins() {
204
+ return [...this.structuredJoins];
205
+ }
206
+ addIncludeExpression(alias, sql) {
207
+ this.includeExpressions.push({ alias, sql });
208
+ return this;
209
+ }
210
+ qualifyWhereConditions(conditions, tableRef) {
211
+ return conditions.map(cond => {
212
+ if (!cond.column) {
213
+ return cond;
214
+ }
215
+ if (cond.column.includes('.')) {
216
+ return cond;
217
+ }
218
+ if (cond.method === 'or' || cond.method === 'and') {
219
+ return {
220
+ ...cond,
221
+ values: this.qualifyWhereConditions(cond.values, tableRef)
222
+ };
223
+ }
224
+ return {
225
+ ...cond,
226
+ column: `${tableRef}.${cond.column}`
227
+ };
228
+ });
229
+ }
230
+ buildStructuredJoinSQL(join) {
231
+ if ((join.type === 'LEFT JOIN LATERAL' || join.type === 'JOIN LATERAL') && join.lateralSubquery) {
232
+ return `${join.type} ${join.lateralSubquery} ON true`;
233
+ }
234
+ if (join.type === 'CROSS JOIN') {
235
+ const tableRef = join.alias !== join.table
236
+ ? `${format.ident(join.table)} AS ${format.ident(join.alias)}`
237
+ : format.ident(join.table);
238
+ return `CROSS JOIN ${tableRef}`;
239
+ }
240
+ const tableRef = join.alias !== join.table
241
+ ? `${format.ident(join.table)} AS ${format.ident(join.alias)}`
242
+ : format.ident(join.table);
243
+ if (join.usingColumns && join.usingColumns.length > 0) {
244
+ const usingSQL = join.usingColumns.map(c => format.ident(c)).join(', ');
245
+ return `${join.type} ${tableRef} USING (${usingSQL})`;
246
+ }
247
+ if (join.onClause) {
248
+ return `${join.type} ${tableRef} ON ${join.onClause}`;
249
+ }
250
+ return `${join.type} ${tableRef}`;
251
+ }
252
+ toString() {
253
+ const hasJoins = this.joinClauses.length > 0 || this.structuredJoins.length > 0;
254
+ const tableRef = this.tableAlias || this.tableName;
255
+ const columns = this.selectColumns.map(col => {
256
+ if (col === '*') {
257
+ return hasJoins ? `${format.ident(tableRef)}.*` : '*';
258
+ }
259
+ if (Array.isArray(col)) {
260
+ const [column, alias] = col;
261
+ if (hasJoins) {
262
+ return format('%I.%I AS %I', tableRef, column, alias);
263
+ }
264
+ return format('%I AS %I', column, alias);
265
+ }
266
+ if (col.includes('(') || col.includes('DISTINCT') || col.includes(' AS ') || col.includes('.')) {
267
+ return col;
268
+ }
269
+ if (hasJoins) {
270
+ return format('%I.%I', tableRef, col);
271
+ }
272
+ return format.ident(col);
273
+ });
274
+ for (const join of this.structuredJoins) {
275
+ if (join.type === 'LEFT JOIN LATERAL' || join.type === 'JOIN LATERAL') {
276
+ columns.push(`${format.ident(join.alias + '_lateral')}.${format.ident(join.alias)} AS ${format.ident(join.alias)}`);
277
+ }
278
+ else if (join.selectColumns && join.selectColumns.length > 0) {
279
+ const jsonArgs = join.selectColumns
280
+ .map(col => `'${col.property}', ${format.ident(join.alias)}.${format.ident(col.sqlName)}`)
281
+ .join(', ');
282
+ columns.push(`json_build_object(${jsonArgs}) AS ${format.ident(join.alias)}`);
283
+ }
284
+ else {
285
+ columns.push(`row_to_json(${format.ident(join.alias)}.*) AS ${format.ident(join.alias)}`);
286
+ }
287
+ }
288
+ for (const expr of this.includeExpressions) {
289
+ columns.push(`${expr.sql} AS ${format.ident(expr.alias)}`);
290
+ }
291
+ const columnsSQL = columns.join(', ');
292
+ let query = 'SELECT';
293
+ if (this.distinctOnColumns.length > 0) {
294
+ const distinctCols = this.distinctOnColumns.map(col => format.ident(col)).join(', ');
295
+ query += format(' DISTINCT ON (%s)', distinctCols);
296
+ }
297
+ else if (this.isDistinct) {
298
+ query += ' DISTINCT';
299
+ }
300
+ if (this.tableAlias && this.tableAlias !== this.tableName) {
301
+ query += format(' %s FROM %I AS %I', columnsSQL, this.tableName, this.tableAlias);
302
+ }
303
+ else {
304
+ query += format(' %s FROM %I', columnsSQL, this.tableName);
305
+ }
306
+ if (this.joinClauses.length > 0) {
307
+ query += ' ' + this.joinClauses.join(' ');
308
+ }
309
+ if (this.structuredJoins.length > 0) {
310
+ const structuredJoinSQL = this.structuredJoins
311
+ .map(join => this.buildStructuredJoinSQL(join))
312
+ .join(' ');
313
+ query += ' ' + structuredJoinSQL;
314
+ }
315
+ if (this.whereConditions.length > 0) {
316
+ let conditions = this.transformConditionColumns(this.whereConditions);
317
+ if (hasJoins) {
318
+ conditions = this.qualifyWhereConditions(conditions, tableRef);
319
+ }
320
+ query += ' WHERE ' + buildConditionsSQL(conditions);
321
+ }
322
+ if (this.groupByColumns.length > 0) {
323
+ const groupBySQL = this.groupByColumns.map(col => {
324
+ if (col.includes('.'))
325
+ return col;
326
+ if (hasJoins)
327
+ return format('%I.%I', tableRef, col);
328
+ return format.ident(col);
329
+ }).join(', ');
330
+ query += ' GROUP BY ' + groupBySQL;
331
+ }
332
+ if (this.havingConditions.length > 0) {
333
+ let havingConds = this.transformConditionColumns(this.havingConditions);
334
+ if (hasJoins) {
335
+ havingConds = this.qualifyWhereConditions(havingConds, tableRef);
336
+ }
337
+ query += ' HAVING ' + buildConditionsSQL(havingConds);
338
+ }
339
+ if (this.orderByColumns.length > 0) {
340
+ query += ' ORDER BY ' + this.orderByColumns
341
+ .map(order => {
342
+ let sql = format('%I %s', order.column, order.direction);
343
+ if (order.nulls) {
344
+ sql += ` NULLS ${order.nulls}`;
345
+ }
346
+ return sql;
347
+ })
348
+ .join(', ');
349
+ }
350
+ if (this.limitValue !== undefined) {
351
+ query += format(' LIMIT %s', this.limitValue);
352
+ }
353
+ if (this.offsetValue !== undefined) {
354
+ query += format(' OFFSET %s', this.offsetValue);
355
+ }
356
+ if (this.lockingClause) {
357
+ query += ' ' + this.lockingClause;
358
+ }
359
+ if (this.unionQueries.length > 0) {
360
+ for (const unionQuery of this.unionQueries) {
361
+ query += ` ${unionQuery.type} ${unionQuery.query}`;
362
+ }
363
+ }
364
+ return query;
365
+ }
366
+ whereRaw(condition) {
367
+ this.whereConditions.push({
368
+ method: 'raw',
369
+ column: condition,
370
+ values: undefined
371
+ });
372
+ return this;
373
+ }
374
+ toCountSQL() {
375
+ let query;
376
+ const hasJoins = this.joinClauses.length > 0 || this.structuredJoins.length > 0;
377
+ const tableRef = this.tableAlias || this.tableName;
378
+ if (this.tableAlias && this.tableAlias !== this.tableName) {
379
+ query = `SELECT COUNT(*) as count FROM ${format.ident(this.tableName)} AS ${format.ident(this.tableAlias)}`;
380
+ }
381
+ else {
382
+ query = `SELECT COUNT(*) as count FROM ${format.ident(this.tableName)}`;
383
+ }
384
+ if (this.joinClauses.length > 0) {
385
+ query += ' ' + this.joinClauses.join(' ');
386
+ }
387
+ if (this.structuredJoins.length > 0) {
388
+ const structuredJoinSQL = this.structuredJoins
389
+ .map(join => this.buildStructuredJoinSQL(join))
390
+ .join(' ');
391
+ query += ' ' + structuredJoinSQL;
392
+ }
393
+ if (this.whereConditions.length > 0) {
394
+ let conditions = this.transformConditionColumns(this.whereConditions);
395
+ if (hasJoins) {
396
+ conditions = this.qualifyWhereConditions(conditions, tableRef);
397
+ }
398
+ query += ' WHERE ' + buildConditionsSQL(conditions);
399
+ }
400
+ if (this.groupByColumns.length > 0) {
401
+ const groupBySQL = this.groupByColumns.map(col => {
402
+ if (col.includes('.'))
403
+ return col;
404
+ if (hasJoins)
405
+ return format('%I.%I', tableRef, col);
406
+ return format.ident(col);
407
+ }).join(', ');
408
+ query += ' GROUP BY ' + groupBySQL;
409
+ }
410
+ if (this.havingConditions.length > 0) {
411
+ let havingConds = this.transformConditionColumns(this.havingConditions);
412
+ if (hasJoins) {
413
+ havingConds = this.qualifyWhereConditions(havingConds, tableRef);
414
+ }
415
+ query += ' HAVING ' + buildConditionsSQL(havingConds);
416
+ }
417
+ return query;
418
+ }
419
+ }
@@ -0,0 +1,33 @@
1
+ import { columnRefToSQL } from "./table-proxy.js";
2
+ export class SqlExpression {
3
+ sql;
4
+ _isSqlExpression = true;
5
+ constructor(sql) {
6
+ this.sql = sql;
7
+ }
8
+ }
9
+ export class AggregateFunctions {
10
+ count(ref) {
11
+ if (!ref)
12
+ return new SqlExpression('COUNT(*)');
13
+ return new SqlExpression(`COUNT(${columnRefToSQL(ref)})`);
14
+ }
15
+ countDistinct(ref) {
16
+ return new SqlExpression(`COUNT(DISTINCT ${columnRefToSQL(ref)})`);
17
+ }
18
+ sum(ref) {
19
+ return new SqlExpression(`SUM(${columnRefToSQL(ref)})`);
20
+ }
21
+ avg(ref) {
22
+ return new SqlExpression(`AVG(${columnRefToSQL(ref)})`);
23
+ }
24
+ min(ref) {
25
+ return new SqlExpression(`MIN(${columnRefToSQL(ref)})`);
26
+ }
27
+ max(ref) {
28
+ return new SqlExpression(`MAX(${columnRefToSQL(ref)})`);
29
+ }
30
+ raw(sql) {
31
+ return new SqlExpression(sql);
32
+ }
33
+ }
@@ -0,0 +1,91 @@
1
+ export function isColumnRef(value) {
2
+ return (typeof value === 'object' &&
3
+ value !== null &&
4
+ '$table' in value &&
5
+ '$alias' in value &&
6
+ '$column' in value &&
7
+ '$sqlColumn' in value);
8
+ }
9
+ export function createTableProxy(tableName, alias, tableSchema) {
10
+ return new Proxy({}, {
11
+ get(_, prop) {
12
+ if (typeof prop === 'symbol') {
13
+ return undefined;
14
+ }
15
+ const columns = tableSchema?.$columns || tableSchema;
16
+ const columnDef = columns?.[prop];
17
+ let sqlColumn;
18
+ if (columnDef) {
19
+ sqlColumn = columnDef.$sqlName || columnDef.$name || camelToSnake(prop);
20
+ }
21
+ else {
22
+ sqlColumn = camelToSnake(prop);
23
+ }
24
+ return {
25
+ $table: tableName,
26
+ $alias: alias,
27
+ $column: prop,
28
+ $sqlColumn: sqlColumn,
29
+ $type: undefined
30
+ };
31
+ },
32
+ has(_, prop) {
33
+ if (typeof prop === 'symbol')
34
+ return false;
35
+ const columns = tableSchema?.$columns || tableSchema;
36
+ return columns ? prop in columns : true;
37
+ },
38
+ ownKeys(_) {
39
+ const columns = tableSchema?.$columns || tableSchema;
40
+ return columns ? Object.keys(columns) : [];
41
+ },
42
+ getOwnPropertyDescriptor(_, prop) {
43
+ if (typeof prop === 'symbol')
44
+ return undefined;
45
+ const columns = tableSchema?.$columns || tableSchema;
46
+ if (columns && prop in columns) {
47
+ const columnDef = columns[prop];
48
+ const sqlColumn = columnDef?.$sqlName || columnDef?.$name || camelToSnake(prop);
49
+ return {
50
+ enumerable: true,
51
+ configurable: true,
52
+ value: {
53
+ $table: tableName,
54
+ $alias: alias,
55
+ $column: prop,
56
+ $sqlColumn: sqlColumn,
57
+ $type: undefined
58
+ }
59
+ };
60
+ }
61
+ return undefined;
62
+ }
63
+ });
64
+ }
65
+ export function createJoinCallbackParams(leftTableKey, leftAlias, leftTableDef, rightTableKey, rightAlias, rightTableDef) {
66
+ const leftTableName = leftTableDef?.$name || leftTableKey;
67
+ const rightTableName = rightTableDef?.$name || rightTableKey;
68
+ return {
69
+ leftProxy: createTableProxy(leftTableName, leftAlias, leftTableDef),
70
+ rightProxy: createTableProxy(rightTableName, rightAlias, rightTableDef),
71
+ leftTableName,
72
+ rightTableName
73
+ };
74
+ }
75
+ function camelToSnake(str) {
76
+ return str
77
+ .replace(/([A-Z])/g, '_$1')
78
+ .toLowerCase()
79
+ .replace(/^_/, '');
80
+ }
81
+ export function columnRefToSQL(ref) {
82
+ return `"${ref.$alias}"."${ref.$sqlColumn}"`;
83
+ }
84
+ export function columnRefToSQLUnqualified(ref) {
85
+ return `"${ref.$sqlColumn}"`;
86
+ }
87
+ export function columnRefsEqual(a, b) {
88
+ return a.$table === b.$table &&
89
+ a.$alias === b.$alias &&
90
+ a.$sqlColumn === b.$sqlColumn;
91
+ }
@@ -0,0 +1,140 @@
1
+ import process from 'node:process';
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, accessSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { tmpdir } from 'node:os';
5
+ import { createHash } from 'node:crypto';
6
+ import { F_OK, W_OK, R_OK } from 'node:constants';
7
+ import { RelqConfigError } from "./errors/relq-errors.js";
8
+ const tokenCache = new Map();
9
+ function getCacheKey(config) {
10
+ const hash = createHash('md5')
11
+ .update(`${config.secretAccessKey ?? ''}-${config.accessKeyId ?? ''}-${config.region}-${config.hostname}`)
12
+ .digest('hex');
13
+ return hash;
14
+ }
15
+ function getTempFolder() {
16
+ return join(tmpdir(), '.dsql_');
17
+ }
18
+ function isTempFolderAvailable() {
19
+ const tempFolder = getTempFolder();
20
+ try {
21
+ mkdirSync(tempFolder, { recursive: true });
22
+ accessSync(tempFolder, F_OK | R_OK | W_OK);
23
+ return true;
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ }
29
+ function getFromCache(cacheKey) {
30
+ const memoryToken = tokenCache.get(cacheKey);
31
+ if (memoryToken && memoryToken.expiresAt > Date.now()) {
32
+ return memoryToken;
33
+ }
34
+ const envName = `DSQL_TOKEN_${cacheKey}`;
35
+ const envToken = process.env[envName];
36
+ if (envToken) {
37
+ try {
38
+ const parsed = JSON.parse(envToken);
39
+ if (parsed.expiresAt > Date.now()) {
40
+ tokenCache.set(cacheKey, parsed);
41
+ return parsed;
42
+ }
43
+ }
44
+ catch { }
45
+ }
46
+ if (isTempFolderAvailable()) {
47
+ const tokenFile = join(getTempFolder(), `${cacheKey}.json`);
48
+ if (existsSync(tokenFile)) {
49
+ try {
50
+ const parsed = JSON.parse(readFileSync(tokenFile, 'utf8'));
51
+ if (parsed.expiresAt > Date.now()) {
52
+ tokenCache.set(cacheKey, parsed);
53
+ process.env[envName] = JSON.stringify(parsed);
54
+ return parsed;
55
+ }
56
+ }
57
+ catch { }
58
+ }
59
+ }
60
+ return null;
61
+ }
62
+ function saveToCache(cacheKey, token) {
63
+ tokenCache.set(cacheKey, token);
64
+ const envName = `DSQL_TOKEN_${cacheKey}`;
65
+ process.env[envName] = JSON.stringify(token);
66
+ if (isTempFolderAvailable()) {
67
+ const tokenFile = join(getTempFolder(), `${cacheKey}.json`);
68
+ try {
69
+ writeFileSync(tokenFile, JSON.stringify(token));
70
+ }
71
+ catch { }
72
+ }
73
+ }
74
+ let DsqlSigner = null;
75
+ async function loadAwsSdk() {
76
+ if (!DsqlSigner) {
77
+ try {
78
+ const sdk = await import('@aws-sdk/dsql-signer');
79
+ DsqlSigner = sdk.DsqlSigner;
80
+ }
81
+ catch (error) {
82
+ throw new RelqConfigError('AWS DSQL requires @aws-sdk/dsql-signer package.\n\n' +
83
+ 'Install it with:\n' +
84
+ ' npm install @aws-sdk/dsql-signer\n' +
85
+ ' # or\n' +
86
+ ' bun add @aws-sdk/dsql-signer', { field: '@aws-sdk/dsql-signer', value: 'not installed' });
87
+ }
88
+ }
89
+ return DsqlSigner;
90
+ }
91
+ export async function getAwsDsqlToken(config) {
92
+ const cacheKey = getCacheKey(config);
93
+ const cached = getFromCache(cacheKey);
94
+ if (cached) {
95
+ return cached.token;
96
+ }
97
+ if (!config.useDefaultCredentials && (!config.accessKeyId || !config.secretAccessKey)) {
98
+ throw new RelqConfigError('AWS DSQL requires credentials. Either provide accessKeyId + secretAccessKey, ' +
99
+ 'or set useDefaultCredentials: true to use AWS credential chain.', { field: 'aws.credentials', value: 'missing' });
100
+ }
101
+ const SignerClass = await loadAwsSdk();
102
+ const expiresIn = config.tokenExpiresIn ?? 604800;
103
+ const signerConfig = {
104
+ hostname: config.hostname,
105
+ region: config.region,
106
+ expiresIn,
107
+ };
108
+ if (!config.useDefaultCredentials) {
109
+ signerConfig.credentials = {
110
+ accessKeyId: config.accessKeyId,
111
+ secretAccessKey: config.secretAccessKey,
112
+ };
113
+ }
114
+ const signer = new SignerClass(signerConfig);
115
+ const token = await signer.getDbConnectAdminAuthToken();
116
+ const cachedToken = {
117
+ token,
118
+ expiresAt: Date.now() + ((expiresIn - 30) * 1000)
119
+ };
120
+ saveToCache(cacheKey, cachedToken);
121
+ return token;
122
+ }
123
+ export function clearAwsDsqlToken(config) {
124
+ const cacheKey = getCacheKey(config);
125
+ tokenCache.delete(cacheKey);
126
+ const envName = `DSQL_TOKEN_${cacheKey}`;
127
+ delete process.env[envName];
128
+ if (isTempFolderAvailable()) {
129
+ const tokenFile = join(getTempFolder(), `${cacheKey}.json`);
130
+ try {
131
+ if (existsSync(tokenFile)) {
132
+ writeFileSync(tokenFile, '');
133
+ }
134
+ }
135
+ catch { }
136
+ }
137
+ }
138
+ export function isAwsDsql(config) {
139
+ return !!config.aws?.hostname && !!config.aws?.region;
140
+ }