@sixb/sqlite 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/execution-storage.d.ts +3 -2
- package/dist/execution-storage.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1492 -380
- package/dist/index.js.map +16 -10
- package/dist/migrations.d.ts.map +1 -1
- package/dist/objects/index.d.ts +3 -0
- package/dist/objects/index.d.ts.map +1 -0
- package/dist/{object-query-compiler.d.ts → objects/query-compiler.d.ts} +16 -1
- 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 +51 -0
- package/dist/objects/reader.d.ts.map +1 -0
- package/dist/objects/rows.d.ts +33 -0
- package/dist/objects/rows.d.ts.map +1 -0
- package/dist/objects/selected-reader.d.ts +9 -0
- package/dist/objects/selected-reader.d.ts.map +1 -0
- package/dist/{object-storage.d.ts → objects/storage.d.ts} +12 -9
- package/dist/objects/storage.d.ts.map +1 -0
- package/dist/share-grant-storage.d.ts +20 -0
- package/dist/share-grant-storage.d.ts.map +1 -0
- package/dist/share-session-storage.d.ts +19 -0
- package/dist/share-session-storage.d.ts.map +1 -0
- package/dist/storage-errors.d.ts +1 -0
- package/dist/storage-errors.d.ts.map +1 -1
- package/dist/transactions.d.ts +8 -0
- package/dist/transactions.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/execution-storage.ts +22 -3
- package/src/index.ts +18 -3
- package/src/migrations/035-share-grants.sql +66 -0
- package/src/migrations/036-share-sessions.sql +226 -0
- package/src/migrations.ts +4 -0
- package/src/objects/index.ts +2 -0
- package/src/{object-query-compiler.ts → objects/query-compiler.ts} +104 -54
- package/src/objects/read-scope.ts +316 -0
- package/src/objects/reader.ts +526 -0
- package/src/objects/rows.ts +123 -0
- package/src/objects/selected-reader.ts +119 -0
- package/src/objects/storage.ts +296 -0
- package/src/share-grant-storage.ts +252 -0
- package/src/share-session-storage.ts +189 -0
- package/src/storage-errors.ts +4 -0
- package/src/transactions.ts +32 -0
- package/dist/object-query-compiler.d.ts.map +0 -1
- package/dist/object-storage.d.ts.map +0 -1
- package/src/object-storage.ts +0 -709
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
-- Shared sessions and their execution provenance.
|
|
2
|
+
CREATE TABLE share_sessions (
|
|
3
|
+
project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
|
|
4
|
+
id TEXT NOT NULL CHECK (length(trim(id)) > 0),
|
|
5
|
+
grant_id TEXT NOT NULL CHECK (length(trim(grant_id)) > 0),
|
|
6
|
+
token_hash TEXT NOT NULL CHECK (
|
|
7
|
+
length(token_hash) = 64
|
|
8
|
+
AND token_hash = lower(token_hash)
|
|
9
|
+
AND token_hash NOT GLOB '*[^0-9a-f]*'
|
|
10
|
+
),
|
|
11
|
+
created_at TEXT NOT NULL,
|
|
12
|
+
expires_at TEXT NOT NULL,
|
|
13
|
+
absolute_expires_at TEXT NOT NULL,
|
|
14
|
+
revoked_at TEXT,
|
|
15
|
+
PRIMARY KEY (project_id, id),
|
|
16
|
+
UNIQUE (project_id, id, grant_id),
|
|
17
|
+
UNIQUE (project_id, token_hash),
|
|
18
|
+
FOREIGN KEY (project_id, grant_id)
|
|
19
|
+
REFERENCES share_grants (project_id, id),
|
|
20
|
+
CHECK (expires_at > created_at),
|
|
21
|
+
CHECK (absolute_expires_at > created_at),
|
|
22
|
+
CHECK (expires_at <= absolute_expires_at),
|
|
23
|
+
CHECK (revoked_at IS NULL OR revoked_at >= created_at)
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
CREATE INDEX idx_share_sessions_grant
|
|
27
|
+
ON share_sessions (project_id, grant_id, created_at DESC, id DESC);
|
|
28
|
+
|
|
29
|
+
CREATE INDEX idx_share_sessions_expiry
|
|
30
|
+
ON share_sessions (project_id, expires_at)
|
|
31
|
+
WHERE revoked_at IS NULL;
|
|
32
|
+
|
|
33
|
+
-- Persist shared-session provenance on request executions without fabricating a principal.
|
|
34
|
+
CREATE TABLE executions_v2 (
|
|
35
|
+
project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
|
|
36
|
+
id TEXT NOT NULL CHECK (length(trim(id)) > 0),
|
|
37
|
+
executor_kind TEXT NOT NULL CHECK (
|
|
38
|
+
executor_kind IN (
|
|
39
|
+
'request', 'action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow',
|
|
40
|
+
'agent', 'kernel'
|
|
41
|
+
)
|
|
42
|
+
),
|
|
43
|
+
executor_id TEXT NOT NULL CHECK (length(trim(executor_id)) > 0),
|
|
44
|
+
source_kind TEXT NOT NULL CHECK (
|
|
45
|
+
source_kind IN ('http', 'webhook', 'schedule', 'event', 'datasetVersion', 'execution')
|
|
46
|
+
),
|
|
47
|
+
source_id TEXT NOT NULL CHECK (length(trim(source_id)) > 0),
|
|
48
|
+
requested_by_user_id TEXT,
|
|
49
|
+
requested_by_service_account_id TEXT,
|
|
50
|
+
correlation_id TEXT NOT NULL CHECK (length(trim(correlation_id)) > 0),
|
|
51
|
+
parent_execution_id TEXT,
|
|
52
|
+
authority_kind TEXT NOT NULL CHECK (
|
|
53
|
+
authority_kind IN ('principal', 'trustedPrimitive', 'delegated', 'kernel', 'disabled')
|
|
54
|
+
),
|
|
55
|
+
authority_user_id TEXT,
|
|
56
|
+
authority_service_account_id TEXT,
|
|
57
|
+
authority_session_id TEXT,
|
|
58
|
+
authority_access_token_id TEXT,
|
|
59
|
+
authority_primitive_kind TEXT CHECK (
|
|
60
|
+
authority_primitive_kind IS NULL
|
|
61
|
+
OR authority_primitive_kind IN (
|
|
62
|
+
'action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow'
|
|
63
|
+
)
|
|
64
|
+
),
|
|
65
|
+
authority_primitive_id TEXT,
|
|
66
|
+
authority_kernel_operation TEXT CHECK (
|
|
67
|
+
authority_kernel_operation IS NULL OR authority_kernel_operation = 'ontology.recover'
|
|
68
|
+
),
|
|
69
|
+
authority_delegation_kind TEXT CHECK (
|
|
70
|
+
authority_delegation_kind IS NULL OR authority_delegation_kind = 'share'
|
|
71
|
+
),
|
|
72
|
+
authority_delegation_id TEXT,
|
|
73
|
+
authority_delegation_session_id TEXT,
|
|
74
|
+
created_at TEXT NOT NULL,
|
|
75
|
+
PRIMARY KEY (project_id, id),
|
|
76
|
+
FOREIGN KEY (project_id, parent_execution_id) REFERENCES executions (project_id, id),
|
|
77
|
+
FOREIGN KEY (project_id, requested_by_user_id) REFERENCES auth_users (project_id, id),
|
|
78
|
+
FOREIGN KEY (project_id, requested_by_service_account_id)
|
|
79
|
+
REFERENCES auth_service_accounts (project_id, id),
|
|
80
|
+
FOREIGN KEY (project_id, authority_user_id) REFERENCES auth_users (project_id, id),
|
|
81
|
+
FOREIGN KEY (project_id, authority_service_account_id)
|
|
82
|
+
REFERENCES auth_service_accounts (project_id, id),
|
|
83
|
+
FOREIGN KEY (project_id, authority_session_id) REFERENCES auth_sessions (project_id, id),
|
|
84
|
+
FOREIGN KEY (project_id, authority_access_token_id)
|
|
85
|
+
REFERENCES auth_access_tokens (project_id, id),
|
|
86
|
+
FOREIGN KEY (
|
|
87
|
+
project_id, authority_delegation_session_id, authority_delegation_id
|
|
88
|
+
) REFERENCES share_sessions (project_id, id, grant_id),
|
|
89
|
+
CHECK ((requested_by_user_id IS NOT NULL) + (requested_by_service_account_id IS NOT NULL) <= 1),
|
|
90
|
+
CHECK (
|
|
91
|
+
(source_kind = 'execution' AND parent_execution_id = source_id)
|
|
92
|
+
OR (source_kind <> 'execution' AND parent_execution_id IS NULL)
|
|
93
|
+
),
|
|
94
|
+
CHECK (
|
|
95
|
+
(
|
|
96
|
+
authority_kind = 'principal'
|
|
97
|
+
AND (authority_user_id IS NOT NULL) + (authority_service_account_id IS NOT NULL) = 1
|
|
98
|
+
AND (authority_session_id IS NOT NULL) + (authority_access_token_id IS NOT NULL) <= 1
|
|
99
|
+
AND (authority_session_id IS NULL OR authority_user_id IS NOT NULL)
|
|
100
|
+
AND authority_primitive_kind IS NULL
|
|
101
|
+
AND authority_primitive_id IS NULL
|
|
102
|
+
AND authority_kernel_operation IS NULL
|
|
103
|
+
AND authority_delegation_kind IS NULL
|
|
104
|
+
AND authority_delegation_id IS NULL
|
|
105
|
+
AND authority_delegation_session_id IS NULL
|
|
106
|
+
)
|
|
107
|
+
OR (
|
|
108
|
+
authority_kind = 'trustedPrimitive'
|
|
109
|
+
AND authority_user_id IS NULL
|
|
110
|
+
AND authority_service_account_id IS NULL
|
|
111
|
+
AND authority_session_id IS NULL
|
|
112
|
+
AND authority_access_token_id IS NULL
|
|
113
|
+
AND authority_primitive_kind IS NOT NULL
|
|
114
|
+
AND authority_primitive_id IS NOT NULL
|
|
115
|
+
AND length(trim(authority_primitive_id)) > 0
|
|
116
|
+
AND authority_kernel_operation IS NULL
|
|
117
|
+
AND authority_delegation_kind IS NULL
|
|
118
|
+
AND authority_delegation_id IS NULL
|
|
119
|
+
AND authority_delegation_session_id IS NULL
|
|
120
|
+
)
|
|
121
|
+
OR (
|
|
122
|
+
authority_kind = 'delegated'
|
|
123
|
+
AND authority_user_id IS NULL
|
|
124
|
+
AND authority_service_account_id IS NULL
|
|
125
|
+
AND authority_session_id IS NULL
|
|
126
|
+
AND authority_access_token_id IS NULL
|
|
127
|
+
AND authority_primitive_kind IS NULL
|
|
128
|
+
AND authority_primitive_id IS NULL
|
|
129
|
+
AND authority_kernel_operation IS NULL
|
|
130
|
+
AND authority_delegation_kind IS NOT NULL
|
|
131
|
+
AND authority_delegation_kind = 'share'
|
|
132
|
+
AND authority_delegation_id IS NOT NULL
|
|
133
|
+
AND length(trim(authority_delegation_id)) > 0
|
|
134
|
+
AND authority_delegation_session_id IS NOT NULL
|
|
135
|
+
AND length(trim(authority_delegation_session_id)) > 0
|
|
136
|
+
)
|
|
137
|
+
OR (
|
|
138
|
+
authority_kind = 'kernel'
|
|
139
|
+
AND authority_user_id IS NULL
|
|
140
|
+
AND authority_service_account_id IS NULL
|
|
141
|
+
AND authority_session_id IS NULL
|
|
142
|
+
AND authority_access_token_id IS NULL
|
|
143
|
+
AND authority_primitive_kind IS NULL
|
|
144
|
+
AND authority_primitive_id IS NULL
|
|
145
|
+
AND authority_kernel_operation IS NOT NULL
|
|
146
|
+
AND authority_delegation_kind IS NULL
|
|
147
|
+
AND authority_delegation_id IS NULL
|
|
148
|
+
AND authority_delegation_session_id IS NULL
|
|
149
|
+
)
|
|
150
|
+
OR (
|
|
151
|
+
authority_kind = 'disabled'
|
|
152
|
+
AND authority_user_id IS NULL
|
|
153
|
+
AND authority_service_account_id IS NULL
|
|
154
|
+
AND authority_session_id IS NULL
|
|
155
|
+
AND authority_access_token_id IS NULL
|
|
156
|
+
AND authority_primitive_kind IS NULL
|
|
157
|
+
AND authority_primitive_id IS NULL
|
|
158
|
+
AND authority_kernel_operation IS NULL
|
|
159
|
+
AND authority_delegation_kind IS NULL
|
|
160
|
+
AND authority_delegation_id IS NULL
|
|
161
|
+
AND authority_delegation_session_id IS NULL
|
|
162
|
+
)
|
|
163
|
+
),
|
|
164
|
+
CHECK (
|
|
165
|
+
(
|
|
166
|
+
executor_kind = 'request'
|
|
167
|
+
AND source_kind = 'http'
|
|
168
|
+
AND executor_id = source_id
|
|
169
|
+
AND (
|
|
170
|
+
(
|
|
171
|
+
authority_kind = 'principal'
|
|
172
|
+
AND requested_by_user_id IS authority_user_id
|
|
173
|
+
AND requested_by_service_account_id IS authority_service_account_id
|
|
174
|
+
)
|
|
175
|
+
OR (
|
|
176
|
+
authority_kind IN ('delegated', 'disabled')
|
|
177
|
+
AND requested_by_user_id IS NULL
|
|
178
|
+
AND requested_by_service_account_id IS NULL
|
|
179
|
+
)
|
|
180
|
+
)
|
|
181
|
+
)
|
|
182
|
+
OR (
|
|
183
|
+
executor_kind IN ('action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow')
|
|
184
|
+
AND authority_kind = 'trustedPrimitive'
|
|
185
|
+
AND executor_kind = authority_primitive_kind
|
|
186
|
+
)
|
|
187
|
+
OR (
|
|
188
|
+
executor_kind = 'agent'
|
|
189
|
+
AND source_kind = 'execution'
|
|
190
|
+
AND (
|
|
191
|
+
(
|
|
192
|
+
authority_kind = 'principal'
|
|
193
|
+
AND authority_service_account_id IS NOT NULL
|
|
194
|
+
AND authority_session_id IS NULL
|
|
195
|
+
AND authority_access_token_id IS NULL
|
|
196
|
+
)
|
|
197
|
+
OR (
|
|
198
|
+
authority_kind = 'principal'
|
|
199
|
+
AND authority_user_id IS NOT NULL
|
|
200
|
+
AND (authority_session_id IS NOT NULL) + (authority_access_token_id IS NOT NULL) = 1
|
|
201
|
+
)
|
|
202
|
+
OR authority_kind = 'disabled'
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
OR (executor_kind = 'kernel' AND authority_kind = 'kernel')
|
|
206
|
+
)
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
INSERT INTO executions_v2 (
|
|
210
|
+
project_id, id, executor_kind, executor_id, source_kind, source_id,
|
|
211
|
+
requested_by_user_id, requested_by_service_account_id, correlation_id, parent_execution_id,
|
|
212
|
+
authority_kind, authority_user_id, authority_service_account_id, authority_session_id,
|
|
213
|
+
authority_access_token_id, authority_primitive_kind, authority_primitive_id,
|
|
214
|
+
authority_kernel_operation, authority_delegation_kind, authority_delegation_id,
|
|
215
|
+
authority_delegation_session_id, created_at
|
|
216
|
+
)
|
|
217
|
+
SELECT
|
|
218
|
+
project_id, id, executor_kind, executor_id, source_kind, source_id,
|
|
219
|
+
requested_by_user_id, requested_by_service_account_id, correlation_id, parent_execution_id,
|
|
220
|
+
authority_kind, authority_user_id, authority_service_account_id, authority_session_id,
|
|
221
|
+
authority_access_token_id, authority_primitive_kind, authority_primitive_id,
|
|
222
|
+
authority_kernel_operation, NULL, NULL, NULL, created_at
|
|
223
|
+
FROM executions;
|
|
224
|
+
|
|
225
|
+
DROP TABLE executions;
|
|
226
|
+
ALTER TABLE executions_v2 RENAME TO executions;
|
package/src/migrations.ts
CHANGED
|
@@ -88,6 +88,8 @@ import retireAgentDefinitionsSql from "./migrations/033-retire-agent-definitions
|
|
|
88
88
|
import deviceAuthorizationsSql from "./migrations/034-device-authorizations.sql" with {
|
|
89
89
|
type: "text",
|
|
90
90
|
}
|
|
91
|
+
import shareGrantsSql from "./migrations/035-share-grants.sql" with { type: "text" }
|
|
92
|
+
import shareSessionsSql from "./migrations/036-share-sessions.sql" with { type: "text" }
|
|
91
93
|
|
|
92
94
|
const MIGRATIONS_TABLE_SQL = `
|
|
93
95
|
CREATE TABLE IF NOT EXISTS sixb_migrations (
|
|
@@ -177,6 +179,8 @@ export const sqliteStorageMigrations = defineMigrations({
|
|
|
177
179
|
sqliteSql("032-conversation-run-spec", conversationRunSpecSql),
|
|
178
180
|
sqliteSql("033-retire-agent-definitions", retireAgentDefinitionsSql),
|
|
179
181
|
sqliteSql("034-device-authorizations", deviceAuthorizationsSql),
|
|
182
|
+
sqliteSql("035-share-grants", shareGrantsSql),
|
|
183
|
+
sqliteSql("036-share-sessions", shareSessionsSql),
|
|
180
184
|
],
|
|
181
185
|
})
|
|
182
186
|
|
|
@@ -36,6 +36,7 @@ interface CompiledHasMoreProbe {
|
|
|
36
36
|
|
|
37
37
|
interface CompileContext {
|
|
38
38
|
probeLimit: boolean
|
|
39
|
+
source: SqliteObjectQuerySource
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
interface CompiledPredicate {
|
|
@@ -74,7 +75,6 @@ interface EncodedCursorValue {
|
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
const PAGE_TOKEN_PREFIX = "keyset:"
|
|
77
|
-
const exactContext: CompileContext = { probeLimit: false }
|
|
78
78
|
|
|
79
79
|
// Fallback fanout cap for a "many" expansion that arrives without an explicit
|
|
80
80
|
// limit. The core executor normally bakes a limit in before pushdown; this only
|
|
@@ -84,10 +84,37 @@ const DEFAULT_EXPANSION_FANOUT = 1_000
|
|
|
84
84
|
export function compileObjectQuery(
|
|
85
85
|
projectId: string,
|
|
86
86
|
query: ObjectQuery,
|
|
87
|
-
options: { includeTotal?: boolean } = {}
|
|
87
|
+
options: { includeTotal?: boolean; source?: SqliteObjectQuerySource } = {}
|
|
88
88
|
): CompiledObjectQuery {
|
|
89
|
-
const
|
|
90
|
-
|
|
89
|
+
const source = options.source ?? DEFAULT_OBJECT_QUERY_SOURCE
|
|
90
|
+
const ctx: CompileContext = { probeLimit: options.includeTotal === false, source }
|
|
91
|
+
return source.wrapQuery(compileObjectQueryInternal(projectId, query, ctx))
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Physical relations used by the object-query compiler. */
|
|
95
|
+
export interface SqliteObjectQuerySource {
|
|
96
|
+
readonly objectsTable: string
|
|
97
|
+
readonly linksTable: string
|
|
98
|
+
/** Wrap a terminal SELECT without its own WITH clause; the selected source owns the only WITH. */
|
|
99
|
+
wrapStatement(
|
|
100
|
+
sql: string,
|
|
101
|
+
args?: readonly SqliteValue[]
|
|
102
|
+
): {
|
|
103
|
+
readonly sql: string
|
|
104
|
+
readonly args: readonly SqliteValue[]
|
|
105
|
+
}
|
|
106
|
+
wrapQuery(query: CompiledObjectQuery): CompiledObjectQuery
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export const DEFAULT_OBJECT_QUERY_SOURCE: SqliteObjectQuerySource = {
|
|
110
|
+
objectsTable: "objects",
|
|
111
|
+
linksTable: "links",
|
|
112
|
+
wrapStatement: (sql, args = []) => ({ sql, args: [...args] }),
|
|
113
|
+
wrapQuery: (query) => query,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function exactContext(ctx: CompileContext): CompileContext {
|
|
117
|
+
return ctx.probeLimit ? { ...ctx, probeLimit: false } : ctx
|
|
91
118
|
}
|
|
92
119
|
|
|
93
120
|
function compileObjectQueryInternal(
|
|
@@ -97,27 +124,28 @@ function compileObjectQueryInternal(
|
|
|
97
124
|
): CompiledObjectQuery {
|
|
98
125
|
switch (query.kind) {
|
|
99
126
|
case "start":
|
|
100
|
-
return compileStart(projectId, query)
|
|
127
|
+
return compileStart(projectId, query, ctx)
|
|
101
128
|
case "refs":
|
|
102
|
-
return compileRefs(projectId, query)
|
|
129
|
+
return compileRefs(projectId, query, ctx)
|
|
103
130
|
case "filter":
|
|
104
|
-
return compileFilter(projectId, query.input, query.predicate)
|
|
131
|
+
return compileFilter(projectId, query.input, query.predicate, ctx)
|
|
105
132
|
case "sort":
|
|
106
133
|
return compileSort(projectId, query.input, query.fields, ctx)
|
|
107
134
|
case "limit":
|
|
108
135
|
return compileLimit(projectId, query.input, query.limit, ctx)
|
|
109
136
|
case "page":
|
|
110
|
-
return compilePage(projectId, query.input, query.pageSize, query.pageToken)
|
|
137
|
+
return compilePage(projectId, query.input, query.pageSize, query.pageToken, ctx)
|
|
111
138
|
case "traverse":
|
|
112
139
|
return compileTraversal(
|
|
113
140
|
projectId,
|
|
114
141
|
query.input,
|
|
115
142
|
query.linkId,
|
|
116
143
|
query.direction,
|
|
117
|
-
query.sourceObjectTypeId
|
|
144
|
+
query.sourceObjectTypeId,
|
|
145
|
+
ctx
|
|
118
146
|
)
|
|
119
147
|
case "set":
|
|
120
|
-
return compileSet(projectId, query.op, query.inputs)
|
|
148
|
+
return compileSet(projectId, query.op, query.inputs, ctx)
|
|
121
149
|
case "project":
|
|
122
150
|
return compileProject(projectId, query.input, query.properties, ctx)
|
|
123
151
|
case "text":
|
|
@@ -126,10 +154,11 @@ function compileObjectQueryInternal(
|
|
|
126
154
|
query.input,
|
|
127
155
|
query.query,
|
|
128
156
|
query.fields,
|
|
129
|
-
query.fieldsByObjectType
|
|
157
|
+
query.fieldsByObjectType,
|
|
158
|
+
ctx
|
|
130
159
|
)
|
|
131
160
|
case "expand":
|
|
132
|
-
return compileExpand(projectId, query.input, query.expansions)
|
|
161
|
+
return compileExpand(projectId, query.input, query.expansions, ctx)
|
|
133
162
|
case "vector":
|
|
134
163
|
throw new Error(`[Sixb] SQLite object storage does not support query node '${query.kind}'`)
|
|
135
164
|
}
|
|
@@ -137,7 +166,8 @@ function compileObjectQueryInternal(
|
|
|
137
166
|
|
|
138
167
|
function compileStart(
|
|
139
168
|
projectId: string,
|
|
140
|
-
query: Extract<ObjectQuery, { kind: "start" }
|
|
169
|
+
query: Extract<ObjectQuery, { kind: "start" }>,
|
|
170
|
+
ctx: CompileContext
|
|
141
171
|
): CompiledObjectQuery {
|
|
142
172
|
if (query.includeSubtypes === true) {
|
|
143
173
|
throw new Error("[Sixb] SQLite object storage does not support start.includeSubtypes")
|
|
@@ -146,7 +176,7 @@ function compileStart(
|
|
|
146
176
|
const order = compileOrder(identityOrderFields())
|
|
147
177
|
const sql = `
|
|
148
178
|
SELECT *, properties AS _cursor_properties
|
|
149
|
-
FROM
|
|
179
|
+
FROM ${ctx.source.objectsTable}
|
|
150
180
|
WHERE project_id = ? AND object_type_id = ?
|
|
151
181
|
ORDER BY ${order.sql}
|
|
152
182
|
`
|
|
@@ -155,7 +185,7 @@ function compileStart(
|
|
|
155
185
|
return {
|
|
156
186
|
sql,
|
|
157
187
|
args,
|
|
158
|
-
totalSql:
|
|
188
|
+
totalSql: `SELECT COUNT(*) as total FROM ${ctx.source.objectsTable} WHERE project_id = ? AND object_type_id = ?`,
|
|
159
189
|
totalArgs: [projectId, query.objectTypeId],
|
|
160
190
|
order,
|
|
161
191
|
hasMore: () => false,
|
|
@@ -166,7 +196,8 @@ function compileStart(
|
|
|
166
196
|
|
|
167
197
|
function compileRefs(
|
|
168
198
|
projectId: string,
|
|
169
|
-
query: Extract<ObjectQuery, { kind: "refs" }
|
|
199
|
+
query: Extract<ObjectQuery, { kind: "refs" }>,
|
|
200
|
+
ctx: CompileContext
|
|
170
201
|
): CompiledObjectQuery {
|
|
171
202
|
if (query.refs.length === 0) {
|
|
172
203
|
throw new Error("[Sixb] SQLite object storage requires at least one ref")
|
|
@@ -182,10 +213,9 @@ function compileRefs(
|
|
|
182
213
|
FROM json_each(?) AS ref
|
|
183
214
|
`
|
|
184
215
|
const sql = `
|
|
185
|
-
WITH requested AS (${requested})
|
|
186
216
|
SELECT selected.*, selected.properties AS _cursor_properties
|
|
187
|
-
FROM requested
|
|
188
|
-
JOIN
|
|
217
|
+
FROM (${requested}) AS requested
|
|
218
|
+
JOIN ${ctx.source.objectsTable} AS selected
|
|
189
219
|
ON selected.project_id = ?
|
|
190
220
|
AND selected.object_type_id = requested.object_type_id
|
|
191
221
|
AND selected.primary_id = requested.primary_id
|
|
@@ -196,10 +226,9 @@ function compileRefs(
|
|
|
196
226
|
sql,
|
|
197
227
|
args: [refsJson, projectId, ...selectedOrder.args],
|
|
198
228
|
totalSql: `
|
|
199
|
-
WITH requested AS (${requested})
|
|
200
229
|
SELECT COUNT(*) AS total
|
|
201
|
-
FROM requested
|
|
202
|
-
JOIN
|
|
230
|
+
FROM (${requested}) AS requested
|
|
231
|
+
JOIN ${ctx.source.objectsTable} AS selected
|
|
203
232
|
ON selected.project_id = ?
|
|
204
233
|
AND selected.object_type_id = requested.object_type_id
|
|
205
234
|
AND selected.primary_id = requested.primary_id
|
|
@@ -215,18 +244,20 @@ function compileRefs(
|
|
|
215
244
|
function compileFilter(
|
|
216
245
|
projectId: string,
|
|
217
246
|
inputQuery: ObjectQuery,
|
|
218
|
-
predicateNode: ObjectQueryPredicate
|
|
247
|
+
predicateNode: ObjectQueryPredicate,
|
|
248
|
+
ctx: CompileContext
|
|
219
249
|
): CompiledObjectQuery {
|
|
220
250
|
const predicate = compilePredicate(predicateNode)
|
|
221
|
-
return compileWhere(projectId, inputQuery, predicate)
|
|
251
|
+
return compileWhere(projectId, inputQuery, predicate, ctx)
|
|
222
252
|
}
|
|
223
253
|
|
|
224
254
|
function compileWhere(
|
|
225
255
|
projectId: string,
|
|
226
256
|
inputQuery: ObjectQuery,
|
|
227
|
-
predicate: CompiledPredicate
|
|
257
|
+
predicate: CompiledPredicate,
|
|
258
|
+
ctx: CompileContext
|
|
228
259
|
): CompiledObjectQuery {
|
|
229
|
-
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext)
|
|
260
|
+
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext(ctx))
|
|
230
261
|
const sql = `
|
|
231
262
|
SELECT *
|
|
232
263
|
FROM (${input.sql}) AS input
|
|
@@ -255,7 +286,8 @@ function compileText(
|
|
|
255
286
|
inputQuery: ObjectQuery,
|
|
256
287
|
query: string,
|
|
257
288
|
fields: readonly string[] | undefined,
|
|
258
|
-
fieldsByObjectType: Readonly<Record<string, readonly string[]>> | undefined
|
|
289
|
+
fieldsByObjectType: Readonly<Record<string, readonly string[]>> | undefined,
|
|
290
|
+
ctx: CompileContext
|
|
259
291
|
): CompiledObjectQuery {
|
|
260
292
|
const predicate =
|
|
261
293
|
fields && fields.length > 0
|
|
@@ -265,7 +297,7 @@ function compileText(
|
|
|
265
297
|
if (!predicate) {
|
|
266
298
|
throw new Error("[Sixb] SQLite object text search requires fields or resolved text defaults")
|
|
267
299
|
}
|
|
268
|
-
return compileWhere(projectId, inputQuery, predicate)
|
|
300
|
+
return compileWhere(projectId, inputQuery, predicate, ctx)
|
|
269
301
|
}
|
|
270
302
|
|
|
271
303
|
function compileSort(
|
|
@@ -274,7 +306,7 @@ function compileSort(
|
|
|
274
306
|
fields: readonly ObjectQuerySortField[],
|
|
275
307
|
ctx: CompileContext
|
|
276
308
|
): CompiledObjectQuery {
|
|
277
|
-
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext)
|
|
309
|
+
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext(ctx))
|
|
278
310
|
const probeInput =
|
|
279
311
|
ctx.probeLimit && needsLimitProbe(inputQuery)
|
|
280
312
|
? compileObjectQueryInternal(projectId, inputQuery, ctx)
|
|
@@ -313,7 +345,7 @@ function compileLimit(
|
|
|
313
345
|
rawLimit: number,
|
|
314
346
|
ctx: CompileContext
|
|
315
347
|
): CompiledObjectQuery {
|
|
316
|
-
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext)
|
|
348
|
+
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext(ctx))
|
|
317
349
|
const limit = Math.max(0, rawLimit)
|
|
318
350
|
const rowLimit = ctx.probeLimit ? limit + 1 : limit
|
|
319
351
|
|
|
@@ -342,9 +374,10 @@ function compilePage(
|
|
|
342
374
|
projectId: string,
|
|
343
375
|
inputQuery: ObjectQuery,
|
|
344
376
|
rawPageSize: number,
|
|
345
|
-
pageToken: string | undefined
|
|
377
|
+
pageToken: string | undefined,
|
|
378
|
+
ctx: CompileContext
|
|
346
379
|
): CompiledObjectQuery {
|
|
347
|
-
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext)
|
|
380
|
+
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext(ctx))
|
|
348
381
|
const pageSize = Math.max(0, rawPageSize)
|
|
349
382
|
const cursor = pageToken ? decodePageToken(pageToken, input.order.fields) : undefined
|
|
350
383
|
const cursorPredicate = cursor
|
|
@@ -381,30 +414,31 @@ function compileTraversal(
|
|
|
381
414
|
inputQuery: ObjectQuery,
|
|
382
415
|
linkId: string,
|
|
383
416
|
direction: "outgoing" | "incoming",
|
|
384
|
-
sourceObjectTypeId
|
|
417
|
+
sourceObjectTypeId: string | undefined,
|
|
418
|
+
ctx: CompileContext
|
|
385
419
|
): CompiledObjectQuery {
|
|
386
|
-
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext)
|
|
420
|
+
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext(ctx))
|
|
387
421
|
const outputAlias = direction === "outgoing" ? "target_object" : "source_object"
|
|
388
422
|
const joinSql =
|
|
389
423
|
direction === "outgoing"
|
|
390
424
|
? `
|
|
391
|
-
JOIN
|
|
425
|
+
JOIN ${ctx.source.linksTable} AS edge
|
|
392
426
|
ON edge.project_id = input.project_id
|
|
393
427
|
AND edge.source_type_id = input.object_type_id
|
|
394
428
|
AND edge.source_id = input.primary_id
|
|
395
429
|
AND edge.link_id = ?
|
|
396
|
-
JOIN
|
|
430
|
+
JOIN ${ctx.source.objectsTable} AS target_object
|
|
397
431
|
ON target_object.project_id = edge.project_id
|
|
398
432
|
AND target_object.object_type_id = edge.target_type_id
|
|
399
433
|
AND target_object.primary_id = edge.target_id
|
|
400
434
|
`
|
|
401
435
|
: `
|
|
402
|
-
JOIN
|
|
436
|
+
JOIN ${ctx.source.linksTable} AS edge
|
|
403
437
|
ON edge.project_id = input.project_id
|
|
404
438
|
AND edge.target_type_id = input.object_type_id
|
|
405
439
|
AND edge.target_id = input.primary_id
|
|
406
440
|
AND edge.link_id = ?${sourceObjectTypeId === undefined ? "" : "\n AND edge.source_type_id = ?"}
|
|
407
|
-
JOIN
|
|
441
|
+
JOIN ${ctx.source.objectsTable} AS source_object
|
|
408
442
|
ON source_object.project_id = edge.project_id
|
|
409
443
|
AND source_object.object_type_id = edge.source_type_id
|
|
410
444
|
AND source_object.primary_id = edge.source_id
|
|
@@ -451,13 +485,15 @@ interface ExpansionParent {
|
|
|
451
485
|
function compileExpand(
|
|
452
486
|
projectId: string,
|
|
453
487
|
inputQuery: ObjectQuery,
|
|
454
|
-
expansions: readonly ObjectExpansion[]
|
|
488
|
+
expansions: readonly ObjectExpansion[],
|
|
489
|
+
ctx: CompileContext
|
|
455
490
|
): CompiledObjectQuery {
|
|
456
|
-
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext)
|
|
491
|
+
const input = compileObjectQueryInternal(projectId, inputQuery, exactContext(ctx))
|
|
457
492
|
const expand = compileExpansionsObject(
|
|
458
493
|
expansions,
|
|
459
494
|
{ project: "input.project_id", type: "input.object_type_id", id: "input.primary_id" },
|
|
460
|
-
""
|
|
495
|
+
"",
|
|
496
|
+
ctx
|
|
461
497
|
)
|
|
462
498
|
const inputOrder = compileOrder(input.order.fields, "input", "input._cursor_properties")
|
|
463
499
|
const sql = `
|
|
@@ -487,13 +523,14 @@ function compileExpand(
|
|
|
487
523
|
function compileExpansionsObject(
|
|
488
524
|
expansions: readonly ObjectExpansion[],
|
|
489
525
|
parent: ExpansionParent,
|
|
490
|
-
pathPrefix: string
|
|
526
|
+
pathPrefix: string,
|
|
527
|
+
ctx: CompileContext
|
|
491
528
|
): CompiledPredicate {
|
|
492
529
|
const parts: string[] = []
|
|
493
530
|
const args: SqliteValue[] = []
|
|
494
531
|
expansions.forEach((expansion, index) => {
|
|
495
532
|
const path = pathPrefix === "" ? `${index}` : `${pathPrefix}_${index}`
|
|
496
|
-
const value = compileExpansionValue(expansion, parent, path)
|
|
533
|
+
const value = compileExpansionValue(expansion, parent, path, ctx)
|
|
497
534
|
parts.push("?", `json(${value.sql})`)
|
|
498
535
|
args.push(expansion.linkId, ...value.args)
|
|
499
536
|
})
|
|
@@ -509,7 +546,8 @@ function compileExpansionsObject(
|
|
|
509
546
|
function compileExpansionValue(
|
|
510
547
|
expansion: ObjectExpansion,
|
|
511
548
|
parent: ExpansionParent,
|
|
512
|
-
path: string
|
|
549
|
+
path: string,
|
|
550
|
+
ctx: CompileContext
|
|
513
551
|
): CompiledPredicate {
|
|
514
552
|
const edge = `edge_${path}`
|
|
515
553
|
const target = `tgt_${path}`
|
|
@@ -522,7 +560,7 @@ function compileExpansionValue(
|
|
|
522
560
|
const parentType = incoming ? `${edge}.target_type_id` : `${edge}.source_type_id`
|
|
523
561
|
const parentId = incoming ? `${edge}.target_id` : `${edge}.source_id`
|
|
524
562
|
|
|
525
|
-
const child = compileExpansionChildJson(expansion, edge, target, path)
|
|
563
|
+
const child = compileExpansionChildJson(expansion, edge, target, path, ctx)
|
|
526
564
|
const order = compileExpansionOrder(expansion, target, neighborType, neighborId)
|
|
527
565
|
|
|
528
566
|
const whereParts = [
|
|
@@ -539,8 +577,8 @@ function compileExpansionValue(
|
|
|
539
577
|
|
|
540
578
|
const inner = `
|
|
541
579
|
SELECT ${child.sql} AS elem, row_number() OVER (ORDER BY ${order.sql}) AS _ord
|
|
542
|
-
FROM
|
|
543
|
-
JOIN
|
|
580
|
+
FROM ${ctx.source.linksTable} AS ${edge}
|
|
581
|
+
JOIN ${ctx.source.objectsTable} AS ${target}
|
|
544
582
|
ON ${target}.project_id = ${edge}.project_id
|
|
545
583
|
AND ${target}.object_type_id = ${neighborType}
|
|
546
584
|
AND ${target}.primary_id = ${neighborId}
|
|
@@ -574,7 +612,8 @@ function compileExpansionChildJson(
|
|
|
574
612
|
expansion: ObjectExpansion,
|
|
575
613
|
edge: string,
|
|
576
614
|
target: string,
|
|
577
|
-
path: string
|
|
615
|
+
path: string,
|
|
616
|
+
ctx: CompileContext
|
|
578
617
|
): CompiledPredicate {
|
|
579
618
|
const fields = [
|
|
580
619
|
`'projectId', ${target}.project_id`,
|
|
@@ -597,7 +636,8 @@ function compileExpansionChildJson(
|
|
|
597
636
|
type: `${target}.object_type_id`,
|
|
598
637
|
id: `${target}.primary_id`,
|
|
599
638
|
},
|
|
600
|
-
path
|
|
639
|
+
path,
|
|
640
|
+
ctx
|
|
601
641
|
)
|
|
602
642
|
fields.push(`'links', ${nested.sql}`)
|
|
603
643
|
args.push(...nested.args)
|
|
@@ -645,14 +685,15 @@ function compileExpansionOrder(
|
|
|
645
685
|
function compileSet(
|
|
646
686
|
projectId: string,
|
|
647
687
|
op: ObjectQuerySetOperation,
|
|
648
|
-
inputs: readonly ObjectQuery[]
|
|
688
|
+
inputs: readonly ObjectQuery[],
|
|
689
|
+
ctx: CompileContext
|
|
649
690
|
): CompiledObjectQuery {
|
|
650
691
|
if (inputs.length === 0) {
|
|
651
692
|
const order = compileOrder(identityOrderFields())
|
|
652
693
|
return {
|
|
653
694
|
sql: `
|
|
654
695
|
SELECT *
|
|
655
|
-
FROM
|
|
696
|
+
FROM ${ctx.source.objectsTable}
|
|
656
697
|
WHERE 1 = 0
|
|
657
698
|
ORDER BY ${order.sql}
|
|
658
699
|
`,
|
|
@@ -667,7 +708,7 @@ function compileSet(
|
|
|
667
708
|
}
|
|
668
709
|
|
|
669
710
|
const compiledInputs = inputs.map((input) =>
|
|
670
|
-
compileObjectQueryInternal(projectId, input, exactContext)
|
|
711
|
+
compileObjectQueryInternal(projectId, input, exactContext(ctx))
|
|
671
712
|
)
|
|
672
713
|
const identities = compileSetIdentities(op, compiledInputs)
|
|
673
714
|
const order = compileOrder(identityOrderFields())
|
|
@@ -675,7 +716,7 @@ function compileSet(
|
|
|
675
716
|
const sql = `
|
|
676
717
|
SELECT selected.*, selected.properties AS _cursor_properties
|
|
677
718
|
FROM (${identities.sql}) AS ids
|
|
678
|
-
JOIN
|
|
719
|
+
JOIN ${ctx.source.objectsTable} AS selected
|
|
679
720
|
ON selected.project_id = ?
|
|
680
721
|
AND selected.object_type_id = ids.object_type_id
|
|
681
722
|
AND selected.primary_id = ids.primary_id
|
|
@@ -778,7 +819,7 @@ function compileProjectionExpression(properties: readonly string[]): CompiledPre
|
|
|
778
819
|
sql: `
|
|
779
820
|
COALESCE(
|
|
780
821
|
(
|
|
781
|
-
SELECT json_group_object(projected.key, projected
|
|
822
|
+
SELECT json_group_object(projected.key, ${sqliteJsonEachValue("projected")})
|
|
782
823
|
FROM json_each(input.properties) AS projected
|
|
783
824
|
WHERE projected.key IN (${properties.map(() => "?").join(", ")})
|
|
784
825
|
),
|
|
@@ -789,6 +830,15 @@ function compileProjectionExpression(properties: readonly string[]): CompiledPre
|
|
|
789
830
|
}
|
|
790
831
|
}
|
|
791
832
|
|
|
833
|
+
/** json_each exposes JSON booleans as integer SQL values; restore their JSON representation. */
|
|
834
|
+
export function sqliteJsonEachValue(alias: string): string {
|
|
835
|
+
return `CASE ${alias}.type
|
|
836
|
+
WHEN 'true' THEN json('true')
|
|
837
|
+
WHEN 'false' THEN json('false')
|
|
838
|
+
ELSE ${alias}.value
|
|
839
|
+
END`
|
|
840
|
+
}
|
|
841
|
+
|
|
792
842
|
function compilePredicate(predicate: ObjectQueryPredicate): CompiledPredicate {
|
|
793
843
|
if (
|
|
794
844
|
"scalarKind" in predicate &&
|