@sixb/sqlite 0.1.0 → 0.1.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.
- package/dist/index.js +193 -48
- package/dist/index.js.map +6 -6
- package/dist/migrations.d.ts.map +1 -1
- package/dist/ontology-storage/materialization-state.d.ts.map +1 -1
- package/dist/workflow-run-storage.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/migrations/002-workflow-run-output.sql +27 -0
- package/src/migrations/003-merge-sync-runs.sql +71 -0
- package/src/migrations.ts +7 -1
- package/src/ontology-storage/materialization-state.ts +81 -42
- package/src/sync-run-storage.ts +2 -2
- package/src/workflow-run-storage.ts +7 -2
package/dist/index.js
CHANGED
|
@@ -1108,6 +1108,110 @@ CREATE INDEX idx_agent_messages_project_thread_role
|
|
|
1108
1108
|
ON agent_messages(project_id, thread_id, role, seq);
|
|
1109
1109
|
`;
|
|
1110
1110
|
|
|
1111
|
+
// src/migrations/002-workflow-run-output.sql
|
|
1112
|
+
var _002_workflow_run_output_default = `ALTER TABLE workflow_runs ADD COLUMN output TEXT;
|
|
1113
|
+
|
|
1114
|
+
UPDATE workflow_runs AS run
|
|
1115
|
+
SET output = CASE
|
|
1116
|
+
WHEN EXISTS (
|
|
1117
|
+
SELECT 1
|
|
1118
|
+
FROM workflow_node_runs AS node
|
|
1119
|
+
WHERE node.project_id = run.project_id
|
|
1120
|
+
AND node.workflow_run_id = run.id
|
|
1121
|
+
AND node.status = 'succeeded'
|
|
1122
|
+
AND node.node_type <> 'action'
|
|
1123
|
+
) THEN COALESCE(
|
|
1124
|
+
(
|
|
1125
|
+
SELECT node.output
|
|
1126
|
+
FROM workflow_node_runs AS node
|
|
1127
|
+
WHERE node.project_id = run.project_id
|
|
1128
|
+
AND node.workflow_run_id = run.id
|
|
1129
|
+
AND node.status = 'succeeded'
|
|
1130
|
+
AND node.node_type <> 'action'
|
|
1131
|
+
ORDER BY node.node_index DESC, node.id DESC
|
|
1132
|
+
LIMIT 1
|
|
1133
|
+
),
|
|
1134
|
+
'{}'
|
|
1135
|
+
)
|
|
1136
|
+
ELSE run.input
|
|
1137
|
+
END
|
|
1138
|
+
WHERE run.status = 'succeeded';
|
|
1139
|
+
`;
|
|
1140
|
+
|
|
1141
|
+
// src/migrations/003-merge-sync-runs.sql
|
|
1142
|
+
var _003_merge_sync_runs_default = `DROP INDEX idx_sync_runs_project_started;
|
|
1143
|
+
DROP INDEX idx_sync_runs_project_dataset_started;
|
|
1144
|
+
DROP INDEX idx_sync_runs_project_sync_started;
|
|
1145
|
+
DROP INDEX idx_sync_runs_project_status_started;
|
|
1146
|
+
|
|
1147
|
+
ALTER TABLE sync_runs RENAME TO sync_runs_before_merge_mode;
|
|
1148
|
+
|
|
1149
|
+
CREATE TABLE sync_runs (
|
|
1150
|
+
project_id TEXT NOT NULL,
|
|
1151
|
+
id TEXT NOT NULL,
|
|
1152
|
+
sync_id TEXT NOT NULL,
|
|
1153
|
+
dataset_id TEXT NOT NULL,
|
|
1154
|
+
mode TEXT NOT NULL CHECK (mode IN ('snapshot', 'append', 'merge')),
|
|
1155
|
+
status TEXT NOT NULL CHECK (status IN ('running', 'succeeded', 'failed', 'cancelled')),
|
|
1156
|
+
started_at TEXT NOT NULL,
|
|
1157
|
+
finished_at TEXT,
|
|
1158
|
+
rows_read INTEGER CHECK (rows_read IS NULL OR rows_read >= 0),
|
|
1159
|
+
output_version_id TEXT,
|
|
1160
|
+
expected_latest_version_id TEXT,
|
|
1161
|
+
commit_message TEXT,
|
|
1162
|
+
error_name TEXT,
|
|
1163
|
+
error_message TEXT,
|
|
1164
|
+
checkpoint TEXT,
|
|
1165
|
+
PRIMARY KEY (project_id, id)
|
|
1166
|
+
);
|
|
1167
|
+
|
|
1168
|
+
INSERT INTO sync_runs (
|
|
1169
|
+
project_id,
|
|
1170
|
+
id,
|
|
1171
|
+
sync_id,
|
|
1172
|
+
dataset_id,
|
|
1173
|
+
mode,
|
|
1174
|
+
status,
|
|
1175
|
+
started_at,
|
|
1176
|
+
finished_at,
|
|
1177
|
+
rows_read,
|
|
1178
|
+
output_version_id,
|
|
1179
|
+
expected_latest_version_id,
|
|
1180
|
+
commit_message,
|
|
1181
|
+
error_name,
|
|
1182
|
+
error_message,
|
|
1183
|
+
checkpoint
|
|
1184
|
+
)
|
|
1185
|
+
SELECT
|
|
1186
|
+
project_id,
|
|
1187
|
+
id,
|
|
1188
|
+
sync_id,
|
|
1189
|
+
dataset_id,
|
|
1190
|
+
mode,
|
|
1191
|
+
status,
|
|
1192
|
+
started_at,
|
|
1193
|
+
finished_at,
|
|
1194
|
+
rows_read,
|
|
1195
|
+
output_version_id,
|
|
1196
|
+
expected_latest_version_id,
|
|
1197
|
+
commit_message,
|
|
1198
|
+
error_name,
|
|
1199
|
+
error_message,
|
|
1200
|
+
checkpoint
|
|
1201
|
+
FROM sync_runs_before_merge_mode;
|
|
1202
|
+
|
|
1203
|
+
DROP TABLE sync_runs_before_merge_mode;
|
|
1204
|
+
|
|
1205
|
+
CREATE INDEX idx_sync_runs_project_started
|
|
1206
|
+
ON sync_runs(project_id, started_at DESC);
|
|
1207
|
+
CREATE INDEX idx_sync_runs_project_dataset_started
|
|
1208
|
+
ON sync_runs(project_id, dataset_id, started_at DESC);
|
|
1209
|
+
CREATE INDEX idx_sync_runs_project_sync_started
|
|
1210
|
+
ON sync_runs(project_id, sync_id, started_at DESC);
|
|
1211
|
+
CREATE INDEX idx_sync_runs_project_status_started
|
|
1212
|
+
ON sync_runs(project_id, status, started_at DESC);
|
|
1213
|
+
`;
|
|
1214
|
+
|
|
1111
1215
|
// src/migrations.ts
|
|
1112
1216
|
var MIGRATIONS_TABLE_SQL = `
|
|
1113
1217
|
CREATE TABLE IF NOT EXISTS sixb_migrations (
|
|
@@ -1125,7 +1229,11 @@ var SQLITE_STORAGE_ADAPTER_ID = "SixbSqliteStorage";
|
|
|
1125
1229
|
var SQLITE_STORAGE_FILE = "storage.sqlite";
|
|
1126
1230
|
var sqliteStorageMigrations = defineMigrations({
|
|
1127
1231
|
adapterId: SQLITE_STORAGE_ADAPTER_ID,
|
|
1128
|
-
steps: [
|
|
1232
|
+
steps: [
|
|
1233
|
+
sqliteSql("001-initial-schema", _001_initial_schema_default),
|
|
1234
|
+
sqliteSql("002-workflow-run-output", _002_workflow_run_output_default),
|
|
1235
|
+
sqliteSql("003-merge-sync-runs", _003_merge_sync_runs_default)
|
|
1236
|
+
]
|
|
1129
1237
|
});
|
|
1130
1238
|
function sqliteStoragePath(basePath) {
|
|
1131
1239
|
return `${basePath}/${SQLITE_STORAGE_FILE}`;
|
|
@@ -5722,22 +5830,30 @@ class SqliteMaterializationStateReader {
|
|
|
5722
5830
|
FROM json_each(?)
|
|
5723
5831
|
`;
|
|
5724
5832
|
const effectiveRows = this.db.query(`WITH requested AS (${requestedObjects})
|
|
5725
|
-
SELECT objects.* FROM
|
|
5726
|
-
JOIN
|
|
5727
|
-
|
|
5833
|
+
SELECT objects.* FROM requested
|
|
5834
|
+
CROSS JOIN objects
|
|
5835
|
+
ON objects.project_id = ?
|
|
5836
|
+
AND objects.object_type_id = requested.object_type_id
|
|
5837
|
+
AND objects.primary_id = requested.primary_id`).all(requested, this.projectId);
|
|
5728
5838
|
const sourceRows = this.db.query(`WITH requested AS (${requestedObjects})
|
|
5729
|
-
SELECT rows.* FROM
|
|
5730
|
-
JOIN
|
|
5839
|
+
SELECT rows.* FROM requested
|
|
5840
|
+
CROSS JOIN ontology_source_rows AS rows
|
|
5841
|
+
ON rows.project_id = ?
|
|
5842
|
+
AND rows.entity_kind = 'object'
|
|
5843
|
+
AND rows.object_type_id = requested.object_type_id
|
|
5844
|
+
AND rows.primary_id = requested.primary_id
|
|
5731
5845
|
JOIN ontology_sources AS sources
|
|
5732
5846
|
ON sources.project_id = rows.project_id
|
|
5733
5847
|
AND sources.source_id = rows.source_id
|
|
5734
5848
|
AND sources.materialization_id = rows.materialization_id
|
|
5735
|
-
WHERE
|
|
5736
|
-
AND sources.status = 'active'`).all(requested, this.projectId);
|
|
5849
|
+
WHERE sources.status = 'active'`).all(requested, this.projectId);
|
|
5737
5850
|
const overrideRows = this.db.query(`WITH requested AS (${requestedObjects})
|
|
5738
|
-
SELECT overrides.* FROM
|
|
5739
|
-
JOIN
|
|
5740
|
-
|
|
5851
|
+
SELECT overrides.* FROM requested
|
|
5852
|
+
CROSS JOIN ontology_overrides AS overrides
|
|
5853
|
+
ON overrides.project_id = ?
|
|
5854
|
+
AND overrides.entity_kind = 'object'
|
|
5855
|
+
AND overrides.object_type_id = requested.object_type_id
|
|
5856
|
+
AND overrides.primary_id = requested.primary_id`).all(requested, this.projectId);
|
|
5741
5857
|
const telemetryRows = this.db.query(`WITH requested AS (${requestedObjects}), ranked AS (
|
|
5742
5858
|
SELECT timeseries.*,
|
|
5743
5859
|
ROW_NUMBER() OVER (
|
|
@@ -5745,11 +5861,11 @@ class SqliteMaterializationStateReader {
|
|
|
5745
5861
|
timeseries.property_id
|
|
5746
5862
|
ORDER BY timeseries.at DESC
|
|
5747
5863
|
) AS rank
|
|
5748
|
-
FROM
|
|
5749
|
-
JOIN
|
|
5750
|
-
ON
|
|
5751
|
-
AND
|
|
5752
|
-
|
|
5864
|
+
FROM requested
|
|
5865
|
+
CROSS JOIN timeseries
|
|
5866
|
+
ON timeseries.project_id = ?
|
|
5867
|
+
AND timeseries.object_type_id = requested.object_type_id
|
|
5868
|
+
AND timeseries.object_id = requested.primary_id
|
|
5753
5869
|
)
|
|
5754
5870
|
SELECT * FROM ranked WHERE rank = 1`).all(requested, this.projectId);
|
|
5755
5871
|
const effective = new Map(effectiveRows.map((row) => [objectRefKey(objectRefFromColumns(row)), row]));
|
|
@@ -5807,26 +5923,39 @@ class SqliteMaterializationStateReader {
|
|
|
5807
5923
|
FROM json_each(?)
|
|
5808
5924
|
`;
|
|
5809
5925
|
const effectiveRows = this.db.query(`WITH requested AS (${effectiveRequest})
|
|
5810
|
-
SELECT links.* FROM
|
|
5811
|
-
JOIN
|
|
5812
|
-
|
|
5926
|
+
SELECT links.* FROM requested
|
|
5927
|
+
CROSS JOIN links
|
|
5928
|
+
ON links.project_id = ?
|
|
5929
|
+
AND links.source_type_id = requested.source_type_id
|
|
5930
|
+
AND links.source_id = requested.source_id
|
|
5931
|
+
AND links.link_id = requested.link_id
|
|
5932
|
+
AND links.target_type_id = requested.target_type_id
|
|
5933
|
+
AND links.target_id = requested.target_id`).all(requested, this.projectId);
|
|
5813
5934
|
const sourceRows = this.db.query(`WITH requested AS (${sourceRequest})
|
|
5814
|
-
SELECT rows.* FROM
|
|
5815
|
-
JOIN
|
|
5816
|
-
|
|
5817
|
-
|
|
5935
|
+
SELECT rows.* FROM requested
|
|
5936
|
+
CROSS JOIN ontology_source_rows AS rows
|
|
5937
|
+
ON rows.project_id = ?
|
|
5938
|
+
AND rows.entity_kind = 'link'
|
|
5939
|
+
AND rows.source_type_id = requested.source_type_id
|
|
5940
|
+
AND rows.source_primary_id = requested.source_primary_id
|
|
5941
|
+
AND rows.link_id = requested.link_id
|
|
5942
|
+
AND rows.target_type_id = requested.target_type_id
|
|
5943
|
+
AND rows.target_primary_id = requested.target_primary_id
|
|
5818
5944
|
JOIN ontology_sources AS sources
|
|
5819
5945
|
ON sources.project_id = rows.project_id
|
|
5820
5946
|
AND sources.source_id = rows.source_id
|
|
5821
5947
|
AND sources.materialization_id = rows.materialization_id
|
|
5822
|
-
WHERE
|
|
5823
|
-
AND sources.status = 'active'`).all(requested, this.projectId);
|
|
5948
|
+
WHERE sources.status = 'active'`).all(requested, this.projectId);
|
|
5824
5949
|
const overrideRows = this.db.query(`WITH requested AS (${sourceRequest})
|
|
5825
|
-
SELECT overrides.* FROM
|
|
5826
|
-
JOIN
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5950
|
+
SELECT overrides.* FROM requested
|
|
5951
|
+
CROSS JOIN ontology_overrides AS overrides
|
|
5952
|
+
ON overrides.project_id = ?
|
|
5953
|
+
AND overrides.entity_kind = 'link'
|
|
5954
|
+
AND overrides.source_type_id = requested.source_type_id
|
|
5955
|
+
AND overrides.source_primary_id = requested.source_primary_id
|
|
5956
|
+
AND overrides.link_id = requested.link_id
|
|
5957
|
+
AND overrides.target_type_id = requested.target_type_id
|
|
5958
|
+
AND overrides.target_primary_id = requested.target_primary_id`).all(requested, this.projectId);
|
|
5830
5959
|
const effective = new Map(effectiveRows.map((row) => [linkRefKey(linkRefFromColumns(row)), row]));
|
|
5831
5960
|
const sources = activeSourceMap(sourceRows);
|
|
5832
5961
|
const overrides = new Map(overrideRows.map((row) => [linkRefKey(linkRefFromOverrideColumns(row)), storedLinkOverride(row)]));
|
|
@@ -5860,9 +5989,13 @@ class SqliteMaterializationStateReader {
|
|
|
5860
5989
|
json_extract(value, '$.at') AS at
|
|
5861
5990
|
FROM json_each(?)
|
|
5862
5991
|
)
|
|
5863
|
-
SELECT timeseries.* FROM
|
|
5864
|
-
JOIN
|
|
5865
|
-
|
|
5992
|
+
SELECT timeseries.* FROM requested
|
|
5993
|
+
CROSS JOIN timeseries
|
|
5994
|
+
ON timeseries.project_id = ?
|
|
5995
|
+
AND timeseries.object_type_id = requested.object_type_id
|
|
5996
|
+
AND timeseries.object_id = requested.object_id
|
|
5997
|
+
AND timeseries.property_id = requested.property_id
|
|
5998
|
+
AND timeseries.at = requested.at`).all(requested, this.projectId);
|
|
5866
5999
|
const found = new Map(rows.map((row) => {
|
|
5867
6000
|
const point = storedPoint(row);
|
|
5868
6001
|
return [telemetryPointSortKey(point.series, point.at), point];
|
|
@@ -5895,9 +6028,12 @@ class SqliteMaterializationStateReader {
|
|
|
5895
6028
|
FROM json_each(?)
|
|
5896
6029
|
)
|
|
5897
6030
|
SELECT requested.scope_sort_key, links.*
|
|
5898
|
-
FROM
|
|
5899
|
-
JOIN
|
|
5900
|
-
|
|
6031
|
+
FROM requested
|
|
6032
|
+
CROSS JOIN links
|
|
6033
|
+
ON links.project_id = ?
|
|
6034
|
+
AND links.source_type_id = requested.source_type_id
|
|
6035
|
+
AND links.source_id = requested.source_id
|
|
6036
|
+
AND links.link_id = requested.link_id
|
|
5901
6037
|
ORDER BY requested.scope_sort_key, ${linkSortExpression("links")}
|
|
5902
6038
|
`).iterate(canonicalJson(requested), this.projectId);
|
|
5903
6039
|
for (const row of rows) {
|
|
@@ -6041,17 +6177,23 @@ class SqliteMaterializationStateReader {
|
|
|
6041
6177
|
if (materializationIds.length === 0 || refs.length === 0) {
|
|
6042
6178
|
return { owned: new Set, byMaterialization: new Map };
|
|
6043
6179
|
}
|
|
6044
|
-
const
|
|
6180
|
+
const requestedEntities = canonicalJson(refs.map((ref) => ({ entityKind: ref.kind, entityKey: projectionEntityKey(ref) })));
|
|
6045
6181
|
const requestedMaterializations = canonicalJson([...new Set(materializationIds)]);
|
|
6046
6182
|
const rows = this.db.query(`WITH requested_entities AS (
|
|
6047
|
-
SELECT value AS
|
|
6183
|
+
SELECT DISTINCT json_extract(value, '$.entityKind') AS entity_kind,
|
|
6184
|
+
json_extract(value, '$.entityKey') AS entity_key
|
|
6185
|
+
FROM json_each(?)
|
|
6048
6186
|
), requested_materializations AS (
|
|
6049
6187
|
SELECT value AS materialization_id FROM json_each(?)
|
|
6050
6188
|
)
|
|
6051
|
-
SELECT rows.* FROM
|
|
6052
|
-
JOIN requested_entities
|
|
6053
|
-
JOIN
|
|
6054
|
-
|
|
6189
|
+
SELECT rows.* FROM requested_materializations
|
|
6190
|
+
CROSS JOIN requested_entities
|
|
6191
|
+
CROSS JOIN ontology_source_rows AS rows
|
|
6192
|
+
ON rows.project_id = ?
|
|
6193
|
+
AND rows.source_id = ?
|
|
6194
|
+
AND rows.materialization_id = requested_materializations.materialization_id
|
|
6195
|
+
AND rows.entity_kind = requested_entities.entity_kind
|
|
6196
|
+
AND rows.entity_key = requested_entities.entity_key`).all(requestedEntities, requestedMaterializations, this.projectId, sourceId);
|
|
6055
6197
|
const owned = new Set;
|
|
6056
6198
|
const byMaterialization = new Map;
|
|
6057
6199
|
for (const row of rows) {
|
|
@@ -8670,8 +8812,8 @@ class SqliteSyncRunStorage {
|
|
|
8670
8812
|
if (input.output && input.output.datasetId !== existing.dataset_id) {
|
|
8671
8813
|
throw new SyncRunError(`[SixbSqlite] Sync run '${input.id}' output dataset '${input.output.datasetId}' does not match '${existing.dataset_id}'.`);
|
|
8672
8814
|
}
|
|
8673
|
-
if (!input.output &&
|
|
8674
|
-
throw new SyncRunError(`[SixbSqlite] Sync run '${input.id}' may omit its output only for an
|
|
8815
|
+
if (!input.output && input.rowsRead !== 0 && existing.mode !== "merge") {
|
|
8816
|
+
throw new SyncRunError(`[SixbSqlite] Sync run '${input.id}' may omit its output with rows read only for an initial merge no-op.`);
|
|
8675
8817
|
}
|
|
8676
8818
|
}
|
|
8677
8819
|
this.db.query(`
|
|
@@ -9541,10 +9683,12 @@ class SqliteWorkflowRunStorage {
|
|
|
9541
9683
|
SET
|
|
9542
9684
|
status = ?,
|
|
9543
9685
|
finished_at = ?,
|
|
9544
|
-
|
|
9545
|
-
|
|
9686
|
+
output = ?,
|
|
9687
|
+
error = ?,
|
|
9688
|
+
execution_token = NULL,
|
|
9689
|
+
execution_queue_lease_expires_at = NULL
|
|
9546
9690
|
WHERE project_id = ? AND id = ?
|
|
9547
|
-
`).run(input.status, (input.finishedAt ?? new Date).toISOString(), input.status === "succeeded" ? null : input.error ?? null, input.projectId, input.id);
|
|
9691
|
+
`).run(input.status, (input.finishedAt ?? new Date).toISOString(), input.status === "succeeded" ? serializeRecord2(input.output) : null, input.status === "succeeded" ? null : input.error ?? null, input.projectId, input.id);
|
|
9548
9692
|
const updated = this.db.query("SELECT * FROM workflow_runs WHERE project_id = ? AND id = ?").get(input.projectId, input.id);
|
|
9549
9693
|
return rowToWorkflowRunRecord(updated);
|
|
9550
9694
|
})();
|
|
@@ -9954,6 +10098,7 @@ function rowToWorkflowRunRecord(row) {
|
|
|
9954
10098
|
workflowId: row.workflow_id,
|
|
9955
10099
|
status: row.status,
|
|
9956
10100
|
input: parseRecord2(row.input),
|
|
10101
|
+
output: row.output ? parseRecord2(row.output) : undefined,
|
|
9957
10102
|
queuedAt: row.queued_at ? new Date(row.queued_at) : undefined,
|
|
9958
10103
|
startedAt: new Date(row.started_at),
|
|
9959
10104
|
finishedAt: row.finished_at ? new Date(row.finished_at) : undefined,
|
|
@@ -10201,4 +10346,4 @@ export {
|
|
|
10201
10346
|
SqliteStorage
|
|
10202
10347
|
};
|
|
10203
10348
|
|
|
10204
|
-
//# debugId=
|
|
10349
|
+
//# debugId=531479881454EA0264756E2164756E21
|