@sixb/pg 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7548 -6387
- package/dist/index.js.map +16 -10
- package/dist/migrations.d.ts.map +1 -1
- package/dist/objects/index.d.ts +2 -0
- package/dist/objects/index.d.ts.map +1 -0
- package/dist/{pg-object-query-compiler.d.ts → objects/query-compiler.d.ts} +25 -4
- package/dist/objects/query-compiler.d.ts.map +1 -0
- package/dist/objects/read-scope.d.ts +17 -0
- package/dist/objects/read-scope.d.ts.map +1 -0
- package/dist/objects/reader.d.ts +50 -0
- package/dist/objects/reader.d.ts.map +1 -0
- package/dist/objects/rows.d.ts +47 -0
- package/dist/objects/rows.d.ts.map +1 -0
- package/dist/objects/selected-reader.d.ts +8 -0
- package/dist/objects/selected-reader.d.ts.map +1 -0
- package/dist/{pg-object-storage.d.ts → objects/storage.d.ts} +12 -20
- package/dist/objects/storage.d.ts.map +1 -0
- package/dist/pg-execution-storage.d.ts +3 -2
- package/dist/pg-execution-storage.d.ts.map +1 -1
- package/dist/share-grant-storage.d.ts +11 -0
- package/dist/share-grant-storage.d.ts.map +1 -0
- package/dist/share-session-storage.d.ts +11 -0
- package/dist/share-session-storage.d.ts.map +1 -0
- package/dist/storage-errors.d.ts +2 -0
- package/dist/storage-errors.d.ts.map +1 -1
- package/dist/transactions.d.ts +9 -2
- package/dist/transactions.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +16 -3
- package/src/migrations/035-share-grants.sql +57 -0
- package/src/migrations/036-share-sessions.sql +173 -0
- package/src/migrations.ts +4 -0
- package/src/objects/index.ts +1 -0
- package/src/{pg-object-query-compiler.ts → objects/query-compiler.ts} +185 -100
- package/src/objects/read-scope.ts +324 -0
- package/src/objects/reader.ts +604 -0
- package/src/objects/rows.ts +146 -0
- package/src/objects/selected-reader.ts +118 -0
- package/src/objects/storage.ts +305 -0
- package/src/pg-execution-storage.ts +21 -2
- package/src/share-grant-storage.ts +236 -0
- package/src/share-session-storage.ts +127 -0
- package/src/storage-errors.ts +6 -0
- package/src/transactions.ts +46 -5
- package/dist/pg-object-query-compiler.d.ts.map +0 -1
- package/dist/pg-object-storage.d.ts.map +0 -1
- package/src/pg-object-storage.ts +0 -734
|
@@ -45,6 +45,7 @@ interface CompiledHasMoreProbe {
|
|
|
45
45
|
|
|
46
46
|
interface CompileContext {
|
|
47
47
|
probeLimit: boolean
|
|
48
|
+
source: PgObjectQuerySource
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
interface CompiledPredicate {
|
|
@@ -89,7 +90,6 @@ interface EncodedCursorValue {
|
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
const PAGE_TOKEN_PREFIX = "keyset:"
|
|
92
|
-
const exactContext: CompileContext = { probeLimit: false }
|
|
93
93
|
// Per-parent fanout the core executor bakes into every pushed-down expansion;
|
|
94
94
|
// this default only guards a malformed (un-baked) IR and mirrors the core cap.
|
|
95
95
|
const DEFAULT_EXPANSION_FANOUT = 1_000
|
|
@@ -97,11 +97,15 @@ const DEFAULT_EXPANSION_FANOUT = 1_000
|
|
|
97
97
|
export function compilePgObjectQuery(
|
|
98
98
|
projectId: string,
|
|
99
99
|
query: ObjectQuery,
|
|
100
|
-
options: { includeTotal?: boolean } = {}
|
|
100
|
+
options: { includeTotal?: boolean; source?: PgObjectQuerySource } = {}
|
|
101
101
|
): CompiledPgObjectQuery {
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
const source = options.source ?? DEFAULT_OBJECT_QUERY_SOURCE
|
|
103
|
+
const compiled = source.wrapQuery(
|
|
104
|
+
compileObjectQueryInternal(projectId, query, {
|
|
105
|
+
probeLimit: options.includeTotal === false,
|
|
106
|
+
source,
|
|
107
|
+
})
|
|
108
|
+
)
|
|
105
109
|
return {
|
|
106
110
|
...compiled,
|
|
107
111
|
sql: numberPlaceholders(compiled.sql),
|
|
@@ -115,44 +119,90 @@ export function compilePgObjectQuery(
|
|
|
115
119
|
}
|
|
116
120
|
}
|
|
117
121
|
|
|
122
|
+
/** Physical relations used by the PostgreSQL object-query compiler. */
|
|
123
|
+
export interface PgObjectQuerySource {
|
|
124
|
+
readonly objectsTable: string
|
|
125
|
+
readonly linksTable: string
|
|
126
|
+
/** Wrap a terminal SELECT without its own WITH clause; the selected source owns the only WITH. */
|
|
127
|
+
wrapStatement(
|
|
128
|
+
sql: string,
|
|
129
|
+
args?: readonly unknown[]
|
|
130
|
+
): {
|
|
131
|
+
readonly sql: string
|
|
132
|
+
readonly args: unknown[]
|
|
133
|
+
}
|
|
134
|
+
wrapQuery(query: CompiledPgObjectQuery): CompiledPgObjectQuery
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Prefix an optional query source, then assign PostgreSQL positional placeholders. */
|
|
138
|
+
export function compilePgObjectStatement(
|
|
139
|
+
sql: string,
|
|
140
|
+
args: readonly unknown[] = [],
|
|
141
|
+
source?: PgObjectQuerySource
|
|
142
|
+
): CompiledPgScalarQuery {
|
|
143
|
+
return numberCompiledQuery((source ?? DEFAULT_OBJECT_QUERY_SOURCE).wrapStatement(sql, args))
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export const DEFAULT_OBJECT_QUERY_SOURCE: PgObjectQuerySource = {
|
|
147
|
+
objectsTable: "objects",
|
|
148
|
+
linksTable: "links",
|
|
149
|
+
wrapStatement: (sql, args = []) => ({ sql, args: [...args] }),
|
|
150
|
+
wrapQuery: (query) => query,
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function exactContext(ctx: CompileContext): CompileContext {
|
|
154
|
+
return ctx.probeLimit ? { ...ctx, probeLimit: false } : ctx
|
|
155
|
+
}
|
|
156
|
+
|
|
118
157
|
export function compilePgObjectCountQuery(
|
|
119
158
|
projectId: string,
|
|
120
|
-
query: ObjectQuery
|
|
159
|
+
query: ObjectQuery,
|
|
160
|
+
options: { source?: PgObjectQuerySource } = {}
|
|
121
161
|
): CompiledPgScalarQuery {
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
162
|
+
const querySource = options.source ?? DEFAULT_OBJECT_QUERY_SOURCE
|
|
163
|
+
const source = compileAggregateSource(projectId, query, querySource)
|
|
164
|
+
return numberCompiledQuery(
|
|
165
|
+
querySource.wrapStatement(
|
|
166
|
+
`
|
|
125
167
|
SELECT COUNT(*)::bigint AS count
|
|
126
168
|
FROM (${source.sql}) AS input
|
|
127
169
|
`,
|
|
128
|
-
|
|
129
|
-
|
|
170
|
+
source.args
|
|
171
|
+
)
|
|
172
|
+
)
|
|
130
173
|
}
|
|
131
174
|
|
|
132
175
|
export function compilePgObjectExistsQuery(
|
|
133
176
|
projectId: string,
|
|
134
|
-
query: ObjectQuery
|
|
177
|
+
query: ObjectQuery,
|
|
178
|
+
options: { source?: PgObjectQuerySource } = {}
|
|
135
179
|
): CompiledPgScalarQuery {
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
180
|
+
const querySource = options.source ?? DEFAULT_OBJECT_QUERY_SOURCE
|
|
181
|
+
const source = compileAggregateSource(projectId, query, querySource)
|
|
182
|
+
return numberCompiledQuery(
|
|
183
|
+
querySource.wrapStatement(
|
|
184
|
+
`
|
|
139
185
|
SELECT 1
|
|
140
186
|
FROM (${source.sql}) AS input
|
|
141
187
|
LIMIT 1
|
|
142
188
|
`,
|
|
143
|
-
|
|
144
|
-
|
|
189
|
+
source.args
|
|
190
|
+
)
|
|
191
|
+
)
|
|
145
192
|
}
|
|
146
193
|
|
|
147
194
|
export function compilePgObjectFacetQuery(
|
|
148
195
|
projectId: string,
|
|
149
196
|
query: ObjectQuery,
|
|
150
197
|
propertyId: string,
|
|
151
|
-
limit: number
|
|
198
|
+
limit: number,
|
|
199
|
+
options: { source?: PgObjectQuerySource } = {}
|
|
152
200
|
): CompiledPgFacetQuery {
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
201
|
+
const querySource = options.source ?? DEFAULT_OBJECT_QUERY_SOURCE
|
|
202
|
+
const source = compileAggregateSource(projectId, query, querySource)
|
|
203
|
+
return numberCompiledQuery(
|
|
204
|
+
querySource.wrapStatement(
|
|
205
|
+
`
|
|
156
206
|
SELECT facet.value_type, facet.value_text, COUNT(*)::bigint AS count
|
|
157
207
|
FROM (
|
|
158
208
|
SELECT
|
|
@@ -165,8 +215,9 @@ export function compilePgObjectFacetQuery(
|
|
|
165
215
|
ORDER BY count DESC, facet.value_text ASC
|
|
166
216
|
LIMIT ?
|
|
167
217
|
`,
|
|
168
|
-
|
|
169
|
-
|
|
218
|
+
[propertyId, propertyId, ...source.args, propertyId, limit]
|
|
219
|
+
)
|
|
220
|
+
)
|
|
170
221
|
}
|
|
171
222
|
|
|
172
223
|
function compileObjectQueryInternal(
|
|
@@ -176,27 +227,28 @@ function compileObjectQueryInternal(
|
|
|
176
227
|
): CompiledPgObjectQuery {
|
|
177
228
|
switch (query.kind) {
|
|
178
229
|
case "start":
|
|
179
|
-
return compileStart(projectId, query)
|
|
230
|
+
return compileStart(projectId, query, ctx)
|
|
180
231
|
case "refs":
|
|
181
|
-
return compileRefs(projectId, query)
|
|
232
|
+
return compileRefs(projectId, query, ctx)
|
|
182
233
|
case "filter":
|
|
183
|
-
return compileFilter(projectId, query.input, query.predicate)
|
|
234
|
+
return compileFilter(projectId, query.input, query.predicate, ctx)
|
|
184
235
|
case "sort":
|
|
185
236
|
return compileSort(projectId, query.input, query.fields, ctx)
|
|
186
237
|
case "limit":
|
|
187
238
|
return compileLimit(projectId, query.input, query.limit, ctx)
|
|
188
239
|
case "page":
|
|
189
|
-
return compilePage(projectId, query.input, query.pageSize, query.pageToken)
|
|
240
|
+
return compilePage(projectId, query.input, query.pageSize, query.pageToken, ctx)
|
|
190
241
|
case "traverse":
|
|
191
242
|
return compileTraversal(
|
|
192
243
|
projectId,
|
|
193
244
|
query.input,
|
|
194
245
|
query.linkId,
|
|
195
246
|
query.direction,
|
|
196
|
-
query.sourceObjectTypeId
|
|
247
|
+
query.sourceObjectTypeId,
|
|
248
|
+
ctx
|
|
197
249
|
)
|
|
198
250
|
case "set":
|
|
199
|
-
return compileSet(projectId, query.op, query.inputs)
|
|
251
|
+
return compileSet(projectId, query.op, query.inputs, ctx)
|
|
200
252
|
case "project":
|
|
201
253
|
return compileProject(projectId, query.input, query.properties, ctx)
|
|
202
254
|
case "text":
|
|
@@ -205,10 +257,11 @@ function compileObjectQueryInternal(
|
|
|
205
257
|
query.input,
|
|
206
258
|
query.query,
|
|
207
259
|
query.fields,
|
|
208
|
-
query.fieldsByObjectType
|
|
260
|
+
query.fieldsByObjectType,
|
|
261
|
+
ctx
|
|
209
262
|
)
|
|
210
263
|
case "expand":
|
|
211
|
-
return compileExpand(projectId, query.input, query.expansions)
|
|
264
|
+
return compileExpand(projectId, query.input, query.expansions, ctx)
|
|
212
265
|
case "vector":
|
|
213
266
|
throw new Error(
|
|
214
267
|
`[SixbPg] PostgreSQL object storage does not support query node '${query.kind}'`
|
|
@@ -218,7 +271,8 @@ function compileObjectQueryInternal(
|
|
|
218
271
|
|
|
219
272
|
function compileStart(
|
|
220
273
|
projectId: string,
|
|
221
|
-
query: Extract<ObjectQuery, { kind: "start" }
|
|
274
|
+
query: Extract<ObjectQuery, { kind: "start" }>,
|
|
275
|
+
ctx: CompileContext
|
|
222
276
|
): CompiledPgObjectQuery {
|
|
223
277
|
if (query.includeSubtypes === true) {
|
|
224
278
|
throw new Error("[SixbPg] PostgreSQL object storage does not support start.includeSubtypes")
|
|
@@ -227,7 +281,7 @@ function compileStart(
|
|
|
227
281
|
const order = compileOrder(identityOrderFields())
|
|
228
282
|
const sql = `
|
|
229
283
|
SELECT *, properties AS _cursor_properties
|
|
230
|
-
FROM
|
|
284
|
+
FROM ${ctx.source.objectsTable}
|
|
231
285
|
WHERE project_id = ? AND object_type_id = ?
|
|
232
286
|
ORDER BY ${order.sql}
|
|
233
287
|
`
|
|
@@ -235,8 +289,7 @@ function compileStart(
|
|
|
235
289
|
return {
|
|
236
290
|
sql,
|
|
237
291
|
args: [projectId, query.objectTypeId, ...order.args],
|
|
238
|
-
totalSql:
|
|
239
|
-
"SELECT COUNT(*)::bigint AS total FROM objects WHERE project_id = ? AND object_type_id = ?",
|
|
292
|
+
totalSql: `SELECT COUNT(*)::bigint AS total FROM ${ctx.source.objectsTable} WHERE project_id = ? AND object_type_id = ?`,
|
|
240
293
|
totalArgs: [projectId, query.objectTypeId],
|
|
241
294
|
order,
|
|
242
295
|
hasMore: () => false,
|
|
@@ -247,7 +300,8 @@ function compileStart(
|
|
|
247
300
|
|
|
248
301
|
function compileRefs(
|
|
249
302
|
projectId: string,
|
|
250
|
-
query: Extract<ObjectQuery, { kind: "refs" }
|
|
303
|
+
query: Extract<ObjectQuery, { kind: "refs" }>,
|
|
304
|
+
ctx: CompileContext
|
|
251
305
|
): CompiledPgObjectQuery {
|
|
252
306
|
if (query.refs.length === 0) {
|
|
253
307
|
throw new Error("[SixbPg] PostgreSQL object storage requires at least one ref")
|
|
@@ -263,10 +317,9 @@ function compileRefs(
|
|
|
263
317
|
FROM jsonb_array_elements(?::text::jsonb) AS ref(value)
|
|
264
318
|
`
|
|
265
319
|
const sql = `
|
|
266
|
-
WITH requested AS (${requested})
|
|
267
320
|
SELECT selected.*, selected.properties AS _cursor_properties
|
|
268
|
-
FROM requested
|
|
269
|
-
JOIN
|
|
321
|
+
FROM (${requested}) AS requested
|
|
322
|
+
JOIN ${ctx.source.objectsTable} AS selected
|
|
270
323
|
ON selected.project_id = ?
|
|
271
324
|
AND selected.object_type_id = requested.object_type_id
|
|
272
325
|
AND selected.primary_id = requested.primary_id
|
|
@@ -277,10 +330,9 @@ function compileRefs(
|
|
|
277
330
|
sql,
|
|
278
331
|
args: [refsJson, projectId, ...selectedOrder.args],
|
|
279
332
|
totalSql: `
|
|
280
|
-
WITH requested AS (${requested})
|
|
281
333
|
SELECT COUNT(*)::bigint AS total
|
|
282
|
-
FROM requested
|
|
283
|
-
JOIN
|
|
334
|
+
FROM (${requested}) AS requested
|
|
335
|
+
JOIN ${ctx.source.objectsTable} AS selected
|
|
284
336
|
ON selected.project_id = ?
|
|
285
337
|
AND selected.object_type_id = requested.object_type_id
|
|
286
338
|
AND selected.primary_id = requested.primary_id
|
|
@@ -296,17 +348,19 @@ function compileRefs(
|
|
|
296
348
|
function compileFilter(
|
|
297
349
|
projectId: string,
|
|
298
350
|
inputQuery: ObjectQuery,
|
|
299
|
-
predicateNode: ObjectQueryPredicate
|
|
351
|
+
predicateNode: ObjectQueryPredicate,
|
|
352
|
+
ctx: CompileContext
|
|
300
353
|
): CompiledPgObjectQuery {
|
|
301
|
-
return compileWhere(projectId, inputQuery, compilePredicate(predicateNode))
|
|
354
|
+
return compileWhere(projectId, inputQuery, compilePredicate(predicateNode), ctx)
|
|
302
355
|
}
|
|
303
356
|
|
|
304
357
|
function compileWhere(
|
|
305
358
|
projectId: string,
|
|
306
359
|
inputQuery: ObjectQuery,
|
|
307
|
-
predicate: CompiledPredicate
|
|
360
|
+
predicate: CompiledPredicate,
|
|
361
|
+
ctx: CompileContext
|
|
308
362
|
): CompiledPgObjectQuery {
|
|
309
|
-
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext)
|
|
363
|
+
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext(ctx))
|
|
310
364
|
const sql = `
|
|
311
365
|
SELECT *
|
|
312
366
|
FROM (${input.sql}) AS input
|
|
@@ -335,12 +389,14 @@ function compileText(
|
|
|
335
389
|
inputQuery: ObjectQuery,
|
|
336
390
|
query: string,
|
|
337
391
|
fields: readonly string[] | undefined,
|
|
338
|
-
fieldsByObjectType: Readonly<Record<string, readonly string[]>> | undefined
|
|
392
|
+
fieldsByObjectType: Readonly<Record<string, readonly string[]>> | undefined,
|
|
393
|
+
ctx: CompileContext
|
|
339
394
|
): CompiledPgObjectQuery {
|
|
340
395
|
return compileWhere(
|
|
341
396
|
projectId,
|
|
342
397
|
inputQuery,
|
|
343
|
-
compileTextSearchPredicate(query, fields, fieldsByObjectType)
|
|
398
|
+
compileTextSearchPredicate(query, fields, fieldsByObjectType),
|
|
399
|
+
ctx
|
|
344
400
|
)
|
|
345
401
|
}
|
|
346
402
|
|
|
@@ -350,7 +406,7 @@ function compileSort(
|
|
|
350
406
|
fields: readonly ObjectQuerySortField[],
|
|
351
407
|
ctx: CompileContext
|
|
352
408
|
): CompiledPgObjectQuery {
|
|
353
|
-
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext)
|
|
409
|
+
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext(ctx))
|
|
354
410
|
const probeInput =
|
|
355
411
|
ctx.probeLimit && needsLimitProbe(inputQuery)
|
|
356
412
|
? compileObjectQueryInternal(projectId, inputQuery, ctx)
|
|
@@ -389,7 +445,7 @@ function compileLimit(
|
|
|
389
445
|
rawLimit: number,
|
|
390
446
|
ctx: CompileContext
|
|
391
447
|
): CompiledPgObjectQuery {
|
|
392
|
-
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext)
|
|
448
|
+
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext(ctx))
|
|
393
449
|
const limit = Math.max(0, rawLimit)
|
|
394
450
|
const rowLimit = ctx.probeLimit ? limit + 1 : limit
|
|
395
451
|
|
|
@@ -418,9 +474,10 @@ function compilePage(
|
|
|
418
474
|
projectId: string,
|
|
419
475
|
inputQuery: ObjectQuery,
|
|
420
476
|
rawPageSize: number,
|
|
421
|
-
pageToken: string | undefined
|
|
477
|
+
pageToken: string | undefined,
|
|
478
|
+
ctx: CompileContext
|
|
422
479
|
): CompiledPgObjectQuery {
|
|
423
|
-
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext)
|
|
480
|
+
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext(ctx))
|
|
424
481
|
const pageSize = Math.max(0, rawPageSize)
|
|
425
482
|
const cursor = pageToken ? decodePageToken(pageToken, input.order.fields) : undefined
|
|
426
483
|
const cursorPredicate = cursor
|
|
@@ -457,30 +514,31 @@ function compileTraversal(
|
|
|
457
514
|
inputQuery: ObjectQuery,
|
|
458
515
|
linkId: string,
|
|
459
516
|
direction: "outgoing" | "incoming",
|
|
460
|
-
sourceObjectTypeId
|
|
517
|
+
sourceObjectTypeId: string | undefined,
|
|
518
|
+
ctx: CompileContext
|
|
461
519
|
): CompiledPgObjectQuery {
|
|
462
|
-
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext)
|
|
520
|
+
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext(ctx))
|
|
463
521
|
const outputAlias = direction === "outgoing" ? "target_object" : "source_object"
|
|
464
522
|
const joinSql =
|
|
465
523
|
direction === "outgoing"
|
|
466
524
|
? `
|
|
467
|
-
JOIN
|
|
525
|
+
JOIN ${ctx.source.linksTable} AS edge
|
|
468
526
|
ON edge.project_id = input.project_id
|
|
469
527
|
AND edge.source_type_id = input.object_type_id
|
|
470
528
|
AND edge.source_id = input.primary_id
|
|
471
529
|
AND edge.link_id = ?
|
|
472
|
-
JOIN
|
|
530
|
+
JOIN ${ctx.source.objectsTable} AS target_object
|
|
473
531
|
ON target_object.project_id = edge.project_id
|
|
474
532
|
AND target_object.object_type_id = edge.target_type_id
|
|
475
533
|
AND target_object.primary_id = edge.target_id
|
|
476
534
|
`
|
|
477
535
|
: `
|
|
478
|
-
JOIN
|
|
536
|
+
JOIN ${ctx.source.linksTable} AS edge
|
|
479
537
|
ON edge.project_id = input.project_id
|
|
480
538
|
AND edge.target_type_id = input.object_type_id
|
|
481
539
|
AND edge.target_id = input.primary_id
|
|
482
540
|
AND edge.link_id = ?${sourceObjectTypeId === undefined ? "" : "\n AND edge.source_type_id = ?"}
|
|
483
|
-
JOIN
|
|
541
|
+
JOIN ${ctx.source.objectsTable} AS source_object
|
|
484
542
|
ON source_object.project_id = edge.project_id
|
|
485
543
|
AND source_object.object_type_id = edge.source_type_id
|
|
486
544
|
AND source_object.primary_id = edge.source_id
|
|
@@ -527,13 +585,15 @@ interface ExpansionParent {
|
|
|
527
585
|
function compileExpand(
|
|
528
586
|
projectId: string,
|
|
529
587
|
inputQuery: ObjectQuery,
|
|
530
|
-
expansions: readonly ObjectExpansion[]
|
|
588
|
+
expansions: readonly ObjectExpansion[],
|
|
589
|
+
ctx: CompileContext
|
|
531
590
|
): CompiledPgObjectQuery {
|
|
532
|
-
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext)
|
|
591
|
+
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext(ctx))
|
|
533
592
|
const expand = compileExpansionsObject(
|
|
534
593
|
expansions,
|
|
535
594
|
{ project: "input.project_id", type: "input.object_type_id", id: "input.primary_id" },
|
|
536
|
-
""
|
|
595
|
+
"",
|
|
596
|
+
ctx
|
|
537
597
|
)
|
|
538
598
|
const inputOrder = compileOrder(input.order.fields, "input", "input._cursor_properties")
|
|
539
599
|
const sql = `
|
|
@@ -561,13 +621,14 @@ function compileExpand(
|
|
|
561
621
|
function compileExpansionsObject(
|
|
562
622
|
expansions: readonly ObjectExpansion[],
|
|
563
623
|
parent: ExpansionParent,
|
|
564
|
-
pathPrefix: string
|
|
624
|
+
pathPrefix: string,
|
|
625
|
+
ctx: CompileContext
|
|
565
626
|
): CompiledPredicate {
|
|
566
627
|
const parts: string[] = []
|
|
567
628
|
const args: unknown[] = []
|
|
568
629
|
expansions.forEach((expansion, index) => {
|
|
569
630
|
const path = pathPrefix === "" ? `${index}` : `${pathPrefix}_${index}`
|
|
570
|
-
const value = compileExpansionValue(expansion, parent, path)
|
|
631
|
+
const value = compileExpansionValue(expansion, parent, path, ctx)
|
|
571
632
|
parts.push("?::text", value.sql)
|
|
572
633
|
args.push(expansion.linkId, ...value.args)
|
|
573
634
|
})
|
|
@@ -583,7 +644,8 @@ function compileExpansionsObject(
|
|
|
583
644
|
function compileExpansionValue(
|
|
584
645
|
expansion: ObjectExpansion,
|
|
585
646
|
parent: ExpansionParent,
|
|
586
|
-
path: string
|
|
647
|
+
path: string,
|
|
648
|
+
ctx: CompileContext
|
|
587
649
|
): CompiledPredicate {
|
|
588
650
|
const edge = `edge_${path}`
|
|
589
651
|
const target = `tgt_${path}`
|
|
@@ -596,7 +658,7 @@ function compileExpansionValue(
|
|
|
596
658
|
const parentType = incoming ? `${edge}.target_type_id` : `${edge}.source_type_id`
|
|
597
659
|
const parentId = incoming ? `${edge}.target_id` : `${edge}.source_id`
|
|
598
660
|
|
|
599
|
-
const child = compileExpansionChildJson(expansion, edge, target, path)
|
|
661
|
+
const child = compileExpansionChildJson(expansion, edge, target, path, ctx)
|
|
600
662
|
const order = compileExpansionOrder(expansion, target, neighborType, neighborId)
|
|
601
663
|
|
|
602
664
|
const whereParts = [
|
|
@@ -613,8 +675,8 @@ function compileExpansionValue(
|
|
|
613
675
|
|
|
614
676
|
const inner = `
|
|
615
677
|
SELECT ${child.sql} AS elem, row_number() OVER (ORDER BY ${order.sql}) AS _ord
|
|
616
|
-
FROM
|
|
617
|
-
JOIN
|
|
678
|
+
FROM ${ctx.source.linksTable} AS ${edge}
|
|
679
|
+
JOIN ${ctx.source.objectsTable} AS ${target}
|
|
618
680
|
ON ${target}.project_id = ${edge}.project_id
|
|
619
681
|
AND ${target}.object_type_id = ${neighborType}
|
|
620
682
|
AND ${target}.primary_id = ${neighborId}
|
|
@@ -644,7 +706,8 @@ function compileExpansionChildJson(
|
|
|
644
706
|
expansion: ObjectExpansion,
|
|
645
707
|
edge: string,
|
|
646
708
|
target: string,
|
|
647
|
-
path: string
|
|
709
|
+
path: string,
|
|
710
|
+
ctx: CompileContext
|
|
648
711
|
): CompiledPredicate {
|
|
649
712
|
const fields = [
|
|
650
713
|
`'projectId', ${target}.project_id`,
|
|
@@ -667,7 +730,8 @@ function compileExpansionChildJson(
|
|
|
667
730
|
type: `${target}.object_type_id`,
|
|
668
731
|
id: `${target}.primary_id`,
|
|
669
732
|
},
|
|
670
|
-
path
|
|
733
|
+
path,
|
|
734
|
+
ctx
|
|
671
735
|
)
|
|
672
736
|
fields.push(`'links', ${nested.sql}`)
|
|
673
737
|
args.push(...nested.args)
|
|
@@ -711,14 +775,15 @@ function compileExpansionOrder(
|
|
|
711
775
|
function compileSet(
|
|
712
776
|
projectId: string,
|
|
713
777
|
op: ObjectQuerySetOperation,
|
|
714
|
-
inputs: readonly ObjectQuery[]
|
|
778
|
+
inputs: readonly ObjectQuery[],
|
|
779
|
+
ctx: CompileContext
|
|
715
780
|
): CompiledPgObjectQuery {
|
|
716
781
|
if (inputs.length === 0) {
|
|
717
782
|
const order = compileOrder(identityOrderFields())
|
|
718
783
|
return {
|
|
719
784
|
sql: `
|
|
720
785
|
SELECT *, properties AS _cursor_properties
|
|
721
|
-
FROM
|
|
786
|
+
FROM ${ctx.source.objectsTable}
|
|
722
787
|
WHERE 1 = 0
|
|
723
788
|
ORDER BY ${order.sql}
|
|
724
789
|
`,
|
|
@@ -733,7 +798,7 @@ function compileSet(
|
|
|
733
798
|
}
|
|
734
799
|
|
|
735
800
|
const compiledInputs = inputs.map((input) =>
|
|
736
|
-
compileObjectQueryInternal(projectId, input, exactContext)
|
|
801
|
+
compileObjectQueryInternal(projectId, input, exactContext(ctx))
|
|
737
802
|
)
|
|
738
803
|
const identities = compileSetIdentities(op, compiledInputs)
|
|
739
804
|
const order = compileOrder(identityOrderFields())
|
|
@@ -741,7 +806,7 @@ function compileSet(
|
|
|
741
806
|
const sql = `
|
|
742
807
|
SELECT selected.*, selected.properties AS _cursor_properties
|
|
743
808
|
FROM (${identities.sql}) AS ids
|
|
744
|
-
JOIN
|
|
809
|
+
JOIN ${ctx.source.objectsTable} AS selected
|
|
745
810
|
ON selected.project_id = ?
|
|
746
811
|
AND selected.object_type_id = ids.object_type_id
|
|
747
812
|
AND selected.primary_id = ids.primary_id
|
|
@@ -799,19 +864,29 @@ function compileProject(
|
|
|
799
864
|
}
|
|
800
865
|
}
|
|
801
866
|
|
|
802
|
-
function compileAggregateSource(
|
|
867
|
+
function compileAggregateSource(
|
|
868
|
+
projectId: string,
|
|
869
|
+
query: ObjectQuery,
|
|
870
|
+
source: PgObjectQuerySource
|
|
871
|
+
): CompiledAggregateSource {
|
|
803
872
|
switch (query.kind) {
|
|
804
873
|
case "start":
|
|
805
|
-
return compileAggregateStart(projectId, query)
|
|
874
|
+
return compileAggregateStart(projectId, query, source)
|
|
806
875
|
case "refs":
|
|
807
|
-
return compileAggregateRefs(projectId, query)
|
|
876
|
+
return compileAggregateRefs(projectId, query, source)
|
|
808
877
|
case "filter":
|
|
809
|
-
return compileAggregateWhere(
|
|
878
|
+
return compileAggregateWhere(
|
|
879
|
+
projectId,
|
|
880
|
+
query.input,
|
|
881
|
+
compilePredicate(query.predicate),
|
|
882
|
+
source
|
|
883
|
+
)
|
|
810
884
|
case "text": {
|
|
811
885
|
return compileAggregateWhere(
|
|
812
886
|
projectId,
|
|
813
887
|
query.input,
|
|
814
|
-
compileTextSearchPredicate(query.query, query.fields, query.fieldsByObjectType)
|
|
888
|
+
compileTextSearchPredicate(query.query, query.fields, query.fieldsByObjectType),
|
|
889
|
+
source
|
|
815
890
|
)
|
|
816
891
|
}
|
|
817
892
|
case "traverse":
|
|
@@ -820,18 +895,19 @@ function compileAggregateSource(projectId: string, query: ObjectQuery): Compiled
|
|
|
820
895
|
query.input,
|
|
821
896
|
query.linkId,
|
|
822
897
|
query.direction,
|
|
823
|
-
query.sourceObjectTypeId
|
|
898
|
+
query.sourceObjectTypeId,
|
|
899
|
+
source
|
|
824
900
|
)
|
|
825
901
|
case "set":
|
|
826
|
-
return compileAggregateSet(projectId, query.op, query.inputs)
|
|
902
|
+
return compileAggregateSet(projectId, query.op, query.inputs, source)
|
|
827
903
|
case "sort":
|
|
828
904
|
case "project":
|
|
829
905
|
// `expand` is output-shaping, like sort/project: aggregates ignore it.
|
|
830
906
|
case "expand":
|
|
831
|
-
return compileAggregateSource(projectId, query.input)
|
|
907
|
+
return compileAggregateSource(projectId, query.input, source)
|
|
832
908
|
case "limit":
|
|
833
909
|
case "page":
|
|
834
|
-
return compileRowQueryAggregateSource(projectId, query)
|
|
910
|
+
return compileRowQueryAggregateSource(projectId, query, source)
|
|
835
911
|
case "vector":
|
|
836
912
|
throw new Error(
|
|
837
913
|
`[SixbPg] PostgreSQL object storage does not support query node '${query.kind}'`
|
|
@@ -841,7 +917,8 @@ function compileAggregateSource(projectId: string, query: ObjectQuery): Compiled
|
|
|
841
917
|
|
|
842
918
|
function compileAggregateStart(
|
|
843
919
|
projectId: string,
|
|
844
|
-
query: Extract<ObjectQuery, { kind: "start" }
|
|
920
|
+
query: Extract<ObjectQuery, { kind: "start" }>,
|
|
921
|
+
source: PgObjectQuerySource
|
|
845
922
|
): CompiledAggregateSource {
|
|
846
923
|
if (query.includeSubtypes === true) {
|
|
847
924
|
throw new Error("[SixbPg] PostgreSQL object storage does not support start.includeSubtypes")
|
|
@@ -850,7 +927,7 @@ function compileAggregateStart(
|
|
|
850
927
|
return {
|
|
851
928
|
sql: `
|
|
852
929
|
SELECT project_id, object_type_id, primary_id, properties
|
|
853
|
-
FROM
|
|
930
|
+
FROM ${source.objectsTable}
|
|
854
931
|
WHERE project_id = ? AND object_type_id = ?
|
|
855
932
|
`,
|
|
856
933
|
args: [projectId, query.objectTypeId],
|
|
@@ -859,7 +936,8 @@ function compileAggregateStart(
|
|
|
859
936
|
|
|
860
937
|
function compileAggregateRefs(
|
|
861
938
|
projectId: string,
|
|
862
|
-
query: Extract<ObjectQuery, { kind: "refs" }
|
|
939
|
+
query: Extract<ObjectQuery, { kind: "refs" }>,
|
|
940
|
+
source: PgObjectQuerySource
|
|
863
941
|
): CompiledAggregateSource {
|
|
864
942
|
if (query.refs.length === 0) {
|
|
865
943
|
throw new Error("[SixbPg] PostgreSQL object storage requires at least one ref")
|
|
@@ -874,7 +952,7 @@ function compileAggregateRefs(
|
|
|
874
952
|
ref.value ->> 'primaryId' AS primary_id
|
|
875
953
|
FROM jsonb_array_elements(?::text::jsonb) AS ref(value)
|
|
876
954
|
) AS requested
|
|
877
|
-
JOIN
|
|
955
|
+
JOIN ${source.objectsTable} AS selected
|
|
878
956
|
ON selected.project_id = ?
|
|
879
957
|
AND selected.object_type_id = requested.object_type_id
|
|
880
958
|
AND selected.primary_id = requested.primary_id
|
|
@@ -886,9 +964,10 @@ function compileAggregateRefs(
|
|
|
886
964
|
function compileAggregateWhere(
|
|
887
965
|
projectId: string,
|
|
888
966
|
inputQuery: ObjectQuery,
|
|
889
|
-
predicate: CompiledPredicate
|
|
967
|
+
predicate: CompiledPredicate,
|
|
968
|
+
source: PgObjectQuerySource
|
|
890
969
|
): CompiledAggregateSource {
|
|
891
|
-
const input = compileAggregateSource(projectId, inputQuery)
|
|
970
|
+
const input = compileAggregateSource(projectId, inputQuery, source)
|
|
892
971
|
return {
|
|
893
972
|
sql: `
|
|
894
973
|
SELECT input.project_id, input.object_type_id, input.primary_id, input.properties
|
|
@@ -904,30 +983,31 @@ function compileAggregateTraversal(
|
|
|
904
983
|
inputQuery: ObjectQuery,
|
|
905
984
|
linkId: string,
|
|
906
985
|
direction: "outgoing" | "incoming",
|
|
907
|
-
sourceObjectTypeId
|
|
986
|
+
sourceObjectTypeId: string | undefined,
|
|
987
|
+
source: PgObjectQuerySource
|
|
908
988
|
): CompiledAggregateSource {
|
|
909
|
-
const input = compileAggregateSource(projectId, inputQuery)
|
|
989
|
+
const input = compileAggregateSource(projectId, inputQuery, source)
|
|
910
990
|
const outputAlias = direction === "outgoing" ? "target_object" : "source_object"
|
|
911
991
|
const joinSql =
|
|
912
992
|
direction === "outgoing"
|
|
913
993
|
? `
|
|
914
|
-
JOIN
|
|
994
|
+
JOIN ${source.linksTable} AS edge
|
|
915
995
|
ON edge.project_id = input.project_id
|
|
916
996
|
AND edge.source_type_id = input.object_type_id
|
|
917
997
|
AND edge.source_id = input.primary_id
|
|
918
998
|
AND edge.link_id = ?
|
|
919
|
-
JOIN
|
|
999
|
+
JOIN ${source.objectsTable} AS target_object
|
|
920
1000
|
ON target_object.project_id = edge.project_id
|
|
921
1001
|
AND target_object.object_type_id = edge.target_type_id
|
|
922
1002
|
AND target_object.primary_id = edge.target_id
|
|
923
1003
|
`
|
|
924
1004
|
: `
|
|
925
|
-
JOIN
|
|
1005
|
+
JOIN ${source.linksTable} AS edge
|
|
926
1006
|
ON edge.project_id = input.project_id
|
|
927
1007
|
AND edge.target_type_id = input.object_type_id
|
|
928
1008
|
AND edge.target_id = input.primary_id
|
|
929
1009
|
AND edge.link_id = ?${sourceObjectTypeId === undefined ? "" : "\n AND edge.source_type_id = ?"}
|
|
930
|
-
JOIN
|
|
1010
|
+
JOIN ${source.objectsTable} AS source_object
|
|
931
1011
|
ON source_object.project_id = edge.project_id
|
|
932
1012
|
AND source_object.object_type_id = edge.source_type_id
|
|
933
1013
|
AND source_object.primary_id = edge.source_id
|
|
@@ -954,26 +1034,27 @@ function compileAggregateTraversal(
|
|
|
954
1034
|
function compileAggregateSet(
|
|
955
1035
|
projectId: string,
|
|
956
1036
|
op: ObjectQuerySetOperation,
|
|
957
|
-
inputs: readonly ObjectQuery[]
|
|
1037
|
+
inputs: readonly ObjectQuery[],
|
|
1038
|
+
source: PgObjectQuerySource
|
|
958
1039
|
): CompiledAggregateSource {
|
|
959
1040
|
if (inputs.length === 0) {
|
|
960
1041
|
return {
|
|
961
1042
|
sql: `
|
|
962
1043
|
SELECT project_id, object_type_id, primary_id, properties
|
|
963
|
-
FROM
|
|
1044
|
+
FROM ${source.objectsTable}
|
|
964
1045
|
WHERE 1 = 0
|
|
965
1046
|
`,
|
|
966
1047
|
args: [],
|
|
967
1048
|
}
|
|
968
1049
|
}
|
|
969
1050
|
|
|
970
|
-
const compiledInputs = inputs.map((input) => compileAggregateSource(projectId, input))
|
|
1051
|
+
const compiledInputs = inputs.map((input) => compileAggregateSource(projectId, input, source))
|
|
971
1052
|
const identities = compileSetIdentities(op, compiledInputs)
|
|
972
1053
|
return {
|
|
973
1054
|
sql: `
|
|
974
1055
|
SELECT selected.project_id, selected.object_type_id, selected.primary_id, selected.properties
|
|
975
1056
|
FROM (${identities.sql}) AS ids
|
|
976
|
-
JOIN
|
|
1057
|
+
JOIN ${source.objectsTable} AS selected
|
|
977
1058
|
ON selected.project_id = ?
|
|
978
1059
|
AND selected.object_type_id = ids.object_type_id
|
|
979
1060
|
AND selected.primary_id = ids.primary_id
|
|
@@ -984,9 +1065,13 @@ function compileAggregateSet(
|
|
|
984
1065
|
|
|
985
1066
|
function compileRowQueryAggregateSource(
|
|
986
1067
|
projectId: string,
|
|
987
|
-
query: ObjectQuery
|
|
1068
|
+
query: ObjectQuery,
|
|
1069
|
+
source: PgObjectQuerySource
|
|
988
1070
|
): CompiledAggregateSource {
|
|
989
|
-
const rowQuery = compileObjectQueryInternal(projectId, query,
|
|
1071
|
+
const rowQuery = compileObjectQueryInternal(projectId, query, {
|
|
1072
|
+
probeLimit: false,
|
|
1073
|
+
source,
|
|
1074
|
+
})
|
|
990
1075
|
return {
|
|
991
1076
|
sql: `
|
|
992
1077
|
SELECT input.project_id, input.object_type_id, input.primary_id, input.properties
|