@sixb/sqlite 0.1.0 → 0.1.2
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/README.md +18 -13
- package/dist/action-run-storage.d.ts +5 -2
- package/dist/action-run-storage.d.ts.map +1 -1
- package/dist/agents/agent-storage.d.ts +4 -2
- package/dist/agents/agent-storage.d.ts.map +1 -1
- package/dist/agents/rows.d.ts +3 -10
- package/dist/agents/rows.d.ts.map +1 -1
- package/dist/agents/runs.d.ts +3 -2
- package/dist/agents/runs.d.ts.map +1 -1
- package/dist/ai-usage-storage.d.ts +22 -0
- package/dist/ai-usage-storage.d.ts.map +1 -0
- package/dist/auth-storage/service-accounts.d.ts.map +1 -1
- package/dist/auth-storage/shared.d.ts +1 -10
- package/dist/auth-storage/shared.d.ts.map +1 -1
- package/dist/connector-connection-storage.d.ts +9 -0
- package/dist/connector-connection-storage.d.ts.map +1 -0
- package/dist/execution-storage.d.ts +14 -0
- package/dist/execution-storage.d.ts.map +1 -0
- package/dist/index.d.ts +13 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4114 -1149
- package/dist/index.js.map +30 -27
- package/dist/latest-run-query.d.ts.map +1 -1
- package/dist/migrations.d.ts +0 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/ontology-storage/materialization-session.d.ts +50 -8
- package/dist/ontology-storage/materialization-session.d.ts.map +1 -1
- package/dist/ontology-storage/materialization-state.d.ts +4 -5
- package/dist/ontology-storage/materialization-state.d.ts.map +1 -1
- package/dist/ontology-storage/materialization-writer.d.ts.map +1 -1
- package/dist/ontology-storage/materializations.d.ts +0 -2
- package/dist/ontology-storage/materializations.d.ts.map +1 -1
- package/dist/ontology-storage/outbox.d.ts.map +1 -1
- package/dist/ontology-storage/shared.d.ts +3 -3
- package/dist/ontology-storage/shared.d.ts.map +1 -1
- package/dist/ontology-storage/sources.d.ts.map +1 -1
- package/dist/pipeline-run-storage.d.ts +7 -2
- package/dist/pipeline-run-storage.d.ts.map +1 -1
- package/dist/projection-run-storage.d.ts +9 -2
- package/dist/projection-run-storage.d.ts.map +1 -1
- package/dist/run-list-query.d.ts +1 -1
- package/dist/run-list-query.d.ts.map +1 -1
- package/dist/sync-run-storage.d.ts +7 -2
- package/dist/sync-run-storage.d.ts.map +1 -1
- package/dist/testing.d.ts +6 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/transactions.d.ts +3 -0
- package/dist/transactions.d.ts.map +1 -1
- package/dist/webhook-run-storage.d.ts +9 -2
- package/dist/webhook-run-storage.d.ts.map +1 -1
- package/dist/workflow-run-storage.d.ts +7 -3
- package/dist/workflow-run-storage.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/action-run-storage.ts +51 -74
- package/src/agents/agent-storage.ts +5 -3
- package/src/agents/rows.ts +8 -40
- package/src/agents/runs.ts +27 -21
- package/src/ai-usage-storage.ts +324 -0
- package/src/auth-storage/service-accounts.ts +14 -21
- package/src/auth-storage/shared.ts +0 -22
- package/src/connector-connection-storage.ts +784 -0
- package/src/execution-storage.ts +158 -0
- package/src/index.ts +63 -22
- package/src/latest-run-query.ts +7 -1
- package/src/migrations/002-workflow-run-output.sql +27 -0
- package/src/migrations/003-merge-sync-runs.sql +71 -0
- package/src/migrations/004-executions.sql +142 -0
- package/src/migrations/005-workflow-executions.sql +7 -0
- package/src/migrations/006-narrow-ontology-source-root-index.sql +4 -0
- package/src/migrations/007-split-overrides.sql +154 -0
- package/src/migrations/008-action-executions.sql +4 -0
- package/src/migrations/009-agent-executions.sql +115 -0
- package/src/migrations/010-ai-usage-accounting-foundation.sql +74 -0
- package/src/migrations/011-sync-failure-record.sql +22 -0
- package/src/migrations/012-pipeline-failure-record.sql +45 -0
- package/src/migrations/013-workflow-failure-record.sql +45 -0
- package/src/migrations/014-agent-failure-record.sql +59 -0
- package/src/migrations/015-projection-failure-record.sql +20 -0
- package/src/migrations/016-webhook-run-failure-record.sql +19 -0
- package/src/migrations/017-action-failure-record.sql +65 -0
- package/src/migrations/018-ontology-outbox-failure-record.sql +80 -0
- package/src/migrations/019-webhook-delivery-failure-record.sql +62 -0
- package/src/migrations/020-drop-run-usage-projections.sql +7 -0
- package/src/migrations/021-sync-pipeline-executions.sql +101 -0
- package/src/migrations/022-projection-executions.sql +244 -0
- package/src/migrations/023-webhook-executions.sql +51 -0
- package/src/migrations/024-ontology-commit-executions.sql +58 -0
- package/src/migrations/025-connector-connections.sql +257 -0
- package/src/migrations.ts +126 -5
- package/src/ontology-storage/materialization-session.ts +317 -143
- package/src/ontology-storage/materialization-state.ts +398 -150
- package/src/ontology-storage/materialization-writer.ts +142 -67
- package/src/ontology-storage/materializations.ts +67 -141
- package/src/ontology-storage/outbox.ts +10 -3
- package/src/ontology-storage/shared.ts +10 -4
- package/src/ontology-storage/sources.ts +4 -1
- package/src/pipeline-run-storage.ts +128 -43
- package/src/projection-run-storage.ts +209 -97
- package/src/run-list-query.ts +9 -4
- package/src/sync-run-storage.ts +120 -34
- package/src/testing.ts +20 -0
- package/src/transactions.ts +10 -3
- package/src/webhook-run-storage.ts +118 -74
- package/src/workflow-run-storage.ts +124 -133
- package/dist/validation.d.ts +0 -5
- package/dist/validation.d.ts.map +0 -1
- package/dist/webhook-delivery-storage.d.ts +0 -27
- package/dist/webhook-delivery-storage.d.ts.map +0 -1
- package/src/validation.ts +0 -30
- package/src/webhook-delivery-storage.ts +0 -272
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite"
|
|
2
|
+
import {
|
|
3
|
+
type ExecutionStorageRow,
|
|
4
|
+
executionRecordFromStorageRow,
|
|
5
|
+
executionRecordToStorageRow,
|
|
6
|
+
normalizeExecutionRecord,
|
|
7
|
+
validateExecutionRecordReferences,
|
|
8
|
+
} from "@sixb/core/internal/execution-storage"
|
|
9
|
+
import type { CreateExecutionInput, ExecutionRecord, ExecutionStorage } from "@sixb/core/storage"
|
|
10
|
+
import { ExecutionStorageError } from "@sixb/core/storage"
|
|
11
|
+
import type { SqliteAuthStorage } from "./auth-storage"
|
|
12
|
+
|
|
13
|
+
export class SqliteExecutionStorage implements ExecutionStorage {
|
|
14
|
+
constructor(
|
|
15
|
+
private readonly db: Database,
|
|
16
|
+
private readonly auth: SqliteAuthStorage
|
|
17
|
+
) {}
|
|
18
|
+
|
|
19
|
+
async create(input: CreateExecutionInput): Promise<ExecutionRecord> {
|
|
20
|
+
const record = normalizeExecutionRecord(input)
|
|
21
|
+
await validateExecutionRecordReferences(record, {
|
|
22
|
+
auth: this.auth,
|
|
23
|
+
getExecution: (params) => this.getById(params),
|
|
24
|
+
})
|
|
25
|
+
const row = executionRecordToStorageRow(record)
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
this.db
|
|
29
|
+
.query(
|
|
30
|
+
`
|
|
31
|
+
INSERT INTO executions (
|
|
32
|
+
project_id,
|
|
33
|
+
id,
|
|
34
|
+
executor_kind,
|
|
35
|
+
executor_id,
|
|
36
|
+
source_kind,
|
|
37
|
+
source_id,
|
|
38
|
+
requested_by_user_id,
|
|
39
|
+
requested_by_service_account_id,
|
|
40
|
+
correlation_id,
|
|
41
|
+
parent_execution_id,
|
|
42
|
+
authority_kind,
|
|
43
|
+
authority_user_id,
|
|
44
|
+
authority_service_account_id,
|
|
45
|
+
authority_session_id,
|
|
46
|
+
authority_access_token_id,
|
|
47
|
+
authority_primitive_kind,
|
|
48
|
+
authority_primitive_id,
|
|
49
|
+
authority_kernel_operation,
|
|
50
|
+
created_at
|
|
51
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
52
|
+
`
|
|
53
|
+
)
|
|
54
|
+
.run(
|
|
55
|
+
row.projectId,
|
|
56
|
+
row.id,
|
|
57
|
+
row.executorKind,
|
|
58
|
+
row.executorId,
|
|
59
|
+
row.sourceKind,
|
|
60
|
+
row.sourceId,
|
|
61
|
+
row.requestedByUserId,
|
|
62
|
+
row.requestedByServiceAccountId,
|
|
63
|
+
row.correlationId,
|
|
64
|
+
row.parentExecutionId,
|
|
65
|
+
row.authorityKind,
|
|
66
|
+
row.authorityUserId,
|
|
67
|
+
row.authorityServiceAccountId,
|
|
68
|
+
row.authoritySessionId,
|
|
69
|
+
row.authorityAccessTokenId,
|
|
70
|
+
row.authorityPrimitiveKind,
|
|
71
|
+
row.authorityPrimitiveId,
|
|
72
|
+
row.authorityKernelOperation,
|
|
73
|
+
row.createdAt.toISOString()
|
|
74
|
+
)
|
|
75
|
+
} catch (error) {
|
|
76
|
+
if (isDuplicateExecutionError(error)) {
|
|
77
|
+
throw new ExecutionStorageError(
|
|
78
|
+
"duplicate_execution",
|
|
79
|
+
`[SixbSqlite] Execution '${record.id}' already exists in project '${record.projectId}'.`,
|
|
80
|
+
{ cause: error }
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
throw error
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return executionRecordFromStorageRow(row)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async getById(params: {
|
|
90
|
+
readonly projectId: string
|
|
91
|
+
readonly id: string
|
|
92
|
+
}): Promise<ExecutionRecord | null> {
|
|
93
|
+
const row = this.db
|
|
94
|
+
.query(
|
|
95
|
+
`
|
|
96
|
+
SELECT *
|
|
97
|
+
FROM executions
|
|
98
|
+
WHERE project_id = ? AND id = ?
|
|
99
|
+
`
|
|
100
|
+
)
|
|
101
|
+
.get(params.projectId, params.id) as SqliteExecutionRow | null
|
|
102
|
+
|
|
103
|
+
return row ? executionRecordFromStorageRow(toStorageRow(row)) : null
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function toStorageRow(row: SqliteExecutionRow): ExecutionStorageRow {
|
|
108
|
+
return {
|
|
109
|
+
projectId: row.project_id,
|
|
110
|
+
id: row.id,
|
|
111
|
+
executorKind: row.executor_kind,
|
|
112
|
+
executorId: row.executor_id,
|
|
113
|
+
sourceKind: row.source_kind,
|
|
114
|
+
sourceId: row.source_id,
|
|
115
|
+
requestedByUserId: row.requested_by_user_id,
|
|
116
|
+
requestedByServiceAccountId: row.requested_by_service_account_id,
|
|
117
|
+
correlationId: row.correlation_id,
|
|
118
|
+
parentExecutionId: row.parent_execution_id,
|
|
119
|
+
authorityKind: row.authority_kind,
|
|
120
|
+
authorityUserId: row.authority_user_id,
|
|
121
|
+
authorityServiceAccountId: row.authority_service_account_id,
|
|
122
|
+
authoritySessionId: row.authority_session_id,
|
|
123
|
+
authorityAccessTokenId: row.authority_access_token_id,
|
|
124
|
+
authorityPrimitiveKind: row.authority_primitive_kind,
|
|
125
|
+
authorityPrimitiveId: row.authority_primitive_id,
|
|
126
|
+
authorityKernelOperation: row.authority_kernel_operation,
|
|
127
|
+
createdAt: new Date(row.created_at),
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function isDuplicateExecutionError(error: unknown): boolean {
|
|
132
|
+
return (
|
|
133
|
+
error instanceof Error &&
|
|
134
|
+
error.message.includes("UNIQUE constraint failed: executions.project_id, executions.id")
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
interface SqliteExecutionRow {
|
|
139
|
+
readonly project_id: string
|
|
140
|
+
readonly id: string
|
|
141
|
+
readonly executor_kind: ExecutionStorageRow["executorKind"]
|
|
142
|
+
readonly executor_id: string
|
|
143
|
+
readonly source_kind: ExecutionStorageRow["sourceKind"]
|
|
144
|
+
readonly source_id: string
|
|
145
|
+
readonly requested_by_user_id: string | null
|
|
146
|
+
readonly requested_by_service_account_id: string | null
|
|
147
|
+
readonly correlation_id: string
|
|
148
|
+
readonly parent_execution_id: string | null
|
|
149
|
+
readonly authority_kind: ExecutionStorageRow["authorityKind"]
|
|
150
|
+
readonly authority_user_id: string | null
|
|
151
|
+
readonly authority_service_account_id: string | null
|
|
152
|
+
readonly authority_session_id: string | null
|
|
153
|
+
readonly authority_access_token_id: string | null
|
|
154
|
+
readonly authority_primitive_kind: ExecutionStorageRow["authorityPrimitiveKind"]
|
|
155
|
+
readonly authority_primitive_id: string | null
|
|
156
|
+
readonly authority_kernel_operation: ExecutionStorageRow["authorityKernelOperation"]
|
|
157
|
+
readonly created_at: string
|
|
158
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -19,13 +19,17 @@ import {
|
|
|
19
19
|
createWorkflowRunOperationScope,
|
|
20
20
|
} from "@sixb/core/internal/storage-operation-scope"
|
|
21
21
|
import {
|
|
22
|
+
type AiUsageStorage,
|
|
22
23
|
createTransactionStorageProxy,
|
|
23
24
|
StorageTransactionError,
|
|
24
25
|
throwNestedStorageTransaction,
|
|
25
26
|
} from "@sixb/core/storage"
|
|
26
27
|
import { SqliteActionRunStorage } from "./action-run-storage"
|
|
27
28
|
import { SqliteAgentStorage } from "./agents"
|
|
29
|
+
import { SqliteAiUsageStorage } from "./ai-usage-storage"
|
|
28
30
|
import { SqliteAuthStorage } from "./auth-storage"
|
|
31
|
+
import { SqliteConnectorConnectionStorage } from "./connector-connection-storage"
|
|
32
|
+
import { SqliteExecutionStorage } from "./execution-storage"
|
|
29
33
|
import {
|
|
30
34
|
createSqliteStorageMigrators,
|
|
31
35
|
installFreshSqliteSchema,
|
|
@@ -37,6 +41,7 @@ import { SqlitePipelineRunStorage } from "./pipeline-run-storage"
|
|
|
37
41
|
import { SqliteProjectionRunStorage } from "./projection-run-storage"
|
|
38
42
|
import { SqliteRulesStorage } from "./rules-storage"
|
|
39
43
|
import { SqliteSyncRunStorage } from "./sync-run-storage"
|
|
44
|
+
import { registerSqliteStorageTestingAdapter } from "./testing"
|
|
40
45
|
import { SqliteTimeseriesStorage } from "./timeseries-storage"
|
|
41
46
|
import {
|
|
42
47
|
closeSqliteStoreConnection,
|
|
@@ -44,7 +49,6 @@ import {
|
|
|
44
49
|
runImmediateTransactionAsync,
|
|
45
50
|
type SqliteStoreConnection,
|
|
46
51
|
} from "./transactions"
|
|
47
|
-
import { SqliteWebhookDeliveryStorage } from "./webhook-delivery-storage"
|
|
48
52
|
import { SqliteWebhookRunStorage } from "./webhook-run-storage"
|
|
49
53
|
import { SqliteWorkflowInterventionStorage } from "./workflow-intervention-storage"
|
|
50
54
|
import { SqliteWorkflowRunStorage } from "./workflow-run-storage"
|
|
@@ -57,8 +61,8 @@ export interface SqliteStorageOptions {
|
|
|
57
61
|
/**
|
|
58
62
|
* SQLite storage provider for Sixb.
|
|
59
63
|
*
|
|
60
|
-
* Bundles object, timeseries, auth, sync run, pipeline run, projection run,
|
|
61
|
-
* run, and
|
|
64
|
+
* Bundles object, timeseries, auth, execution, AI usage, sync run, pipeline run, projection run,
|
|
65
|
+
* workflow run, webhook run, and connector connection storage backed by SQLite.
|
|
62
66
|
*
|
|
63
67
|
* Usage:
|
|
64
68
|
* ```ts
|
|
@@ -74,7 +78,9 @@ export class SqliteStorage implements MigrationCapableStorage {
|
|
|
74
78
|
readonly objects: Storage["objects"]
|
|
75
79
|
readonly ontology: SqliteOntologyStorage
|
|
76
80
|
readonly auth: SqliteAuthStorage
|
|
81
|
+
readonly executions: SqliteExecutionStorage
|
|
77
82
|
readonly agents: SqliteAgentStorage
|
|
83
|
+
readonly aiUsage: AiUsageStorage
|
|
78
84
|
readonly actionRuns: SqliteActionRunStorage
|
|
79
85
|
readonly pipelineRuns: SqlitePipelineRunStorage
|
|
80
86
|
readonly syncRuns: SqliteSyncRunStorage
|
|
@@ -82,18 +88,25 @@ export class SqliteStorage implements MigrationCapableStorage {
|
|
|
82
88
|
readonly workflowRuns: SqliteWorkflowRunStorage
|
|
83
89
|
readonly workflowInterventions: SqliteWorkflowInterventionStorage
|
|
84
90
|
readonly timeseries: Storage["timeseries"]
|
|
85
|
-
readonly webhookDeliveries: SqliteWebhookDeliveryStorage
|
|
86
91
|
readonly webhookRuns: SqliteWebhookRunStorage
|
|
87
92
|
readonly rules: SqliteRulesStorage
|
|
93
|
+
readonly connectorConnections: SqliteConnectorConnectionStorage
|
|
88
94
|
readonly migrators: readonly StorageMigrator[]
|
|
89
95
|
|
|
90
96
|
private readonly connection: SqliteStoreConnection
|
|
97
|
+
private readonly readConnection: SqliteStoreConnection
|
|
91
98
|
private readonly transactionScope = new AsyncLocalStorage<{ active: boolean }>()
|
|
92
99
|
private transactionTail: Promise<void> = Promise.resolve()
|
|
93
100
|
|
|
94
101
|
constructor(options: SqliteStorageOptions = {}) {
|
|
95
102
|
const path = options.path ? sqliteStoragePath(options.path) : undefined
|
|
96
103
|
this.connection = openSqliteStoreConnection({ path })
|
|
104
|
+
if (path) {
|
|
105
|
+
this.connection.db.run("PRAGMA journal_mode = WAL")
|
|
106
|
+
this.readConnection = openSqliteStoreConnection({ path, readonly: true })
|
|
107
|
+
} else {
|
|
108
|
+
this.readConnection = this.connection
|
|
109
|
+
}
|
|
97
110
|
|
|
98
111
|
if (this.connection.installFreshSchema) {
|
|
99
112
|
installFreshSqliteSchema(this.connection.db)
|
|
@@ -112,35 +125,56 @@ export class SqliteStorage implements MigrationCapableStorage {
|
|
|
112
125
|
(run) => this.runRootOntologyOperation(run),
|
|
113
126
|
assertRootOperationAvailable
|
|
114
127
|
)
|
|
115
|
-
|
|
128
|
+
const readScope = path
|
|
129
|
+
? createStorageOperationScope(async (run) => {
|
|
130
|
+
this.assertRootOperationAvailable()
|
|
131
|
+
return run()
|
|
132
|
+
}, assertRootOperationAvailable)
|
|
133
|
+
: scope
|
|
134
|
+
const readObjects = path
|
|
135
|
+
? new SqliteObjectStorage({ connection: this.readConnection })
|
|
136
|
+
: stores.objects
|
|
137
|
+
const readTimeseries = path
|
|
138
|
+
? new SqliteTimeseriesStorage({ connection: this.readConnection })
|
|
139
|
+
: stores.timeseries
|
|
140
|
+
this.objects = createOperationScopedFacade(readObjects, readScope)
|
|
116
141
|
this.ontology = createOntologyOperationScope(stores.ontology, ontologyScope)
|
|
117
142
|
this.auth = createAuthOperationScope(stores.auth, scope)
|
|
143
|
+
this.executions = createOperationScopedFacade(stores.executions, scope)
|
|
118
144
|
this.agents = createAgentOperationScope(stores.agents, scope)
|
|
145
|
+
this.aiUsage = createOperationScopedFacade(stores.aiUsage, scope)
|
|
119
146
|
this.actionRuns = createOperationScopedFacade(stores.actionRuns, scope)
|
|
120
147
|
this.pipelineRuns = createOperationScopedFacade(stores.pipelineRuns, scope)
|
|
121
|
-
this.timeseries = createOperationScopedFacade(
|
|
148
|
+
this.timeseries = createOperationScopedFacade(readTimeseries, readScope)
|
|
122
149
|
this.syncRuns = createOperationScopedFacade(stores.syncRuns, scope)
|
|
123
150
|
this.projectionRuns = createOperationScopedFacade(stores.projectionRuns, scope)
|
|
124
151
|
this.workflowRuns = createWorkflowRunOperationScope(stores.workflowRuns, scope)
|
|
125
152
|
this.workflowInterventions = createOperationScopedFacade(stores.workflowInterventions, scope)
|
|
126
|
-
this.webhookDeliveries = createOperationScopedFacade(stores.webhookDeliveries, scope)
|
|
127
153
|
this.webhookRuns = createOperationScopedFacade(stores.webhookRuns, scope)
|
|
128
154
|
this.rules = createOperationScopedFacade(stores.rules, scope)
|
|
155
|
+
this.connectorConnections = createOperationScopedFacade(stores.connectorConnections, scope)
|
|
129
156
|
this.migrators = options.path ? createSqliteStorageMigrators(options.path) : []
|
|
157
|
+
registerSqliteStorageTestingAdapter(this, (durationMs) =>
|
|
158
|
+
stores.connectorConnections.advanceTimeForTesting(durationMs)
|
|
159
|
+
)
|
|
130
160
|
}
|
|
131
161
|
|
|
132
162
|
async ping(): Promise<void> {
|
|
163
|
+
this.assertRootOperationAvailable()
|
|
164
|
+
if (this.readConnection !== this.connection) {
|
|
165
|
+
this.readConnection.db.query("SELECT 1").get()
|
|
166
|
+
return
|
|
167
|
+
}
|
|
133
168
|
await this.runRootStorageOperation(() => {
|
|
134
169
|
this.connection.db.query("SELECT 1").get()
|
|
135
170
|
})
|
|
136
171
|
}
|
|
137
172
|
|
|
138
173
|
/**
|
|
139
|
-
* The `isolation` option is intentionally ignored. SQLite runs every transaction through
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
* `isolation: "serializable"` translates to a real isolation level.
|
|
174
|
+
* The `isolation` option is intentionally ignored. SQLite runs every write transaction through
|
|
175
|
+
* one connection serialized by {@link withTransactionLock} and a `BEGIN IMMEDIATE`, so there is no
|
|
176
|
+
* concurrent writer to isolate against. File-backed object and timeseries reads use a separate WAL
|
|
177
|
+
* snapshot connection; Postgres is where `isolation: "serializable"` maps to a real isolation level.
|
|
144
178
|
*/
|
|
145
179
|
async transaction<T>(
|
|
146
180
|
run: (tx: Storage) => Promise<T> | T,
|
|
@@ -183,6 +217,7 @@ export class SqliteStorage implements MigrationCapableStorage {
|
|
|
183
217
|
}
|
|
184
218
|
|
|
185
219
|
close(): void {
|
|
220
|
+
if (this.readConnection !== this.connection) closeSqliteStoreConnection(this.readConnection)
|
|
186
221
|
closeSqliteStoreConnection(this.connection)
|
|
187
222
|
}
|
|
188
223
|
|
|
@@ -250,6 +285,8 @@ function createSqliteStores(
|
|
|
250
285
|
readonly transactionContext: SqliteOntologyTransactionContext | null
|
|
251
286
|
}
|
|
252
287
|
): SqliteStoreSet {
|
|
288
|
+
const auth = new SqliteAuthStorage({ connection })
|
|
289
|
+
const executions = new SqliteExecutionStorage(connection.db, auth)
|
|
253
290
|
return {
|
|
254
291
|
objects: new SqliteObjectStorage({ connection }),
|
|
255
292
|
ontology: new SqliteOntologyStorage({
|
|
@@ -257,18 +294,20 @@ function createSqliteStores(
|
|
|
257
294
|
runRootOperation: options.runOntologyOperation,
|
|
258
295
|
transactionContext: options.transactionContext,
|
|
259
296
|
}),
|
|
260
|
-
auth
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
297
|
+
auth,
|
|
298
|
+
executions,
|
|
299
|
+
agents: new SqliteAgentStorage({ connection, executions }),
|
|
300
|
+
aiUsage: new SqliteAiUsageStorage({ connection }),
|
|
301
|
+
actionRuns: new SqliteActionRunStorage({ connection, executions }),
|
|
302
|
+
pipelineRuns: new SqlitePipelineRunStorage({ connection, executions }),
|
|
264
303
|
timeseries: new SqliteTimeseriesStorage({ connection }),
|
|
265
|
-
syncRuns: new SqliteSyncRunStorage({ connection }),
|
|
266
|
-
projectionRuns: new SqliteProjectionRunStorage({ connection }),
|
|
267
|
-
workflowRuns: new SqliteWorkflowRunStorage({ connection }),
|
|
304
|
+
syncRuns: new SqliteSyncRunStorage({ connection, executions }),
|
|
305
|
+
projectionRuns: new SqliteProjectionRunStorage({ connection, executions }),
|
|
306
|
+
workflowRuns: new SqliteWorkflowRunStorage({ connection, executions }),
|
|
268
307
|
workflowInterventions: new SqliteWorkflowInterventionStorage({ connection }),
|
|
269
|
-
|
|
270
|
-
webhookRuns: new SqliteWebhookRunStorage({ connection }),
|
|
308
|
+
webhookRuns: new SqliteWebhookRunStorage({ connection, executions }),
|
|
271
309
|
rules: new SqliteRulesStorage({ connection }),
|
|
310
|
+
connectorConnections: new SqliteConnectorConnectionStorage(connection),
|
|
272
311
|
}
|
|
273
312
|
}
|
|
274
313
|
|
|
@@ -276,7 +315,9 @@ interface SqliteStoreSet {
|
|
|
276
315
|
readonly objects: SqliteObjectStorage
|
|
277
316
|
readonly ontology: SqliteOntologyStorage
|
|
278
317
|
readonly auth: SqliteAuthStorage
|
|
318
|
+
readonly executions: SqliteExecutionStorage
|
|
279
319
|
readonly agents: SqliteAgentStorage
|
|
320
|
+
readonly aiUsage: SqliteAiUsageStorage
|
|
280
321
|
readonly actionRuns: SqliteActionRunStorage
|
|
281
322
|
readonly pipelineRuns: SqlitePipelineRunStorage
|
|
282
323
|
readonly syncRuns: SqliteSyncRunStorage
|
|
@@ -284,9 +325,9 @@ interface SqliteStoreSet {
|
|
|
284
325
|
readonly workflowRuns: SqliteWorkflowRunStorage
|
|
285
326
|
readonly workflowInterventions: SqliteWorkflowInterventionStorage
|
|
286
327
|
readonly timeseries: SqliteTimeseriesStorage
|
|
287
|
-
readonly webhookDeliveries: SqliteWebhookDeliveryStorage
|
|
288
328
|
readonly webhookRuns: SqliteWebhookRunStorage
|
|
289
329
|
readonly rules: SqliteRulesStorage
|
|
330
|
+
readonly connectorConnections: SqliteConnectorConnectionStorage
|
|
290
331
|
}
|
|
291
332
|
|
|
292
333
|
export { migrateSqliteStorage } from "./migrations"
|
package/src/latest-run-query.ts
CHANGED
|
@@ -21,6 +21,12 @@ export function queryLatestRunsByOwnerId<TRow>(
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
const placeholders = ownerIds.map(() => "?").join(", ")
|
|
24
|
+
const orderColumn =
|
|
25
|
+
input.tableName === "sync_runs" ||
|
|
26
|
+
input.tableName === "pipeline_runs" ||
|
|
27
|
+
input.tableName === "projection_runs"
|
|
28
|
+
? "COALESCE(started_at, queued_at)"
|
|
29
|
+
: "started_at"
|
|
24
30
|
const rows = input.db
|
|
25
31
|
.query(
|
|
26
32
|
`
|
|
@@ -30,7 +36,7 @@ export function queryLatestRunsByOwnerId<TRow>(
|
|
|
30
36
|
*,
|
|
31
37
|
ROW_NUMBER() OVER (
|
|
32
38
|
PARTITION BY ${input.ownerColumn}
|
|
33
|
-
ORDER BY
|
|
39
|
+
ORDER BY ${orderColumn} DESC, id DESC
|
|
34
40
|
) AS sixb_latest_rank
|
|
35
41
|
FROM ${input.tableName}
|
|
36
42
|
WHERE project_id = ? AND ${input.ownerColumn} IN (${placeholders})
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
ALTER TABLE workflow_runs ADD COLUMN output TEXT;
|
|
2
|
+
|
|
3
|
+
UPDATE workflow_runs AS run
|
|
4
|
+
SET output = CASE
|
|
5
|
+
WHEN EXISTS (
|
|
6
|
+
SELECT 1
|
|
7
|
+
FROM workflow_node_runs AS node
|
|
8
|
+
WHERE node.project_id = run.project_id
|
|
9
|
+
AND node.workflow_run_id = run.id
|
|
10
|
+
AND node.status = 'succeeded'
|
|
11
|
+
AND node.node_type <> 'action'
|
|
12
|
+
) THEN COALESCE(
|
|
13
|
+
(
|
|
14
|
+
SELECT node.output
|
|
15
|
+
FROM workflow_node_runs AS node
|
|
16
|
+
WHERE node.project_id = run.project_id
|
|
17
|
+
AND node.workflow_run_id = run.id
|
|
18
|
+
AND node.status = 'succeeded'
|
|
19
|
+
AND node.node_type <> 'action'
|
|
20
|
+
ORDER BY node.node_index DESC, node.id DESC
|
|
21
|
+
LIMIT 1
|
|
22
|
+
),
|
|
23
|
+
'{}'
|
|
24
|
+
)
|
|
25
|
+
ELSE run.input
|
|
26
|
+
END
|
|
27
|
+
WHERE run.status = 'succeeded';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
DROP INDEX idx_sync_runs_project_started;
|
|
2
|
+
DROP INDEX idx_sync_runs_project_dataset_started;
|
|
3
|
+
DROP INDEX idx_sync_runs_project_sync_started;
|
|
4
|
+
DROP INDEX idx_sync_runs_project_status_started;
|
|
5
|
+
|
|
6
|
+
ALTER TABLE sync_runs RENAME TO sync_runs_before_merge_mode;
|
|
7
|
+
|
|
8
|
+
CREATE TABLE sync_runs (
|
|
9
|
+
project_id TEXT NOT NULL,
|
|
10
|
+
id TEXT NOT NULL,
|
|
11
|
+
sync_id TEXT NOT NULL,
|
|
12
|
+
dataset_id TEXT NOT NULL,
|
|
13
|
+
mode TEXT NOT NULL CHECK (mode IN ('snapshot', 'append', 'merge')),
|
|
14
|
+
status TEXT NOT NULL CHECK (status IN ('running', 'succeeded', 'failed', 'cancelled')),
|
|
15
|
+
started_at TEXT NOT NULL,
|
|
16
|
+
finished_at TEXT,
|
|
17
|
+
rows_read INTEGER CHECK (rows_read IS NULL OR rows_read >= 0),
|
|
18
|
+
output_version_id TEXT,
|
|
19
|
+
expected_latest_version_id TEXT,
|
|
20
|
+
commit_message TEXT,
|
|
21
|
+
error_name TEXT,
|
|
22
|
+
error_message TEXT,
|
|
23
|
+
checkpoint TEXT,
|
|
24
|
+
PRIMARY KEY (project_id, id)
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
INSERT INTO sync_runs (
|
|
28
|
+
project_id,
|
|
29
|
+
id,
|
|
30
|
+
sync_id,
|
|
31
|
+
dataset_id,
|
|
32
|
+
mode,
|
|
33
|
+
status,
|
|
34
|
+
started_at,
|
|
35
|
+
finished_at,
|
|
36
|
+
rows_read,
|
|
37
|
+
output_version_id,
|
|
38
|
+
expected_latest_version_id,
|
|
39
|
+
commit_message,
|
|
40
|
+
error_name,
|
|
41
|
+
error_message,
|
|
42
|
+
checkpoint
|
|
43
|
+
)
|
|
44
|
+
SELECT
|
|
45
|
+
project_id,
|
|
46
|
+
id,
|
|
47
|
+
sync_id,
|
|
48
|
+
dataset_id,
|
|
49
|
+
mode,
|
|
50
|
+
status,
|
|
51
|
+
started_at,
|
|
52
|
+
finished_at,
|
|
53
|
+
rows_read,
|
|
54
|
+
output_version_id,
|
|
55
|
+
expected_latest_version_id,
|
|
56
|
+
commit_message,
|
|
57
|
+
error_name,
|
|
58
|
+
error_message,
|
|
59
|
+
checkpoint
|
|
60
|
+
FROM sync_runs_before_merge_mode;
|
|
61
|
+
|
|
62
|
+
DROP TABLE sync_runs_before_merge_mode;
|
|
63
|
+
|
|
64
|
+
CREATE INDEX idx_sync_runs_project_started
|
|
65
|
+
ON sync_runs(project_id, started_at DESC);
|
|
66
|
+
CREATE INDEX idx_sync_runs_project_dataset_started
|
|
67
|
+
ON sync_runs(project_id, dataset_id, started_at DESC);
|
|
68
|
+
CREATE INDEX idx_sync_runs_project_sync_started
|
|
69
|
+
ON sync_runs(project_id, sync_id, started_at DESC);
|
|
70
|
+
CREATE INDEX idx_sync_runs_project_status_started
|
|
71
|
+
ON sync_runs(project_id, status, started_at DESC);
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
CREATE TABLE executions (
|
|
2
|
+
project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
|
|
3
|
+
id TEXT NOT NULL CHECK (length(trim(id)) > 0),
|
|
4
|
+
|
|
5
|
+
executor_kind TEXT NOT NULL CHECK (
|
|
6
|
+
executor_kind IN (
|
|
7
|
+
'request', 'action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow',
|
|
8
|
+
'agent', 'kernel'
|
|
9
|
+
)
|
|
10
|
+
),
|
|
11
|
+
executor_id TEXT NOT NULL CHECK (length(trim(executor_id)) > 0),
|
|
12
|
+
source_kind TEXT NOT NULL CHECK (
|
|
13
|
+
source_kind IN ('http', 'webhook', 'schedule', 'event', 'execution')
|
|
14
|
+
),
|
|
15
|
+
source_id TEXT NOT NULL CHECK (length(trim(source_id)) > 0),
|
|
16
|
+
|
|
17
|
+
requested_by_user_id TEXT,
|
|
18
|
+
requested_by_service_account_id TEXT,
|
|
19
|
+
correlation_id TEXT NOT NULL CHECK (length(trim(correlation_id)) > 0),
|
|
20
|
+
parent_execution_id TEXT,
|
|
21
|
+
|
|
22
|
+
authority_kind TEXT NOT NULL CHECK (
|
|
23
|
+
authority_kind IN ('principal', 'trustedPrimitive', 'kernel', 'disabled')
|
|
24
|
+
),
|
|
25
|
+
authority_user_id TEXT,
|
|
26
|
+
authority_service_account_id TEXT,
|
|
27
|
+
authority_session_id TEXT,
|
|
28
|
+
authority_access_token_id TEXT,
|
|
29
|
+
authority_primitive_kind TEXT CHECK (
|
|
30
|
+
authority_primitive_kind IS NULL
|
|
31
|
+
OR authority_primitive_kind IN (
|
|
32
|
+
'action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow'
|
|
33
|
+
)
|
|
34
|
+
),
|
|
35
|
+
authority_primitive_id TEXT,
|
|
36
|
+
authority_kernel_operation TEXT CHECK (
|
|
37
|
+
authority_kernel_operation IS NULL OR authority_kernel_operation = 'ontology.recover'
|
|
38
|
+
),
|
|
39
|
+
|
|
40
|
+
created_at TEXT NOT NULL,
|
|
41
|
+
|
|
42
|
+
PRIMARY KEY (project_id, id),
|
|
43
|
+
FOREIGN KEY (project_id, parent_execution_id)
|
|
44
|
+
REFERENCES executions (project_id, id),
|
|
45
|
+
FOREIGN KEY (project_id, requested_by_user_id)
|
|
46
|
+
REFERENCES auth_users (project_id, id),
|
|
47
|
+
FOREIGN KEY (project_id, requested_by_service_account_id)
|
|
48
|
+
REFERENCES auth_service_accounts (project_id, id),
|
|
49
|
+
FOREIGN KEY (project_id, authority_user_id)
|
|
50
|
+
REFERENCES auth_users (project_id, id),
|
|
51
|
+
FOREIGN KEY (project_id, authority_service_account_id)
|
|
52
|
+
REFERENCES auth_service_accounts (project_id, id),
|
|
53
|
+
FOREIGN KEY (project_id, authority_session_id)
|
|
54
|
+
REFERENCES auth_sessions (project_id, id),
|
|
55
|
+
FOREIGN KEY (project_id, authority_access_token_id)
|
|
56
|
+
REFERENCES auth_access_tokens (project_id, id),
|
|
57
|
+
|
|
58
|
+
CHECK (
|
|
59
|
+
(requested_by_user_id IS NOT NULL) + (requested_by_service_account_id IS NOT NULL) <= 1
|
|
60
|
+
),
|
|
61
|
+
CHECK (
|
|
62
|
+
(source_kind = 'execution' AND parent_execution_id = source_id)
|
|
63
|
+
OR (source_kind <> 'execution' AND parent_execution_id IS NULL)
|
|
64
|
+
),
|
|
65
|
+
CHECK (
|
|
66
|
+
(
|
|
67
|
+
authority_kind = 'principal'
|
|
68
|
+
AND (authority_user_id IS NOT NULL) + (authority_service_account_id IS NOT NULL) = 1
|
|
69
|
+
AND (authority_session_id IS NOT NULL) + (authority_access_token_id IS NOT NULL) <= 1
|
|
70
|
+
AND (authority_session_id IS NULL OR authority_user_id IS NOT NULL)
|
|
71
|
+
AND authority_primitive_kind IS NULL
|
|
72
|
+
AND authority_primitive_id IS NULL
|
|
73
|
+
AND authority_kernel_operation IS NULL
|
|
74
|
+
)
|
|
75
|
+
OR (
|
|
76
|
+
authority_kind = 'trustedPrimitive'
|
|
77
|
+
AND authority_user_id IS NULL
|
|
78
|
+
AND authority_service_account_id IS NULL
|
|
79
|
+
AND authority_session_id IS NULL
|
|
80
|
+
AND authority_access_token_id IS NULL
|
|
81
|
+
AND authority_primitive_kind IS NOT NULL
|
|
82
|
+
AND authority_primitive_id IS NOT NULL
|
|
83
|
+
AND length(trim(authority_primitive_id)) > 0
|
|
84
|
+
AND authority_kernel_operation IS NULL
|
|
85
|
+
)
|
|
86
|
+
OR (
|
|
87
|
+
authority_kind = 'kernel'
|
|
88
|
+
AND authority_user_id IS NULL
|
|
89
|
+
AND authority_service_account_id IS NULL
|
|
90
|
+
AND authority_session_id IS NULL
|
|
91
|
+
AND authority_access_token_id IS NULL
|
|
92
|
+
AND authority_primitive_kind IS NULL
|
|
93
|
+
AND authority_primitive_id IS NULL
|
|
94
|
+
AND authority_kernel_operation IS NOT NULL
|
|
95
|
+
)
|
|
96
|
+
OR (
|
|
97
|
+
authority_kind = 'disabled'
|
|
98
|
+
AND authority_user_id IS NULL
|
|
99
|
+
AND authority_service_account_id IS NULL
|
|
100
|
+
AND authority_session_id IS NULL
|
|
101
|
+
AND authority_access_token_id IS NULL
|
|
102
|
+
AND authority_primitive_kind IS NULL
|
|
103
|
+
AND authority_primitive_id IS NULL
|
|
104
|
+
AND authority_kernel_operation IS NULL
|
|
105
|
+
)
|
|
106
|
+
),
|
|
107
|
+
CHECK (
|
|
108
|
+
(
|
|
109
|
+
executor_kind = 'request'
|
|
110
|
+
AND source_kind = 'http'
|
|
111
|
+
AND executor_id = source_id
|
|
112
|
+
AND (
|
|
113
|
+
(
|
|
114
|
+
authority_kind = 'principal'
|
|
115
|
+
AND requested_by_user_id IS authority_user_id
|
|
116
|
+
AND requested_by_service_account_id IS authority_service_account_id
|
|
117
|
+
)
|
|
118
|
+
OR (
|
|
119
|
+
authority_kind = 'disabled'
|
|
120
|
+
AND requested_by_user_id IS NULL
|
|
121
|
+
AND requested_by_service_account_id IS NULL
|
|
122
|
+
)
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
OR (
|
|
126
|
+
executor_kind IN ('action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow')
|
|
127
|
+
AND authority_kind = 'trustedPrimitive'
|
|
128
|
+
AND executor_kind = authority_primitive_kind
|
|
129
|
+
)
|
|
130
|
+
OR (
|
|
131
|
+
executor_kind = 'agent'
|
|
132
|
+
AND authority_kind = 'principal'
|
|
133
|
+
AND authority_service_account_id IS NOT NULL
|
|
134
|
+
AND authority_session_id IS NULL
|
|
135
|
+
AND authority_access_token_id IS NULL
|
|
136
|
+
)
|
|
137
|
+
OR (
|
|
138
|
+
executor_kind = 'kernel'
|
|
139
|
+
AND authority_kind = 'kernel'
|
|
140
|
+
)
|
|
141
|
+
)
|
|
142
|
+
);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
ALTER TABLE workflow_runs ADD COLUMN execution_id TEXT NOT NULL;
|
|
2
|
+
ALTER TABLE workflow_runs DROP COLUMN source;
|
|
3
|
+
ALTER TABLE workflow_runs DROP COLUMN requested_by_principal_type;
|
|
4
|
+
ALTER TABLE workflow_runs DROP COLUMN requested_by_principal_id;
|
|
5
|
+
|
|
6
|
+
CREATE UNIQUE INDEX idx_workflow_runs_project_execution
|
|
7
|
+
ON workflow_runs(project_id, execution_id);
|