@tanstack/db 0.0.1

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 (154) hide show
  1. package/README.md +37 -0
  2. package/dist/cjs/SortedMap.cjs +140 -0
  3. package/dist/cjs/SortedMap.cjs.map +1 -0
  4. package/dist/cjs/SortedMap.d.cts +91 -0
  5. package/dist/cjs/collection.cjs +597 -0
  6. package/dist/cjs/collection.cjs.map +1 -0
  7. package/dist/cjs/collection.d.cts +176 -0
  8. package/dist/cjs/deferred.cjs +25 -0
  9. package/dist/cjs/deferred.cjs.map +1 -0
  10. package/dist/cjs/deferred.d.cts +20 -0
  11. package/dist/cjs/errors.cjs +10 -0
  12. package/dist/cjs/errors.cjs.map +1 -0
  13. package/dist/cjs/errors.d.cts +3 -0
  14. package/dist/cjs/index.cjs +33 -0
  15. package/dist/cjs/index.cjs.map +1 -0
  16. package/dist/cjs/index.d.cts +9 -0
  17. package/dist/cjs/proxy.cjs +654 -0
  18. package/dist/cjs/proxy.cjs.map +1 -0
  19. package/dist/cjs/proxy.d.cts +59 -0
  20. package/dist/cjs/query/compiled-query.cjs +162 -0
  21. package/dist/cjs/query/compiled-query.cjs.map +1 -0
  22. package/dist/cjs/query/compiled-query.d.cts +22 -0
  23. package/dist/cjs/query/evaluators.cjs +146 -0
  24. package/dist/cjs/query/evaluators.cjs.map +1 -0
  25. package/dist/cjs/query/evaluators.d.cts +9 -0
  26. package/dist/cjs/query/extractors.cjs +122 -0
  27. package/dist/cjs/query/extractors.cjs.map +1 -0
  28. package/dist/cjs/query/extractors.d.cts +22 -0
  29. package/dist/cjs/query/functions.cjs +152 -0
  30. package/dist/cjs/query/functions.cjs.map +1 -0
  31. package/dist/cjs/query/functions.d.cts +21 -0
  32. package/dist/cjs/query/group-by.cjs +91 -0
  33. package/dist/cjs/query/group-by.cjs.map +1 -0
  34. package/dist/cjs/query/group-by.d.cts +40 -0
  35. package/dist/cjs/query/index.d.cts +5 -0
  36. package/dist/cjs/query/joins.cjs +155 -0
  37. package/dist/cjs/query/joins.cjs.map +1 -0
  38. package/dist/cjs/query/joins.d.cts +14 -0
  39. package/dist/cjs/query/key-by.cjs +43 -0
  40. package/dist/cjs/query/key-by.cjs.map +1 -0
  41. package/dist/cjs/query/key-by.d.cts +3 -0
  42. package/dist/cjs/query/order-by.cjs +229 -0
  43. package/dist/cjs/query/order-by.cjs.map +1 -0
  44. package/dist/cjs/query/order-by.d.cts +3 -0
  45. package/dist/cjs/query/pipeline-compiler.cjs +94 -0
  46. package/dist/cjs/query/pipeline-compiler.cjs.map +1 -0
  47. package/dist/cjs/query/pipeline-compiler.d.cts +9 -0
  48. package/dist/cjs/query/query-builder.cjs +314 -0
  49. package/dist/cjs/query/query-builder.cjs.map +1 -0
  50. package/dist/cjs/query/query-builder.d.cts +219 -0
  51. package/dist/cjs/query/schema.d.cts +98 -0
  52. package/dist/cjs/query/select.cjs +107 -0
  53. package/dist/cjs/query/select.cjs.map +1 -0
  54. package/dist/cjs/query/select.d.cts +3 -0
  55. package/dist/cjs/query/types.d.cts +188 -0
  56. package/dist/cjs/query/utils.cjs +154 -0
  57. package/dist/cjs/query/utils.cjs.map +1 -0
  58. package/dist/cjs/query/utils.d.cts +37 -0
  59. package/dist/cjs/transactions.cjs +137 -0
  60. package/dist/cjs/transactions.cjs.map +1 -0
  61. package/dist/cjs/transactions.d.cts +27 -0
  62. package/dist/cjs/types.d.cts +94 -0
  63. package/dist/cjs/utils.cjs +17 -0
  64. package/dist/cjs/utils.cjs.map +1 -0
  65. package/dist/cjs/utils.d.cts +3 -0
  66. package/dist/esm/SortedMap.d.ts +91 -0
  67. package/dist/esm/SortedMap.js +140 -0
  68. package/dist/esm/SortedMap.js.map +1 -0
  69. package/dist/esm/collection.d.ts +176 -0
  70. package/dist/esm/collection.js +597 -0
  71. package/dist/esm/collection.js.map +1 -0
  72. package/dist/esm/deferred.d.ts +20 -0
  73. package/dist/esm/deferred.js +25 -0
  74. package/dist/esm/deferred.js.map +1 -0
  75. package/dist/esm/errors.d.ts +3 -0
  76. package/dist/esm/errors.js +10 -0
  77. package/dist/esm/errors.js.map +1 -0
  78. package/dist/esm/index.d.ts +9 -0
  79. package/dist/esm/index.js +33 -0
  80. package/dist/esm/index.js.map +1 -0
  81. package/dist/esm/proxy.d.ts +59 -0
  82. package/dist/esm/proxy.js +654 -0
  83. package/dist/esm/proxy.js.map +1 -0
  84. package/dist/esm/query/compiled-query.d.ts +22 -0
  85. package/dist/esm/query/compiled-query.js +162 -0
  86. package/dist/esm/query/compiled-query.js.map +1 -0
  87. package/dist/esm/query/evaluators.d.ts +9 -0
  88. package/dist/esm/query/evaluators.js +146 -0
  89. package/dist/esm/query/evaluators.js.map +1 -0
  90. package/dist/esm/query/extractors.d.ts +22 -0
  91. package/dist/esm/query/extractors.js +122 -0
  92. package/dist/esm/query/extractors.js.map +1 -0
  93. package/dist/esm/query/functions.d.ts +21 -0
  94. package/dist/esm/query/functions.js +152 -0
  95. package/dist/esm/query/functions.js.map +1 -0
  96. package/dist/esm/query/group-by.d.ts +40 -0
  97. package/dist/esm/query/group-by.js +91 -0
  98. package/dist/esm/query/group-by.js.map +1 -0
  99. package/dist/esm/query/index.d.ts +5 -0
  100. package/dist/esm/query/joins.d.ts +14 -0
  101. package/dist/esm/query/joins.js +155 -0
  102. package/dist/esm/query/joins.js.map +1 -0
  103. package/dist/esm/query/key-by.d.ts +3 -0
  104. package/dist/esm/query/key-by.js +43 -0
  105. package/dist/esm/query/key-by.js.map +1 -0
  106. package/dist/esm/query/order-by.d.ts +3 -0
  107. package/dist/esm/query/order-by.js +229 -0
  108. package/dist/esm/query/order-by.js.map +1 -0
  109. package/dist/esm/query/pipeline-compiler.d.ts +9 -0
  110. package/dist/esm/query/pipeline-compiler.js +94 -0
  111. package/dist/esm/query/pipeline-compiler.js.map +1 -0
  112. package/dist/esm/query/query-builder.d.ts +219 -0
  113. package/dist/esm/query/query-builder.js +314 -0
  114. package/dist/esm/query/query-builder.js.map +1 -0
  115. package/dist/esm/query/schema.d.ts +98 -0
  116. package/dist/esm/query/select.d.ts +3 -0
  117. package/dist/esm/query/select.js +107 -0
  118. package/dist/esm/query/select.js.map +1 -0
  119. package/dist/esm/query/types.d.ts +188 -0
  120. package/dist/esm/query/utils.d.ts +37 -0
  121. package/dist/esm/query/utils.js +154 -0
  122. package/dist/esm/query/utils.js.map +1 -0
  123. package/dist/esm/transactions.d.ts +27 -0
  124. package/dist/esm/transactions.js +137 -0
  125. package/dist/esm/transactions.js.map +1 -0
  126. package/dist/esm/types.d.ts +94 -0
  127. package/dist/esm/utils.d.ts +3 -0
  128. package/dist/esm/utils.js +17 -0
  129. package/dist/esm/utils.js.map +1 -0
  130. package/package.json +57 -0
  131. package/src/SortedMap.ts +163 -0
  132. package/src/collection.ts +919 -0
  133. package/src/deferred.ts +47 -0
  134. package/src/errors.ts +6 -0
  135. package/src/index.ts +12 -0
  136. package/src/proxy.ts +1104 -0
  137. package/src/query/compiled-query.ts +193 -0
  138. package/src/query/evaluators.ts +222 -0
  139. package/src/query/extractors.ts +211 -0
  140. package/src/query/functions.ts +297 -0
  141. package/src/query/group-by.ts +137 -0
  142. package/src/query/index.ts +5 -0
  143. package/src/query/joins.ts +247 -0
  144. package/src/query/key-by.ts +61 -0
  145. package/src/query/order-by.ts +312 -0
  146. package/src/query/pipeline-compiler.ts +152 -0
  147. package/src/query/query-builder.ts +898 -0
  148. package/src/query/schema.ts +255 -0
  149. package/src/query/select.ts +173 -0
  150. package/src/query/types.ts +417 -0
  151. package/src/query/utils.ts +245 -0
  152. package/src/transactions.ts +198 -0
  153. package/src/types.ts +125 -0
  154. package/src/utils.ts +15 -0
@@ -0,0 +1,255 @@
1
+ import type {
2
+ Context,
3
+ InputReference,
4
+ PropertyReference,
5
+ PropertyReferenceString,
6
+ WildcardReferenceString,
7
+ } from "./types.js"
8
+ import type { Collection } from "../collection"
9
+
10
+ // Identifiers
11
+ export type ColumnName<TColumnNames extends string> = TColumnNames
12
+
13
+ // JSONLike supports any JSON-compatible value plus Date objects.
14
+ export type JSONLike =
15
+ | string
16
+ | number
17
+ | boolean
18
+ | Date
19
+ | null
20
+ | Array<JSONLike>
21
+ | { [key: string]: JSONLike }
22
+
23
+ // LiteralValue supports common primitives, JS Date, or undefined.
24
+ // We exclude strings that start with "@" because they are property references.
25
+ export type LiteralValue =
26
+ | (string & {})
27
+ | number
28
+ | boolean
29
+ | Date
30
+ | null
31
+ | undefined
32
+
33
+ // These versions are for use with methods on the query builder where we want to
34
+ // ensure that the argument is a string that does not start with "@".
35
+ // Can be combined with PropertyReference for validating references.
36
+ export type SafeString<T extends string> = T extends `@${string}` ? never : T
37
+ export type OptionalSafeString<T extends any> = T extends string
38
+ ? SafeString<T>
39
+ : never
40
+ export type LiteralValueWithSafeString<T extends any> =
41
+ | (OptionalSafeString<T> & {})
42
+ | number
43
+ | boolean
44
+ | Date
45
+ | null
46
+ | undefined
47
+
48
+ // To force a literal value (which may be arbitrary JSON or a Date), wrap it in an object with the "value" key.
49
+ export interface ExplicitLiteral {
50
+ value: JSONLike
51
+ }
52
+
53
+ // Allowed function names (common SQL functions)
54
+ export type AllowedFunctionName =
55
+ | `DATE`
56
+ | `JSON_EXTRACT`
57
+ | `JSON_EXTRACT_PATH`
58
+ | `UPPER`
59
+ | `LOWER`
60
+ | `COALESCE`
61
+ | `CONCAT`
62
+ | `LENGTH`
63
+ | `ORDER_INDEX`
64
+
65
+ // A function call is represented as a union of objects—each having exactly one key that is one of the allowed function names.
66
+ export type FunctionCall<TContext extends Context = Context> = {
67
+ [K in AllowedFunctionName]: {
68
+ [key in K]: ConditionOperand<TContext> | Array<ConditionOperand<TContext>>
69
+ }
70
+ }[AllowedFunctionName]
71
+
72
+ export type AggregateFunctionName =
73
+ | `SUM`
74
+ | `COUNT`
75
+ | `AVG`
76
+ | `MIN`
77
+ | `MAX`
78
+ | `MEDIAN`
79
+ | `MODE`
80
+
81
+ export type AggregateFunctionCall<TContext extends Context = Context> = {
82
+ [K in AggregateFunctionName]: {
83
+ [key in K]: ConditionOperand<TContext> | Array<ConditionOperand<TContext>>
84
+ }
85
+ }[AggregateFunctionName]
86
+
87
+ /**
88
+ * An operand in a condition may be:
89
+ * - A literal value (LiteralValue)
90
+ * - A column reference (a string starting with "@" or an explicit { col: string } object)
91
+ * - An explicit literal (to wrap arbitrary JSON or Date values) as { value: ... }
92
+ * - A function call (as defined above)
93
+ * - An array of operands (for example, for "in" clauses)
94
+ */
95
+ export type ConditionOperand<
96
+ TContext extends Context = Context,
97
+ T extends any = any,
98
+ > =
99
+ | LiteralValue
100
+ | PropertyReference<TContext>
101
+ | ExplicitLiteral
102
+ | FunctionCall<TContext>
103
+ | Array<ConditionOperand<TContext, T>>
104
+
105
+ // Allowed SQL comparators.
106
+ export type Comparator =
107
+ | `=`
108
+ | `!=`
109
+ | `<`
110
+ | `<=`
111
+ | `>`
112
+ | `>=`
113
+ | `like`
114
+ | `not like`
115
+ | `in`
116
+ | `not in`
117
+ | `is`
118
+ | `is not`
119
+
120
+ // Logical operators.
121
+ export type LogicalOperator = `and` | `or`
122
+
123
+ // A simple condition is a tuple: [left operand, comparator, right operand].
124
+ export type SimpleCondition<
125
+ TContext extends Context = Context,
126
+ T extends any = any,
127
+ > = [ConditionOperand<TContext, T>, Comparator, ConditionOperand<TContext, T>]
128
+
129
+ // A flat composite condition allows all elements to be at the same level:
130
+ // [left1, op1, right1, 'and'/'or', left2, op2, right2, ...]
131
+ export type FlatCompositeCondition<
132
+ TContext extends Context = Context,
133
+ T extends any = any,
134
+ > = [
135
+ ConditionOperand<TContext, T>,
136
+ Comparator,
137
+ ConditionOperand<TContext, T>,
138
+ ...Array<LogicalOperator | ConditionOperand<TContext, T> | Comparator>,
139
+ ]
140
+
141
+ // A nested composite condition combines conditions with logical operators
142
+ // The first element can be a SimpleCondition or FlatCompositeCondition
143
+ // followed by logical operators and more conditions
144
+ export type NestedCompositeCondition<
145
+ TContext extends Context = Context,
146
+ T extends any = any,
147
+ > = [
148
+ SimpleCondition<TContext, T> | FlatCompositeCondition<TContext, T>,
149
+ ...Array<
150
+ | LogicalOperator
151
+ | SimpleCondition<TContext, T>
152
+ | FlatCompositeCondition<TContext, T>
153
+ >,
154
+ ]
155
+
156
+ // A condition is either a simple condition or a composite condition (flat or nested).
157
+ export type Condition<
158
+ TContext extends Context = Context,
159
+ T extends any = any,
160
+ > =
161
+ | SimpleCondition<TContext, T>
162
+ | FlatCompositeCondition<TContext, T>
163
+ | NestedCompositeCondition<TContext, T>
164
+
165
+ // A join clause includes a join type, the table to join, an optional alias,
166
+ // an "on" condition, and an optional "where" clause specific to the join.
167
+ export interface JoinClause<TContext extends Context = Context> {
168
+ type: `inner` | `left` | `right` | `full` | `cross`
169
+ from: string
170
+ as?: string
171
+ on: Condition<TContext>
172
+ where?: Condition<TContext>
173
+ }
174
+
175
+ // The orderBy clause can be a string, an object mapping a column to "asc" or "desc",
176
+ // or an array of such items.
177
+ export type OrderBy<TContext extends Context = Context> =
178
+ | PropertyReferenceString<TContext>
179
+ | { [column in PropertyReferenceString<TContext>]?: `asc` | `desc` }
180
+ | Record<PropertyReferenceString<TContext>, `asc` | `desc`>
181
+ | Array<
182
+ | PropertyReferenceString<TContext>
183
+ | { [column in PropertyReferenceString<TContext>]?: `asc` | `desc` }
184
+ >
185
+
186
+ export type Select<TContext extends Context = Context> =
187
+ | PropertyReferenceString<TContext>
188
+ | {
189
+ [alias: string]:
190
+ | PropertyReference<TContext>
191
+ | FunctionCall<TContext>
192
+ | AggregateFunctionCall<TContext>
193
+ }
194
+ | WildcardReferenceString<TContext>
195
+
196
+ export type As<TContext extends Context = Context> = string
197
+
198
+ export type From<TContext extends Context = Context> = InputReference<{
199
+ baseSchema: TContext[`baseSchema`]
200
+ schema: TContext[`baseSchema`]
201
+ }>
202
+
203
+ export type Where<TContext extends Context = Context> = Condition<TContext>
204
+
205
+ export type GroupBy<TContext extends Context = Context> =
206
+ | PropertyReference<TContext>
207
+ | Array<PropertyReference<TContext>>
208
+
209
+ export type Having<TContext extends Context = Context> = Condition<TContext>
210
+
211
+ export type Limit<TContext extends Context = Context> = number
212
+
213
+ export type Offset<TContext extends Context = Context> = number
214
+
215
+ export interface BaseQuery<TContext extends Context = Context> {
216
+ // The select clause is an array of either plain strings or objects mapping alias names
217
+ // to expressions. Plain strings starting with "@" denote column references.
218
+ // Plain string "@*" denotes all columns from all tables.
219
+ // Plain string "@table.*" denotes all columns from a specific table.
220
+ select: Array<Select<TContext>>
221
+ as?: As<TContext>
222
+ from: From<TContext>
223
+ join?: Array<JoinClause<TContext>>
224
+ where?: Condition<TContext>
225
+ groupBy?: GroupBy<TContext>
226
+ having?: Condition<TContext>
227
+ orderBy?: OrderBy<TContext>
228
+ limit?: Limit<TContext>
229
+ offset?: Offset<TContext>
230
+ }
231
+
232
+ // The top-level query interface.
233
+ export interface Query<TContext extends Context = Context>
234
+ extends BaseQuery<TContext> {
235
+ keyBy?: PropertyReference<TContext> | Array<PropertyReference<TContext>>
236
+ with?: Array<WithQuery<TContext>>
237
+ collections?: {
238
+ [K: string]: Collection<any>
239
+ }
240
+ }
241
+
242
+ // A WithQuery is a query that is used as a Common Table Expression (CTE)
243
+ // It cannot be keyed and must have an alias (as)
244
+ // There is no support for recursive CTEs
245
+ export interface WithQuery<TContext extends Context = Context>
246
+ extends BaseQuery<TContext> {
247
+ as: string
248
+ }
249
+
250
+ // A keyed query is a query that has a keyBy clause, and so the result is always
251
+ // a keyed stream.
252
+ export interface KeyedQuery<TContext extends Context = Context>
253
+ extends Query<TContext> {
254
+ keyBy: PropertyReference<TContext> | Array<PropertyReference<TContext>>
255
+ }
@@ -0,0 +1,173 @@
1
+ import { map } from "@electric-sql/d2ts"
2
+ import {
3
+ evaluateOperandOnNestedRow,
4
+ extractValueFromNestedRow,
5
+ } from "./extractors"
6
+ import type { IStreamBuilder } from "@electric-sql/d2ts"
7
+ import type { ConditionOperand, Query } from "./schema"
8
+
9
+ export function processSelect(
10
+ pipeline: IStreamBuilder<Record<string, unknown>>,
11
+ query: Query,
12
+ mainTableAlias: string,
13
+ inputs: Record<string, IStreamBuilder<Record<string, unknown>>>
14
+ ) {
15
+ return pipeline.pipe(
16
+ map((nestedRow: Record<string, unknown>) => {
17
+ const result: Record<string, unknown> = {}
18
+
19
+ // Check if this is a grouped result (has no nested table structure)
20
+ // If it's a grouped result, we need to handle it differently
21
+ const isGroupedResult =
22
+ query.groupBy &&
23
+ Object.keys(nestedRow).some(
24
+ (key) =>
25
+ !Object.keys(inputs).includes(key) &&
26
+ typeof nestedRow[key] !== `object`
27
+ )
28
+
29
+ for (const item of query.select) {
30
+ if (typeof item === `string`) {
31
+ // Handle wildcard select - all columns from all tables
32
+ if ((item as string) === `@*`) {
33
+ // For grouped results, just return the row as is
34
+ if (isGroupedResult) {
35
+ Object.assign(result, nestedRow)
36
+ } else {
37
+ // Extract all columns from all tables
38
+ Object.assign(result, extractAllColumnsFromAllTables(nestedRow))
39
+ }
40
+ continue
41
+ }
42
+
43
+ // Handle @table.* syntax - all columns from a specific table
44
+ if (
45
+ (item as string).startsWith(`@`) &&
46
+ (item as string).endsWith(`.*`)
47
+ ) {
48
+ const tableAlias = (item as string).slice(1, -2) // Remove the '@' and '.*' parts
49
+
50
+ // For grouped results, check if we have columns from this table
51
+ if (isGroupedResult) {
52
+ // In grouped results, we don't have the nested structure anymore
53
+ // So we can't extract by table. Just continue to the next item.
54
+ continue
55
+ } else {
56
+ // Extract all columns from the specified table
57
+ Object.assign(
58
+ result,
59
+ extractAllColumnsFromTable(nestedRow, tableAlias)
60
+ )
61
+ }
62
+ continue
63
+ }
64
+
65
+ // Handle simple column references like "@table.column" or "@column"
66
+ if ((item as string).startsWith(`@`)) {
67
+ const columnRef = (item as string).substring(1)
68
+ const alias = columnRef
69
+
70
+ // For grouped results, check if the column is directly in the row first
71
+ if (isGroupedResult && columnRef in nestedRow) {
72
+ result[alias] = nestedRow[columnRef]
73
+ } else {
74
+ // Extract the value from the nested structure
75
+ result[alias] = extractValueFromNestedRow(
76
+ nestedRow,
77
+ columnRef,
78
+ mainTableAlias,
79
+ undefined
80
+ )
81
+ }
82
+
83
+ // If the alias contains a dot (table.column),
84
+ // use just the column part as the field name
85
+ if (alias.includes(`.`)) {
86
+ const columnName = alias.split(`.`)[1]
87
+ result[columnName!] = result[alias]
88
+ delete result[alias]
89
+ }
90
+ }
91
+ } else {
92
+ // Handle aliased columns like { alias: "@column_name" }
93
+ for (const [alias, expr] of Object.entries(item)) {
94
+ if (typeof expr === `string` && (expr as string).startsWith(`@`)) {
95
+ const columnRef = (expr as string).substring(1)
96
+
97
+ // For grouped results, check if the column is directly in the row first
98
+ if (isGroupedResult && columnRef in nestedRow) {
99
+ result[alias] = nestedRow[columnRef]
100
+ } else {
101
+ // Extract the value from the nested structure
102
+ result[alias] = extractValueFromNestedRow(
103
+ nestedRow,
104
+ columnRef,
105
+ mainTableAlias,
106
+ undefined
107
+ )
108
+ }
109
+ } else if (typeof expr === `object`) {
110
+ // For grouped results, the aggregate results are already in the row
111
+ if (isGroupedResult && alias in nestedRow) {
112
+ result[alias] = nestedRow[alias]
113
+ } else {
114
+ // This might be a function call
115
+ result[alias] = evaluateOperandOnNestedRow(
116
+ nestedRow,
117
+ expr as ConditionOperand,
118
+ mainTableAlias,
119
+ undefined
120
+ )
121
+ }
122
+ }
123
+ }
124
+ }
125
+ }
126
+
127
+ return result
128
+ })
129
+ )
130
+ }
131
+
132
+ // Helper function to extract all columns from all tables in a nested row
133
+ function extractAllColumnsFromAllTables(
134
+ nestedRow: Record<string, unknown>
135
+ ): Record<string, unknown> {
136
+ const result: Record<string, unknown> = {}
137
+
138
+ // Process each table in the nested row
139
+ for (const [tableAlias, tableData] of Object.entries(nestedRow)) {
140
+ if (tableData && typeof tableData === `object`) {
141
+ // Add all columns from this table to the result
142
+ // If there are column name conflicts, the last table's columns will overwrite previous ones
143
+ Object.assign(result, extractAllColumnsFromTable(nestedRow, tableAlias))
144
+ }
145
+ }
146
+
147
+ return result
148
+ }
149
+
150
+ // Helper function to extract all columns from a table in a nested row
151
+ function extractAllColumnsFromTable(
152
+ nestedRow: Record<string, unknown>,
153
+ tableAlias: string
154
+ ): Record<string, unknown> {
155
+ const result: Record<string, unknown> = {}
156
+
157
+ // Get the table data
158
+ const tableData = nestedRow[tableAlias] as
159
+ | Record<string, unknown>
160
+ | null
161
+ | undefined
162
+
163
+ if (!tableData || typeof tableData !== `object`) {
164
+ return result
165
+ }
166
+
167
+ // Add all columns from the table to the result
168
+ for (const [columnName, value] of Object.entries(tableData)) {
169
+ result[columnName] = value
170
+ }
171
+
172
+ return result
173
+ }