@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,327 @@
1
+ import { INTERNAL } from "./methods.js";
2
+ import { executeTypeSafeJoin, executeTypeSafeJoinMany, executeTypeSafeJoinManyThrough } from "./select-joins.js";
3
+ import { executeCursorEach, executePagination } from "./select-pagination.js";
4
+ import { requireCapability } from "./capability-guard.js";
5
+ import { createTableAccessor } from "../shared/table-accessor.js";
6
+ import { AggregateFunctions } from "../../select/sql-expression.js";
7
+ import { createTableProxy } from "../../select/table-proxy.js";
8
+ import { resolveForeignKey } from "../../utils/fk-resolver.js";
9
+ export class ConnectedSelectBuilder {
10
+ builder;
11
+ relq;
12
+ tableName;
13
+ columns;
14
+ schemaKey;
15
+ constructor(builder, relq, tableName, columns, schemaKey) {
16
+ this.builder = builder;
17
+ this.relq = relq;
18
+ this.tableName = tableName;
19
+ this.columns = columns;
20
+ this.schemaKey = schemaKey;
21
+ this.setupColumnResolver();
22
+ }
23
+ get joinCtx() {
24
+ return { relq: this.relq, builder: this.builder, tableName: this.tableName, schemaKey: this.schemaKey };
25
+ }
26
+ get paginationCtx() {
27
+ return { relq: this.relq, builder: this.builder, tableName: this.tableName };
28
+ }
29
+ setupColumnResolver() {
30
+ const internal = this.relq[INTERNAL];
31
+ const tableKey = this.schemaKey || this.tableName;
32
+ const tableDef = internal.getTableDef(tableKey);
33
+ if (!tableDef) {
34
+ return;
35
+ }
36
+ const tableColumns = tableDef.$columns || tableDef;
37
+ this.builder.setColumnResolver((column) => {
38
+ const columnDef = tableColumns[column];
39
+ if (columnDef) {
40
+ return columnDef.$columnName || column;
41
+ }
42
+ return column;
43
+ });
44
+ }
45
+ transformJoinResults(rows) {
46
+ const joins = this.builder.getStructuredJoins();
47
+ if (joins.length === 0) {
48
+ return rows;
49
+ }
50
+ const internal = this.relq[INTERNAL];
51
+ return rows.map(row => {
52
+ if (!row || typeof row !== 'object')
53
+ return row;
54
+ const transformed = { ...row };
55
+ for (const join of joins) {
56
+ const alias = join.alias;
57
+ const nestedData = transformed[alias];
58
+ if (nestedData === null || nestedData === undefined) {
59
+ continue;
60
+ }
61
+ const joinedTableDef = internal.getTableDef(join.schemaKey || alias) || internal.getTableDef(join.table);
62
+ if (!joinedTableDef) {
63
+ continue;
64
+ }
65
+ const tableColumns = joinedTableDef.$columns || joinedTableDef;
66
+ const dbToProp = new Map();
67
+ const propTypes = new Map();
68
+ for (const [propName, colDef] of Object.entries(tableColumns)) {
69
+ const dbColName = colDef?.$columnName ?? propName;
70
+ dbToProp.set(dbColName, propName);
71
+ const snakeCase = propName.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
72
+ if (snakeCase !== propName && !dbToProp.has(snakeCase)) {
73
+ dbToProp.set(snakeCase, propName);
74
+ }
75
+ const sqlType = colDef?.$sqlType || (typeof colDef?.$type === 'string' ? colDef.$type : undefined);
76
+ if (sqlType) {
77
+ propTypes.set(propName, sqlType.toLowerCase());
78
+ }
79
+ }
80
+ if (Array.isArray(nestedData)) {
81
+ transformed[alias] = nestedData.map((item) => this.transformNestedObject(item, dbToProp, propTypes));
82
+ }
83
+ else {
84
+ transformed[alias] = this.transformNestedObject(nestedData, dbToProp, propTypes);
85
+ }
86
+ }
87
+ return transformed;
88
+ });
89
+ }
90
+ transformNestedObject(obj, dbToProp, propTypes) {
91
+ if (!obj || typeof obj !== 'object')
92
+ return obj;
93
+ const result = {};
94
+ for (const [key, value] of Object.entries(obj)) {
95
+ const propName = dbToProp.get(key) ?? key;
96
+ result[propName] = propTypes ? this.coerceValue(value, propTypes.get(propName)) : value;
97
+ }
98
+ return result;
99
+ }
100
+ coerceValue(value, sqlType) {
101
+ if (value === null || value === undefined || !sqlType)
102
+ return value;
103
+ switch (sqlType) {
104
+ case 'timestamp':
105
+ case 'timestamptz':
106
+ case 'timestamp without time zone':
107
+ case 'timestamp with time zone':
108
+ return typeof value === 'string' ? new Date(value) : value;
109
+ case 'bigint':
110
+ case 'int8':
111
+ return typeof value === 'number' ? BigInt(value) : typeof value === 'string' ? BigInt(value) : value;
112
+ default:
113
+ return value;
114
+ }
115
+ }
116
+ where(callback) {
117
+ this.builder.where((q) => {
118
+ q._tables = createTableAccessor(this.relq, this.relq.schema);
119
+ return callback(q);
120
+ });
121
+ return this;
122
+ }
123
+ orderBy(column, direction) {
124
+ const dbColumn = this.relq[INTERNAL].hasColumnMapping()
125
+ ? Object.keys(this.relq[INTERNAL].transformToDbColumns(this.tableName, { [column]: true }))[0]
126
+ : column;
127
+ this.builder.orderBy(dbColumn, direction);
128
+ return this;
129
+ }
130
+ orderByNulls(column, direction, nulls) {
131
+ const dbColumn = this.relq[INTERNAL].hasColumnMapping()
132
+ ? Object.keys(this.relq[INTERNAL].transformToDbColumns(this.tableName, { [column]: true }))[0]
133
+ : column;
134
+ this.builder.orderByNulls(dbColumn, direction, nulls);
135
+ return this;
136
+ }
137
+ limit(count) {
138
+ this.builder.limit(count);
139
+ return this;
140
+ }
141
+ offset(count) {
142
+ this.builder.offset(count);
143
+ return this;
144
+ }
145
+ groupBy(...columns) {
146
+ const dbColumns = this.relq[INTERNAL].hasColumnMapping()
147
+ ? columns.map(col => Object.keys(this.relq[INTERNAL].transformToDbColumns(this.tableName, { [col]: true }))[0])
148
+ : columns;
149
+ this.builder.groupBy(...dbColumns);
150
+ return this;
151
+ }
152
+ having(callback) {
153
+ this.builder.having(callback);
154
+ return this;
155
+ }
156
+ include(callback) {
157
+ const agg = new AggregateFunctions();
158
+ const internal = this.relq[INTERNAL];
159
+ const schema = internal.getSchema() || {};
160
+ const sourceSchemaKey = this.schemaKey || this.tableName;
161
+ const sourceAlias = this.builder.getTableIdentifier();
162
+ const tableProxies = new Proxy({}, {
163
+ get(_, tableKey) {
164
+ if (typeof tableKey === 'symbol')
165
+ return undefined;
166
+ const tableDef = schema[tableKey];
167
+ const tableName = tableDef?.$name || tableKey;
168
+ const alias = tableKey === sourceSchemaKey ? sourceAlias : tableKey;
169
+ return createTableProxy(tableName, alias, tableDef);
170
+ }
171
+ });
172
+ const expressions = callback(agg, tableProxies);
173
+ for (const [alias, expr] of Object.entries(expressions)) {
174
+ this.builder.addIncludeExpression(alias, expr.sql);
175
+ }
176
+ return this;
177
+ }
178
+ join(tableOrAlias, callback) {
179
+ executeTypeSafeJoin(this.joinCtx, 'JOIN', tableOrAlias, callback);
180
+ return this;
181
+ }
182
+ leftJoin(tableOrAlias, callback) {
183
+ executeTypeSafeJoin(this.joinCtx, 'LEFT JOIN', tableOrAlias, callback);
184
+ return this;
185
+ }
186
+ rightJoin(tableOrAlias, callback) {
187
+ executeTypeSafeJoin(this.joinCtx, 'RIGHT JOIN', tableOrAlias, callback);
188
+ return this;
189
+ }
190
+ innerJoin(tableOrAlias, callback) {
191
+ executeTypeSafeJoin(this.joinCtx, 'INNER JOIN', tableOrAlias, callback);
192
+ return this;
193
+ }
194
+ joinSubquery(alias, subquery, onClause) {
195
+ const subquerySQL = typeof subquery === 'string' ? subquery : subquery.toString();
196
+ this.builder.addRawJoin(`JOIN (${subquerySQL}) AS "${alias}" ON ${onClause}`);
197
+ return this;
198
+ }
199
+ leftJoinSubquery(alias, subquery, onClause) {
200
+ const subquerySQL = typeof subquery === 'string' ? subquery : subquery.toString();
201
+ this.builder.addRawJoin(`LEFT JOIN (${subquerySQL}) AS "${alias}" ON ${onClause}`);
202
+ return this;
203
+ }
204
+ joinMany(tableOrAlias, callbackOrOptions, throughCallback) {
205
+ requireCapability(this.relq, 'lateral', 'LATERAL JOIN (joinMany)', 'Use separate queries for one-to-many relationships');
206
+ if (callbackOrOptions && typeof callbackOrOptions === 'object' && 'through' in callbackOrOptions) {
207
+ executeTypeSafeJoinManyThrough(this.joinCtx, 'JOIN', tableOrAlias, callbackOrOptions.through, throughCallback);
208
+ }
209
+ else {
210
+ executeTypeSafeJoinMany(this.joinCtx, 'JOIN', tableOrAlias, callbackOrOptions);
211
+ }
212
+ return this;
213
+ }
214
+ leftJoinMany(tableOrAlias, callbackOrOptions, throughCallback) {
215
+ requireCapability(this.relq, 'lateral', 'LATERAL JOIN (leftJoinMany)', 'Use separate queries for one-to-many relationships');
216
+ if (callbackOrOptions && typeof callbackOrOptions === 'object' && 'through' in callbackOrOptions) {
217
+ executeTypeSafeJoinManyThrough(this.joinCtx, 'LEFT JOIN', tableOrAlias, callbackOrOptions.through, throughCallback);
218
+ }
219
+ else {
220
+ executeTypeSafeJoinMany(this.joinCtx, 'LEFT JOIN', tableOrAlias, callbackOrOptions);
221
+ }
222
+ return this;
223
+ }
224
+ with(table) {
225
+ executeTypeSafeJoin(this.joinCtx, 'LEFT JOIN', table);
226
+ return this;
227
+ }
228
+ withMany(table, options) {
229
+ requireCapability(this.relq, 'lateral', 'LATERAL JOIN (withMany)', 'Use separate queries for one-to-many relationships');
230
+ if (options && 'through' in options) {
231
+ executeTypeSafeJoinManyThrough(this.joinCtx, 'LEFT JOIN', table, options.through);
232
+ return this;
233
+ }
234
+ const internal = this.relq[INTERNAL];
235
+ const schema = internal.getSchema();
236
+ const relations = internal.getRelations();
237
+ if (!schema || !relations) {
238
+ throw new Error(`Cannot use .withMany('${table}') without schema and relations config. ` +
239
+ `Use .leftJoinMany() with an explicit callback instead.`);
240
+ }
241
+ const sourceKey = this.schemaKey || this.tableName;
242
+ const fk = resolveForeignKey(relations, schema, sourceKey, table);
243
+ if (!fk) {
244
+ throw new Error(`No FK relationship found between "${sourceKey}" and "${table}". ` +
245
+ `Use .leftJoinMany() with explicit join conditions instead.`);
246
+ }
247
+ executeTypeSafeJoinMany(this.joinCtx, 'LEFT JOIN', table, (on, right, left) => {
248
+ const rightCol = right[fk.toColumn];
249
+ const leftCol = left[fk.fromColumn];
250
+ return on.equal(rightCol, leftCol);
251
+ });
252
+ return this;
253
+ }
254
+ distinct() {
255
+ this.builder.distinct();
256
+ return this;
257
+ }
258
+ distinctOn(...columns) {
259
+ requireCapability(this.relq, 'distinctOn', 'DISTINCT ON', 'Use GROUP BY with appropriate aggregation instead');
260
+ this.builder.distinctOn(...columns);
261
+ return this;
262
+ }
263
+ union(query) {
264
+ this.builder.union(typeof query === 'string' ? query : query.toString());
265
+ return this;
266
+ }
267
+ unionAll(query) {
268
+ this.builder.unionAll(typeof query === 'string' ? query : query.toString());
269
+ return this;
270
+ }
271
+ intersect(query) {
272
+ this.builder.intersect(typeof query === 'string' ? query : query.toString());
273
+ return this;
274
+ }
275
+ except(query) {
276
+ this.builder.except(typeof query === 'string' ? query : query.toString());
277
+ return this;
278
+ }
279
+ forUpdate() {
280
+ this.builder.forUpdate();
281
+ return this;
282
+ }
283
+ forUpdateSkipLocked() {
284
+ requireCapability(this.relq, 'forUpdateSkipLocked', 'FOR UPDATE SKIP LOCKED', 'Use FOR UPDATE without SKIP LOCKED');
285
+ this.builder.forUpdateSkipLocked();
286
+ return this;
287
+ }
288
+ forShare() {
289
+ this.builder.forShare();
290
+ return this;
291
+ }
292
+ toString() {
293
+ return this.builder.toString();
294
+ }
295
+ async all(withMetadata, _asRequired) {
296
+ const sql = this.builder.toString();
297
+ const result = await this.relq[INTERNAL].executeSelect(sql, this.tableName);
298
+ const transformedData = this.transformJoinResults(result.data);
299
+ if (withMetadata) {
300
+ return { data: transformedData, metadata: result.metadata };
301
+ }
302
+ return transformedData;
303
+ }
304
+ async get(withMetadata, _asRequired) {
305
+ this.builder.limit(1);
306
+ const sql = this.builder.toString();
307
+ const result = await this.relq[INTERNAL].executeSelectOne(sql, this.tableName);
308
+ const transformedData = result.data ? this.transformJoinResults([result.data])[0] : null;
309
+ if (withMetadata) {
310
+ return { data: transformedData, metadata: result.metadata };
311
+ }
312
+ return transformedData;
313
+ }
314
+ async value(column) {
315
+ this.builder.limit(1);
316
+ const sql = this.builder.toString();
317
+ const result = await this.relq[INTERNAL].executeSelectOne(sql, this.tableName);
318
+ return result.data?.[column] ?? null;
319
+ }
320
+ async each(callback, options = {}) {
321
+ requireCapability(this.relq, 'cursors', 'Cursor-based iteration (each)', 'Use pagination() instead of each() for row-by-row processing');
322
+ return executeCursorEach(this.paginationCtx, callback, options);
323
+ }
324
+ async pagination(options) {
325
+ return executePagination(this.paginationCtx, options, (opts) => this.pagination(opts));
326
+ }
327
+ }
@@ -0,0 +1,100 @@
1
+ import { ConnectedRawQueryBuilder } from "./ConnectedRawQueryBuilder.js";
2
+ import { createTableAccessor } from "../shared/table-accessor.js";
3
+ import { INTERNAL } from "./methods.js";
4
+ export class TransactionClient {
5
+ client;
6
+ relq;
7
+ schema;
8
+ constructor(client, relq) {
9
+ this.client = client;
10
+ this.relq = relq;
11
+ const internal = this.relq[INTERNAL];
12
+ this.schema = internal.getSchema?.() ?? this.relq.schema;
13
+ }
14
+ get dialect() { return this.relq.dialect; }
15
+ get capabilities() { return this.relq.capabilities; }
16
+ get table() {
17
+ return createTableAccessor(this, this.schema);
18
+ }
19
+ raw(query, ...params) {
20
+ return new ConnectedRawQueryBuilder(query, params, this);
21
+ }
22
+ get [INTERNAL]() {
23
+ const parentInternal = this.relq[INTERNAL];
24
+ const queryViaClient = async (sql) => {
25
+ const start = performance.now();
26
+ const pgResult = await this.client.query(sql);
27
+ return {
28
+ result: {
29
+ rows: pgResult.rows,
30
+ rowCount: pgResult.rowCount,
31
+ command: pgResult.command,
32
+ fields: pgResult.fields?.map((f) => ({ name: f.name, dataTypeID: f.dataTypeID })) ?? [],
33
+ },
34
+ duration: performance.now() - start,
35
+ };
36
+ };
37
+ const buildMetadata = (result, duration) => ({
38
+ rowCount: result.rowCount,
39
+ command: result.command,
40
+ duration,
41
+ fields: result.fields,
42
+ });
43
+ return {
44
+ executeQuery: queryViaClient,
45
+ async executeSelect(sql, tableName) {
46
+ const { result, duration } = await queryViaClient(sql);
47
+ const rows = tableName
48
+ ? parentInternal.transformResultsFromDb(tableName, result.rows)
49
+ : result.rows;
50
+ return { data: rows, metadata: buildMetadata(result, duration) };
51
+ },
52
+ async executeSelectOne(sql, tableName) {
53
+ const { result, duration } = await queryViaClient(sql);
54
+ const row = result.rows[0]
55
+ ? (tableName ? parentInternal.transformFromDbColumns(tableName, result.rows[0]) : result.rows[0])
56
+ : null;
57
+ return { data: row, metadata: buildMetadata(result, duration) };
58
+ },
59
+ async executeCount(sql) {
60
+ const { result, duration } = await queryViaClient(sql);
61
+ const count = result.rows[0]?.count ? parseInt(result.rows[0].count, 10) : 0;
62
+ return { count, metadata: buildMetadata(result, duration) };
63
+ },
64
+ async executeRun(sql) {
65
+ const { result, duration } = await queryViaClient(sql);
66
+ return { success: true, metadata: buildMetadata(result, duration) };
67
+ },
68
+ transformToDbColumns: parentInternal.transformToDbColumns,
69
+ transformFromDbColumns: parentInternal.transformFromDbColumns,
70
+ transformResultsFromDb: parentInternal.transformResultsFromDb,
71
+ hasColumnMapping: parentInternal.hasColumnMapping,
72
+ validateData: parentInternal.validateData,
73
+ getSchema: parentInternal.getSchema,
74
+ getRelations: parentInternal.getRelations,
75
+ getTableDef: parentInternal.getTableDef,
76
+ getClientForCursor: async () => ({ client: this.client, release: () => { } }),
77
+ };
78
+ }
79
+ }
80
+ export async function executeTransaction(relq, callback) {
81
+ await relq.ensureInitialized();
82
+ const { client, release } = await relq[INTERNAL].getClientForCursor();
83
+ try {
84
+ await client.query('BEGIN');
85
+ const tx = new TransactionClient(client, relq);
86
+ const result = await callback(tx);
87
+ await client.query('COMMIT');
88
+ return result;
89
+ }
90
+ catch (error) {
91
+ try {
92
+ await client.query('ROLLBACK');
93
+ }
94
+ catch { }
95
+ throw error;
96
+ }
97
+ finally {
98
+ release();
99
+ }
100
+ }
@@ -0,0 +1,75 @@
1
+ import { INTERNAL } from "./methods.js";
2
+ import { ReturningExecutor } from "./ReturningExecutor.js";
3
+ import { requireCapability } from "./capability-guard.js";
4
+ import { createTableAccessor } from "../shared/table-accessor.js";
5
+ export class ConnectedUpdateBuilder {
6
+ builder;
7
+ relq;
8
+ tableName;
9
+ schemaKey;
10
+ constructor(builder, relq, tableName, schemaKey) {
11
+ this.builder = builder;
12
+ this.relq = relq;
13
+ this.tableName = tableName;
14
+ this.schemaKey = schemaKey;
15
+ this.setupColumnResolver();
16
+ }
17
+ setupColumnResolver() {
18
+ if (!this.tableName && !this.schemaKey) {
19
+ return;
20
+ }
21
+ const internal = this.relq[INTERNAL];
22
+ const tableDef = internal.getTableDef(this.schemaKey || this.tableName);
23
+ if (!tableDef) {
24
+ return;
25
+ }
26
+ const tableColumns = tableDef.$columns || tableDef;
27
+ this.builder.setColumnResolver((column) => {
28
+ const columnDef = tableColumns[column];
29
+ if (columnDef) {
30
+ return columnDef.$columnName || column;
31
+ }
32
+ return column;
33
+ });
34
+ this.builder.setColumnTypeResolver((column) => {
35
+ const columnDef = tableColumns[column];
36
+ if (!columnDef) {
37
+ return undefined;
38
+ }
39
+ const type = columnDef.$type;
40
+ if (typeof type !== 'string') {
41
+ return undefined;
42
+ }
43
+ const isArray = columnDef.$array === true;
44
+ const baseType = type.replace(/\[\]$/, '').toLowerCase();
45
+ return { type: baseType, isArray };
46
+ });
47
+ }
48
+ where(callback) {
49
+ this.builder.where((q) => {
50
+ q._tables = createTableAccessor(this.relq, this.relq.schema);
51
+ return callback(q);
52
+ });
53
+ return this;
54
+ }
55
+ toString() {
56
+ return this.builder.toString();
57
+ }
58
+ async run(withMetadata) {
59
+ this.relq[INTERNAL].validateData(this.builder.tableName, this.builder.updateData, 'update');
60
+ const sql = this.builder.toString();
61
+ const result = await this.relq[INTERNAL].executeRun(sql);
62
+ if (withMetadata) {
63
+ return result;
64
+ }
65
+ return result.metadata.rowCount ?? 0;
66
+ }
67
+ returning(columns) {
68
+ if (columns === null) {
69
+ return this;
70
+ }
71
+ requireCapability(this.relq, 'returning', 'RETURNING clause', 'Use a SELECT query after the UPDATE to retrieve modified data');
72
+ this.builder.returning(columns);
73
+ return new ReturningExecutor(this.builder, this.relq, this.tableName, this.schemaKey);
74
+ }
75
+ }
@@ -0,0 +1,174 @@
1
+ import { CountBuilder } from "../../count/count-builder.js";
2
+ import { RelqQueryError } from "../../../shared/errors/relq-errors.js";
3
+ import { SelectBuilder } from "../../select/select-builder.js";
4
+ import { INTERNAL } from "./methods.js";
5
+ export class PaginateBuilder {
6
+ relq;
7
+ tableName;
8
+ columns;
9
+ whereClause;
10
+ orderByClause;
11
+ constructor(relq, tableName, columns, whereClause, orderByClause) {
12
+ this.relq = relq;
13
+ this.tableName = tableName;
14
+ this.columns = columns;
15
+ this.whereClause = whereClause;
16
+ this.orderByClause = orderByClause;
17
+ }
18
+ async paging(options) {
19
+ const page = options.page ?? 1;
20
+ const perPage = options.perPage;
21
+ const shouldCount = options.count ?? true;
22
+ if (page < 1) {
23
+ throw new RelqQueryError('page must be >= 1', { hint: 'Page numbers are 1-indexed' });
24
+ }
25
+ if (perPage < 1) {
26
+ throw new RelqQueryError('perPage must be >= 1');
27
+ }
28
+ const columnsToSelect = this.columns && this.columns.length > 0 ? this.columns : ['*'];
29
+ const orderByArr = this.orderByClause
30
+ ? (Array.isArray(this.orderByClause[0]) ? this.orderByClause : [this.orderByClause])
31
+ : [];
32
+ const selectBuilder = new SelectBuilder(this.tableName, columnsToSelect);
33
+ if (this.whereClause) {
34
+ selectBuilder.where(this.whereClause);
35
+ }
36
+ for (const [column, direction] of orderByArr) {
37
+ const dbColumn = this.relq[INTERNAL].transformToDbColumns(this.tableName, { [column]: true });
38
+ selectBuilder.orderBy(Object.keys(dbColumn)[0] || column, direction);
39
+ }
40
+ let total = 0;
41
+ if (shouldCount) {
42
+ const countBuilder = new CountBuilder(this.tableName);
43
+ if (this.whereClause) {
44
+ countBuilder.where(this.whereClause);
45
+ }
46
+ const countResult = await this.relq[INTERNAL].executeCount(countBuilder.toString());
47
+ total = countResult.count;
48
+ }
49
+ const offset = (page - 1) * perPage;
50
+ selectBuilder.limit(perPage);
51
+ selectBuilder.offset(offset);
52
+ const result = await this.relq[INTERNAL].executeSelect(selectBuilder.toString(), this.tableName);
53
+ const totalPages = Math.ceil(total / perPage);
54
+ const hasNext = page < totalPages;
55
+ const hasPrev = page > 1;
56
+ const pagination = {
57
+ page,
58
+ perPage,
59
+ total,
60
+ totalPages,
61
+ };
62
+ if (hasNext) {
63
+ pagination.hasNext = true;
64
+ pagination.nextPage = page + 1;
65
+ Object.defineProperty(pagination, 'loadNext', {
66
+ value: () => this.paging({ ...options, page: page + 1 }),
67
+ enumerable: false
68
+ });
69
+ }
70
+ else {
71
+ pagination.hasNext = false;
72
+ }
73
+ if (hasPrev) {
74
+ pagination.hasPrev = true;
75
+ pagination.prevPage = page - 1;
76
+ Object.defineProperty(pagination, 'loadPrev', {
77
+ value: () => this.paging({ ...options, page: page - 1 }),
78
+ enumerable: false
79
+ });
80
+ }
81
+ else {
82
+ pagination.hasPrev = false;
83
+ }
84
+ Object.defineProperty(pagination, 'toJSON', {
85
+ value: () => ({ page, perPage, total, totalPages, hasNext: pagination.hasNext, hasPrev: pagination.hasPrev, nextPage: pagination.nextPage, prevPage: pagination.prevPage }),
86
+ enumerable: false
87
+ });
88
+ return { data: result.data, pagination };
89
+ }
90
+ async offset(options) {
91
+ const position = options.position ?? 0;
92
+ const shouldCount = options.count ?? false;
93
+ if (position < 0) {
94
+ throw new RelqQueryError('position must be >= 0');
95
+ }
96
+ let limit;
97
+ if (options.shuffleLimit) {
98
+ const [min, max] = options.shuffleLimit;
99
+ if (min < 1 || max < 1) {
100
+ throw new RelqQueryError('shuffleLimit values must be >= 1', { hint: 'Use [min, max] where both are >= 1' });
101
+ }
102
+ if (min > max) {
103
+ throw new RelqQueryError('shuffleLimit[0] must be <= shuffleLimit[1]', { hint: 'Use [min, max] format where min <= max' });
104
+ }
105
+ limit = Math.floor(Math.random() * (max - min + 1)) + min;
106
+ }
107
+ else {
108
+ const limitValue = options.limit;
109
+ if (limitValue !== undefined && limitValue < 1) {
110
+ throw new RelqQueryError('limit must be >= 1');
111
+ }
112
+ limit = limitValue ?? 50;
113
+ }
114
+ const columnsToSelect = this.columns && this.columns.length > 0 ? this.columns : ['*'];
115
+ const orderByArr = this.orderByClause
116
+ ? (Array.isArray(this.orderByClause[0]) ? this.orderByClause : [this.orderByClause])
117
+ : [];
118
+ const selectBuilder = new SelectBuilder(this.tableName, columnsToSelect);
119
+ if (this.whereClause) {
120
+ selectBuilder.where(this.whereClause);
121
+ }
122
+ for (const [column, direction] of orderByArr) {
123
+ const dbColumn = this.relq[INTERNAL].transformToDbColumns(this.tableName, { [column]: true });
124
+ selectBuilder.orderBy(Object.keys(dbColumn)[0] || column, direction);
125
+ }
126
+ let total = 0;
127
+ if (shouldCount) {
128
+ const countBuilder = new CountBuilder(this.tableName);
129
+ if (this.whereClause) {
130
+ countBuilder.where(this.whereClause);
131
+ }
132
+ const countResult = await this.relq[INTERNAL].executeCount(countBuilder.toString());
133
+ total = countResult.count;
134
+ }
135
+ selectBuilder.limit(limit + 1);
136
+ selectBuilder.offset(position);
137
+ const result = await this.relq[INTERNAL].executeSelect(selectBuilder.toString(), this.tableName);
138
+ const hasMore = result.data.length > limit;
139
+ const data = hasMore ? result.data.slice(0, limit) : result.data;
140
+ const hasPrev = position > 0;
141
+ const pagination = {
142
+ position,
143
+ limit,
144
+ total,
145
+ };
146
+ if (hasMore) {
147
+ pagination.hasMore = true;
148
+ pagination.nextPos = position + limit;
149
+ Object.defineProperty(pagination, 'loadNext', {
150
+ value: () => this.offset({ ...options, position: position + limit }),
151
+ enumerable: false
152
+ });
153
+ }
154
+ else {
155
+ pagination.hasMore = false;
156
+ }
157
+ if (hasPrev) {
158
+ pagination.hasPrev = true;
159
+ pagination.prevPos = Math.max(0, position - limit);
160
+ Object.defineProperty(pagination, 'loadPrev', {
161
+ value: () => this.offset({ ...options, position: Math.max(0, position - limit) }),
162
+ enumerable: false
163
+ });
164
+ }
165
+ else {
166
+ pagination.hasPrev = false;
167
+ }
168
+ Object.defineProperty(pagination, 'toJSON', {
169
+ value: () => ({ position, limit, total, hasMore: pagination.hasMore, hasPrev: pagination.hasPrev, nextPos: pagination.nextPos, prevPos: pagination.prevPos }),
170
+ enumerable: false
171
+ });
172
+ return { data, pagination };
173
+ }
174
+ }