@pikku/kysely 0.13.33 → 0.13.34
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/CHANGELOG.md +15 -0
- package/dist/src/kysely-workflow-service.d.ts +5 -0
- package/dist/src/kysely-workflow-service.js +3 -0
- package/dist/src/schema/agent.schema.js +43 -36
- package/dist/src/schema/analytics.schema.js +17 -17
- package/dist/src/schema/audit.schema.js +22 -22
- package/dist/src/schema/channel.schema.js +13 -10
- package/dist/src/schema/credential.schema.js +6 -6
- package/dist/src/schema/deployment.schema.js +12 -12
- package/dist/src/schema/flag.schema.js +15 -12
- package/dist/src/schema/incoming-webhook.schema.js +7 -7
- package/dist/src/schema/index.js +30 -7
- package/dist/src/schema/lease.schema.js +3 -3
- package/dist/src/schema/pikku-schema.types.d.ts +42 -2
- package/dist/src/schema/pikku-schema.types.js +23 -7
- package/dist/src/schema/scope.schema.js +34 -22
- package/dist/src/schema/secret.schema.js +5 -5
- package/dist/src/schema/session.schema.js +3 -3
- package/dist/src/schema/trigger-source.schema.js +8 -8
- package/dist/src/schema/virtual-user-schedule.schema.js +4 -4
- package/dist/src/schema/virtual-user.schema.js +14 -14
- package/dist/src/schema/webhook.schema.js +17 -17
- package/dist/src/schema/workflow.schema.js +49 -49
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
## 0.13.34
|
|
2
|
+
|
|
3
|
+
### Patch Changes
|
|
4
|
+
|
|
5
|
+
- 80c94f9: MySQL is a third dialect for the `pikku db` commands, beside sqlite and postgres.
|
|
6
|
+
|
|
7
|
+
Set `mysqlUrl` in `createConfig` and `db migrate`, `generate`, `check`, `baseline`, `reset`, `codegen` and the dev seed behave as they do elsewhere, with migrations in `db/mysql/` and the seed in `db/mysql-dev-seed.sql`. MySQL has no embedded engine, so a command that needs a throwaway database creates and drops a `pikku_scratch_<hex>` one on your server — the account needs `CREATE` and `DROP`. DDL is not transactional there, so a migration that fails halfway is replayed from the top. `db.schema` is refused, because a MySQL schema is a database.
|
|
8
|
+
|
|
9
|
+
`@pikku/migrator-sql` gains `@pikku/migrator-sql/mysql`. The runtime schemas in `@pikku/kysely` now compile for MySQL without changing what sqlite and postgres get: keys are `varchar(255)`, free text is `longtext`, literal text defaults are expressions, and foreign keys are table-level constraints, because MySQL parses an inline `REFERENCES` and silently drops it. A foreign key onto a column another source owns takes that column's full type (`varchar(36)`), not the bare `varchar` the introspector reports.
|
|
10
|
+
|
|
11
|
+
An addon that ships `db/mysql` migrations needs `db.mysqlUrl` in its `pikku.config.json` for `pikku all` to publish them. The standalone bundle does not support MySQL yet and refuses a MySQL project by name.
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [149faae]
|
|
14
|
+
- @pikku/core@0.12.136
|
|
15
|
+
|
|
1
16
|
## 0.13.33
|
|
2
17
|
|
|
3
18
|
### Patch Changes
|
|
@@ -23,6 +23,11 @@ export declare class KyselyWorkflowService extends PikkuWorkflowService {
|
|
|
23
23
|
protected listStepStates(runId: string): Promise<Array<StepState & {
|
|
24
24
|
stepName: string;
|
|
25
25
|
}>>;
|
|
26
|
+
getRunSteps(runId: string): Promise<Array<StepState & {
|
|
27
|
+
stepName: string;
|
|
28
|
+
rpcName?: string;
|
|
29
|
+
data?: any;
|
|
30
|
+
}>>;
|
|
26
31
|
getRunHistory(runId: string): Promise<Array<StepState & {
|
|
27
32
|
stepName: string;
|
|
28
33
|
}>>;
|
|
@@ -147,6 +147,9 @@ export class KyselyWorkflowService extends PikkuWorkflowService {
|
|
|
147
147
|
.execute();
|
|
148
148
|
return rows.map((row) => ({ ...toStepState(row), stepName: row.stepName }));
|
|
149
149
|
}
|
|
150
|
+
async getRunSteps(runId) {
|
|
151
|
+
return this.runService.getRunSteps(runId);
|
|
152
|
+
}
|
|
150
153
|
async getRunHistory(runId) {
|
|
151
154
|
return this.runService.getRunHistory(runId);
|
|
152
155
|
}
|
|
@@ -13,89 +13,96 @@ export const agentSchema = {
|
|
|
13
13
|
name: 'agent',
|
|
14
14
|
ownedBy: ['agentStorage', 'agentRunState', 'agentRunService'],
|
|
15
15
|
statements: [
|
|
16
|
-
(db) => db.schema
|
|
16
|
+
(db, _types, ctx) => db.schema
|
|
17
17
|
.createTable('agentThreads')
|
|
18
18
|
.addColumn('id', 'varchar(36)', (col) => col.primaryKey())
|
|
19
19
|
.addColumn('resourceId', 'varchar(255)', (col) => col.notNull())
|
|
20
|
-
.addColumn('title',
|
|
21
|
-
.addColumn('metadata',
|
|
20
|
+
.addColumn('title', ctx.text)
|
|
21
|
+
.addColumn('metadata', ctx.text)
|
|
22
22
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
23
23
|
.addColumn('updatedAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull()),
|
|
24
|
-
(db) => db.schema
|
|
24
|
+
(db, _types, ctx) => db.schema
|
|
25
25
|
.createIndex('idx_agent_threads_resource')
|
|
26
26
|
.on('agentThreads')
|
|
27
27
|
.column('resourceId'),
|
|
28
|
-
(db) => db.schema
|
|
28
|
+
(db, _types, ctx) => db.schema
|
|
29
29
|
.createTable('agentMessage')
|
|
30
30
|
.addColumn('id', 'varchar(36)', (col) => col.primaryKey())
|
|
31
|
-
.addColumn('threadId', 'varchar(36)', (col) => col.notNull()
|
|
31
|
+
.addColumn('threadId', 'varchar(36)', (col) => ctx.references(col.notNull(), 'agentThreads.id'))
|
|
32
32
|
.addColumn('role', 'varchar(50)', (col) => col.notNull())
|
|
33
|
-
.addColumn('content',
|
|
34
|
-
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
35
|
-
|
|
33
|
+
.addColumn('content', ctx.text)
|
|
34
|
+
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
35
|
+
.$call(ctx.foreignKeys('agentMessage', { threadId: 'agentThreads.id' })),
|
|
36
|
+
(db, _types, ctx) => db.schema
|
|
36
37
|
.createIndex('idx_agent_message_thread')
|
|
37
38
|
.on('agentMessage')
|
|
38
39
|
.columns(['threadId', 'createdAt']),
|
|
39
|
-
(db) => db.schema
|
|
40
|
+
(db, _types, ctx) => db.schema
|
|
40
41
|
.createTable('agentToolCall')
|
|
41
42
|
.addColumn('id', 'varchar(36)', (col) => col.primaryKey())
|
|
42
|
-
.addColumn('threadId', 'varchar(36)', (col) => col.notNull()
|
|
43
|
-
.addColumn('messageId', 'varchar(36)', (col) => col.notNull()
|
|
43
|
+
.addColumn('threadId', 'varchar(36)', (col) => ctx.references(col.notNull(), 'agentThreads.id'))
|
|
44
|
+
.addColumn('messageId', 'varchar(36)', (col) => ctx.references(col.notNull(), 'agentMessage.id'))
|
|
44
45
|
.addColumn('runId', 'varchar(36)')
|
|
45
46
|
.addColumn('toolName', 'varchar(255)', (col) => col.notNull())
|
|
46
|
-
.addColumn('args',
|
|
47
|
-
.addColumn('result',
|
|
47
|
+
.addColumn('args', ctx.text, (col) => col.notNull())
|
|
48
|
+
.addColumn('result', ctx.text)
|
|
48
49
|
.addColumn('approvalStatus', 'varchar(50)')
|
|
49
50
|
.addColumn('approvalType', 'varchar(50)')
|
|
50
51
|
.addColumn('agentRunId', 'varchar(36)')
|
|
51
52
|
.addColumn('displayToolName', 'varchar(255)')
|
|
52
|
-
.addColumn('displayArgs',
|
|
53
|
-
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
54
|
-
|
|
53
|
+
.addColumn('displayArgs', ctx.text)
|
|
54
|
+
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
55
|
+
.$call(ctx.foreignKeys('agentToolCall', {
|
|
56
|
+
threadId: 'agentThreads.id',
|
|
57
|
+
messageId: 'agentMessage.id',
|
|
58
|
+
})),
|
|
59
|
+
(db, _types, ctx) => db.schema
|
|
55
60
|
.createIndex('idx_agent_tool_call_thread')
|
|
56
61
|
.on('agentToolCall')
|
|
57
62
|
.column('threadId'),
|
|
58
|
-
(db) => db.schema
|
|
63
|
+
(db, _types, ctx) => db.schema
|
|
59
64
|
.createIndex('idx_agent_tool_call_message')
|
|
60
65
|
.on('agentToolCall')
|
|
61
66
|
.column('messageId'),
|
|
62
|
-
(db) => db.schema
|
|
67
|
+
(db, _types, ctx) => db.schema
|
|
63
68
|
.createTable('agentWorkingMemory')
|
|
64
69
|
.addColumn('id', 'varchar(255)', (col) => col.notNull())
|
|
65
70
|
.addColumn('scope', 'varchar(50)', (col) => col.notNull())
|
|
66
|
-
.addColumn('data',
|
|
71
|
+
.addColumn('data', ctx.text, (col) => col.notNull())
|
|
67
72
|
.addColumn('updatedAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
68
73
|
.addPrimaryKeyConstraint('agent_working_memory_pk', ['id', 'scope']),
|
|
69
|
-
(db) => db.schema
|
|
74
|
+
(db, _types, ctx) => db.schema
|
|
70
75
|
.createTable('agentRun')
|
|
71
76
|
.addColumn('runId', 'varchar(36)', (col) => col.primaryKey())
|
|
72
77
|
.addColumn('agentName', 'varchar(255)', (col) => col.notNull())
|
|
73
|
-
.addColumn('threadId', 'varchar(36)', (col) => col.notNull()
|
|
78
|
+
.addColumn('threadId', 'varchar(36)', (col) => ctx.references(col.notNull(), 'agentThreads.id'))
|
|
74
79
|
.addColumn('resourceId', 'varchar(255)', (col) => col.notNull())
|
|
75
|
-
.addColumn('status', 'varchar(50)', (col) => col.notNull().defaultTo('running'))
|
|
76
|
-
.addColumn('errorMessage',
|
|
77
|
-
.addColumn('suspendReason',
|
|
78
|
-
.addColumn('missingRpcs',
|
|
79
|
-
.addColumn('pendingApprovals',
|
|
80
|
+
.addColumn('status', 'varchar(50)', (col) => col.notNull().defaultTo(ctx.defaultText('running')))
|
|
81
|
+
.addColumn('errorMessage', ctx.text)
|
|
82
|
+
.addColumn('suspendReason', ctx.text)
|
|
83
|
+
.addColumn('missingRpcs', ctx.text)
|
|
84
|
+
.addColumn('pendingApprovals', ctx.text)
|
|
80
85
|
.addColumn('usageInputTokens', 'integer', (col) => col.notNull().defaultTo(0))
|
|
81
86
|
.addColumn('usageOutputTokens', 'integer', (col) => col.notNull().defaultTo(0))
|
|
82
|
-
.addColumn('usageModel', 'varchar(255)', (col) => col.notNull().defaultTo(''))
|
|
87
|
+
.addColumn('usageModel', 'varchar(255)', (col) => col.notNull().defaultTo(ctx.defaultText('')))
|
|
83
88
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
84
|
-
.addColumn('updatedAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
85
|
-
|
|
89
|
+
.addColumn('updatedAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
90
|
+
.$call(ctx.foreignKeys('agentRun', { threadId: 'agentThreads.id' })),
|
|
91
|
+
(db, _types, ctx) => db.schema
|
|
86
92
|
.createIndex('idx_agent_run_thread')
|
|
87
93
|
.on('agentRun')
|
|
88
94
|
.columns(['threadId', 'createdAt']),
|
|
89
|
-
(db) => db.schema
|
|
95
|
+
(db, _types, ctx) => db.schema
|
|
90
96
|
.createTable('agentRunScore')
|
|
91
97
|
.addColumn('id', 'varchar(36)', (col) => col.primaryKey())
|
|
92
|
-
.addColumn('runId', 'varchar(36)', (col) => col.notNull()
|
|
98
|
+
.addColumn('runId', 'varchar(36)', (col) => ctx.references(col.notNull(), 'agentRun.runId'))
|
|
93
99
|
.addColumn('scorerName', 'varchar(255)', (col) => col.notNull())
|
|
94
100
|
.addColumn('score', 'real', (col) => col.notNull())
|
|
95
|
-
.addColumn('reason',
|
|
96
|
-
.addColumn('metadata',
|
|
97
|
-
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
98
|
-
|
|
101
|
+
.addColumn('reason', ctx.text)
|
|
102
|
+
.addColumn('metadata', ctx.text)
|
|
103
|
+
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
104
|
+
.$call(ctx.foreignKeys('agentRunScore', { runId: 'agentRun.runId' })),
|
|
105
|
+
(db, _types, ctx) => db.schema
|
|
99
106
|
.createIndex('idx_agent_run_score_run')
|
|
100
107
|
.on('agentRunScore')
|
|
101
108
|
.columns(['runId', 'createdAt']),
|
|
@@ -17,30 +17,30 @@ export const analyticsSchema = {
|
|
|
17
17
|
name: 'analytics',
|
|
18
18
|
ownedBy: ['analyticsService'],
|
|
19
19
|
statements: [
|
|
20
|
-
(db) => db.schema
|
|
20
|
+
(db, _types, ctx) => db.schema
|
|
21
21
|
.createTable('pikkuAnalyticsEvents')
|
|
22
|
-
.addColumn('eventId',
|
|
23
|
-
.addColumn('name',
|
|
24
|
-
.addColumn('occurredAt',
|
|
25
|
-
.addColumn('source',
|
|
26
|
-
.addColumn('functionId',
|
|
27
|
-
.addColumn('wireType',
|
|
28
|
-
.addColumn('traceId',
|
|
29
|
-
.addColumn('userId',
|
|
30
|
-
.addColumn('orgId',
|
|
31
|
-
.addColumn('pikkuUserId',
|
|
22
|
+
.addColumn('eventId', ctx.key, (col) => col.primaryKey())
|
|
23
|
+
.addColumn('name', ctx.key, (col) => col.notNull())
|
|
24
|
+
.addColumn('occurredAt', ctx.key, (col) => col.notNull())
|
|
25
|
+
.addColumn('source', ctx.text, (col) => col.notNull())
|
|
26
|
+
.addColumn('functionId', ctx.text)
|
|
27
|
+
.addColumn('wireType', ctx.text)
|
|
28
|
+
.addColumn('traceId', ctx.text)
|
|
29
|
+
.addColumn('userId', ctx.text)
|
|
30
|
+
.addColumn('orgId', ctx.text)
|
|
31
|
+
.addColumn('pikkuUserId', ctx.text)
|
|
32
32
|
// The device id for a visitor with no session. Its own column beside
|
|
33
33
|
// `userId` and not folded into it: the whole point of the anonymous id
|
|
34
34
|
// is the traffic that has no user to be attributed to yet.
|
|
35
|
-
.addColumn('anonymousId',
|
|
36
|
-
.addColumn('vendorIds',
|
|
37
|
-
.addColumn('consent',
|
|
38
|
-
.addColumn('props',
|
|
39
|
-
(db) => db.schema
|
|
35
|
+
.addColumn('anonymousId', ctx.text)
|
|
36
|
+
.addColumn('vendorIds', ctx.text)
|
|
37
|
+
.addColumn('consent', ctx.text)
|
|
38
|
+
.addColumn('props', ctx.text),
|
|
39
|
+
(db, _types, ctx) => db.schema
|
|
40
40
|
.createIndex('idx_pikku_analytics_events_occurred_at')
|
|
41
41
|
.on('pikkuAnalyticsEvents')
|
|
42
42
|
.column('occurredAt'),
|
|
43
|
-
(db) => db.schema
|
|
43
|
+
(db, _types, ctx) => db.schema
|
|
44
44
|
.createIndex('idx_pikku_analytics_events_name')
|
|
45
45
|
.on('pikkuAnalyticsEvents')
|
|
46
46
|
.column('name'),
|
|
@@ -17,33 +17,33 @@ export const auditSchema = {
|
|
|
17
17
|
name: 'audit',
|
|
18
18
|
ownedBy: ['audit', 'auditLog'],
|
|
19
19
|
statements: [
|
|
20
|
-
(db) => db.schema
|
|
20
|
+
(db, _types, ctx) => db.schema
|
|
21
21
|
.createTable('audit')
|
|
22
|
-
.addColumn('auditId',
|
|
23
|
-
.addColumn('occurredAt',
|
|
24
|
-
.addColumn('type',
|
|
25
|
-
.addColumn('source',
|
|
26
|
-
.addColumn('outcome',
|
|
27
|
-
.addColumn('functionId',
|
|
28
|
-
.addColumn('wireType',
|
|
29
|
-
.addColumn('traceId',
|
|
30
|
-
.addColumn('transactionId',
|
|
31
|
-
.addColumn('queryId',
|
|
32
|
-
.addColumn('userId',
|
|
33
|
-
.addColumn('orgId',
|
|
34
|
-
.addColumn('pikkuUserId',
|
|
35
|
-
.addColumn('tables',
|
|
36
|
-
.addColumn('changedCols',
|
|
37
|
-
.addColumn('event',
|
|
38
|
-
.addColumn('old',
|
|
39
|
-
.addColumn('data',
|
|
22
|
+
.addColumn('auditId', ctx.key, (col) => col.primaryKey())
|
|
23
|
+
.addColumn('occurredAt', ctx.key, (col) => col.notNull())
|
|
24
|
+
.addColumn('type', ctx.key, (col) => col.notNull())
|
|
25
|
+
.addColumn('source', ctx.text, (col) => col.defaultTo(ctx.defaultText('auto')).notNull())
|
|
26
|
+
.addColumn('outcome', ctx.text)
|
|
27
|
+
.addColumn('functionId', ctx.text)
|
|
28
|
+
.addColumn('wireType', ctx.text)
|
|
29
|
+
.addColumn('traceId', ctx.text)
|
|
30
|
+
.addColumn('transactionId', ctx.text)
|
|
31
|
+
.addColumn('queryId', ctx.text)
|
|
32
|
+
.addColumn('userId', ctx.key)
|
|
33
|
+
.addColumn('orgId', ctx.text)
|
|
34
|
+
.addColumn('pikkuUserId', ctx.text)
|
|
35
|
+
.addColumn('tables', ctx.text)
|
|
36
|
+
.addColumn('changedCols', ctx.text)
|
|
37
|
+
.addColumn('event', ctx.text)
|
|
38
|
+
.addColumn('old', ctx.text)
|
|
39
|
+
.addColumn('data', ctx.text),
|
|
40
40
|
// The trail is only ever read newest-first, and the two filters the console
|
|
41
41
|
// offers are user and type.
|
|
42
|
-
(db) => db.schema
|
|
42
|
+
(db, _types, ctx) => db.schema
|
|
43
43
|
.createIndex('idx_audit_occurred_at')
|
|
44
44
|
.on('audit')
|
|
45
45
|
.column('occurredAt'),
|
|
46
|
-
(db) => db.schema.createIndex('idx_audit_user_id').on('audit').column('userId'),
|
|
47
|
-
(db) => db.schema.createIndex('idx_audit_type').on('audit').column('type'),
|
|
46
|
+
(db, _types, ctx) => db.schema.createIndex('idx_audit_user_id').on('audit').column('userId'),
|
|
47
|
+
(db, _types, ctx) => db.schema.createIndex('idx_audit_type').on('audit').column('type'),
|
|
48
48
|
],
|
|
49
49
|
};
|
|
@@ -4,22 +4,25 @@ export const channelSchema = {
|
|
|
4
4
|
name: 'channel',
|
|
5
5
|
ownedBy: ['channelStore', 'eventHub'],
|
|
6
6
|
statements: [
|
|
7
|
-
(db) => db.schema
|
|
7
|
+
(db, _types, ctx) => db.schema
|
|
8
8
|
.createTable('channels')
|
|
9
|
-
.addColumn('channelId',
|
|
10
|
-
.addColumn('channelName',
|
|
9
|
+
.addColumn('channelId', ctx.key, (col) => col.primaryKey())
|
|
10
|
+
.addColumn('channelName', ctx.text, (col) => col.notNull())
|
|
11
11
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
12
|
-
.addColumn('openingData',
|
|
13
|
-
.addColumn('pikkuUserId',
|
|
14
|
-
.addColumn('state',
|
|
12
|
+
.addColumn('openingData', ctx.text, (col) => col.notNull().defaultTo(ctx.defaultText('{}')))
|
|
13
|
+
.addColumn('pikkuUserId', ctx.text)
|
|
14
|
+
.addColumn('state', ctx.text)
|
|
15
15
|
.addColumn('lastWire', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull()),
|
|
16
|
-
(db) => db.schema
|
|
16
|
+
(db, _types, ctx) => db.schema
|
|
17
17
|
.createTable('channelSubscriptions')
|
|
18
|
-
.addColumn('channelId',
|
|
19
|
-
.addColumn('topic',
|
|
18
|
+
.addColumn('channelId', ctx.key, (col) => ctx.references(col.notNull(), 'channels.channelId'))
|
|
19
|
+
.addColumn('topic', ctx.key, (col) => col.notNull())
|
|
20
20
|
.addPrimaryKeyConstraint('channel_subscriptions_pk', [
|
|
21
21
|
'channelId',
|
|
22
22
|
'topic',
|
|
23
|
-
])
|
|
23
|
+
])
|
|
24
|
+
.$call(ctx.foreignKeys('channelSubscriptions', {
|
|
25
|
+
channelId: 'channels.channelId',
|
|
26
|
+
})),
|
|
24
27
|
],
|
|
25
28
|
};
|
|
@@ -14,22 +14,22 @@ export const credentialSchema = {
|
|
|
14
14
|
name: 'credential',
|
|
15
15
|
ownedBy: ['credentialService'],
|
|
16
16
|
statements: [
|
|
17
|
-
(db) => db.schema
|
|
17
|
+
(db, _types, ctx) => db.schema
|
|
18
18
|
.createTable('credentials')
|
|
19
19
|
.addColumn('name', 'varchar(255)', (col) => col.notNull())
|
|
20
20
|
.addColumn('userId', 'varchar(255)')
|
|
21
|
-
.addColumn('ciphertext',
|
|
22
|
-
.addColumn('wrappedDek',
|
|
21
|
+
.addColumn('ciphertext', ctx.text, (col) => col.notNull())
|
|
22
|
+
.addColumn('wrappedDek', ctx.text, (col) => col.notNull())
|
|
23
23
|
.addColumn('keyVersion', 'integer', (col) => col.notNull())
|
|
24
24
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
25
25
|
.addColumn('updatedAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull()),
|
|
26
|
-
rawStatement(({ table }) => sql `CREATE UNIQUE INDEX credentials_name_user_id_unique ON ${table('credentials')} (name, COALESCE(user_id, ''))`),
|
|
27
|
-
(db) => db.schema
|
|
26
|
+
rawStatement(({ table, mysql }) => sql `CREATE UNIQUE INDEX credentials_name_user_id_unique ON ${table('credentials')} (name, ${mysql ? sql `(COALESCE(user_id, ''))` : sql `COALESCE(user_id, '')`})`),
|
|
27
|
+
(db, _types, ctx) => db.schema
|
|
28
28
|
.createTable('credentialKekSalts')
|
|
29
29
|
.addColumn('keyVersion', 'integer', (col) => col.primaryKey())
|
|
30
30
|
.addColumn('salt', 'varchar(64)', (col) => col.notNull())
|
|
31
31
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull()),
|
|
32
|
-
(db) => db.schema
|
|
32
|
+
(db, _types, ctx) => db.schema
|
|
33
33
|
.createTable('credentialsAudit')
|
|
34
34
|
.addColumn('id', 'varchar(36)', (col) => col.primaryKey())
|
|
35
35
|
.addColumn('credentialName', 'varchar(255)', (col) => col.notNull())
|
|
@@ -3,28 +3,28 @@ import { sql } from 'kysely';
|
|
|
3
3
|
export const deploymentSchema = {
|
|
4
4
|
name: 'deployment',
|
|
5
5
|
statements: [
|
|
6
|
-
(db) => db.schema
|
|
6
|
+
(db, _types, ctx) => db.schema
|
|
7
7
|
.createTable('pikkuDeployments')
|
|
8
|
-
.addColumn('deploymentId',
|
|
9
|
-
.addColumn('endpoint',
|
|
8
|
+
.addColumn('deploymentId', ctx.key, (col) => col.primaryKey())
|
|
9
|
+
.addColumn('endpoint', ctx.text, (col) => col.notNull())
|
|
10
10
|
.addColumn('lastHeartbeat', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
11
11
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull()),
|
|
12
|
-
(db) => db.schema
|
|
12
|
+
(db, _types, ctx) => db.schema
|
|
13
13
|
.createTable('pikkuDeploymentFunctions')
|
|
14
|
-
.addColumn('deploymentId',
|
|
15
|
-
.notNull()
|
|
16
|
-
.references('pikkuDeployments.deploymentId')
|
|
17
|
-
.onDelete('cascade'))
|
|
18
|
-
.addColumn('functionName', 'text', (col) => col.notNull())
|
|
14
|
+
.addColumn('deploymentId', ctx.key, (col) => ctx.references(col.notNull(), 'pikkuDeployments.deploymentId'))
|
|
15
|
+
.addColumn('functionName', ctx.key, (col) => col.notNull())
|
|
19
16
|
.addPrimaryKeyConstraint('pikku_deployment_functions_pk', [
|
|
20
17
|
'deploymentId',
|
|
21
18
|
'functionName',
|
|
22
|
-
])
|
|
23
|
-
|
|
19
|
+
])
|
|
20
|
+
.$call(ctx.foreignKeys('pikkuDeploymentFunctions', {
|
|
21
|
+
deploymentId: 'pikkuDeployments.deploymentId',
|
|
22
|
+
})),
|
|
23
|
+
(db, _types, ctx) => db.schema
|
|
24
24
|
.createIndex('idx_pikku_deployments_heartbeat')
|
|
25
25
|
.on('pikkuDeployments')
|
|
26
26
|
.column('lastHeartbeat'),
|
|
27
|
-
(db) => db.schema
|
|
27
|
+
(db, _types, ctx) => db.schema
|
|
28
28
|
.createIndex('idx_pikku_deployment_functions_name')
|
|
29
29
|
.on('pikkuDeploymentFunctions')
|
|
30
30
|
.column('functionName'),
|
|
@@ -17,14 +17,14 @@ export const flagSchema = {
|
|
|
17
17
|
name: 'flag',
|
|
18
18
|
ownedBy: ['featureFlags'],
|
|
19
19
|
statements: [
|
|
20
|
-
(db) => db.schema
|
|
20
|
+
(db, _types, ctx) => db.schema
|
|
21
21
|
.createTable('pikkuFeatureFlags')
|
|
22
|
-
.addColumn('name',
|
|
23
|
-
.addColumn('description',
|
|
22
|
+
.addColumn('name', ctx.key, (col) => col.primaryKey())
|
|
23
|
+
.addColumn('description', ctx.text)
|
|
24
24
|
// The declared `anyOf` scope list, as JSON. Read by the console to say
|
|
25
25
|
// who would see the feature; never read on the request path, where the
|
|
26
26
|
// capability half comes from the session's own scopes.
|
|
27
|
-
.addColumn('anyOf',
|
|
27
|
+
.addColumn('anyOf', ctx.text)
|
|
28
28
|
// Off until somebody turns it on. A flag exists so a feature can ship
|
|
29
29
|
// dark, so the row a deploy creates has to start closed — the opposite
|
|
30
30
|
// default would make merging the declaration the moment of launch.
|
|
@@ -37,26 +37,29 @@ export const flagSchema = {
|
|
|
37
37
|
// longer offered, awaiting `pikku flags prune`. The same additive
|
|
38
38
|
// contract as `pikkuScopes.declared`.
|
|
39
39
|
.addColumn('declared', 'boolean', (col) => col.defaultTo(true).notNull())
|
|
40
|
-
.addColumn('updatedBy',
|
|
40
|
+
.addColumn('updatedBy', ctx.text)
|
|
41
41
|
// Why it was flipped. A kill switch is pulled during an incident, and
|
|
42
42
|
// the one question afterwards is always who turned it off and why.
|
|
43
|
-
.addColumn('note',
|
|
43
|
+
.addColumn('note', ctx.text)
|
|
44
44
|
.addColumn('updatedAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull()),
|
|
45
|
-
(db) => db.schema
|
|
45
|
+
(db, _types, ctx) => db.schema
|
|
46
46
|
.createTable('pikkuFeatureFlagOverrides')
|
|
47
|
-
.addColumn('flag',
|
|
48
|
-
.addColumn('subjectId',
|
|
47
|
+
.addColumn('flag', ctx.key, (col) => ctx.references(col.notNull(), 'pikkuFeatureFlags.name'))
|
|
48
|
+
.addColumn('subjectId', ctx.key, (col) => col.notNull())
|
|
49
49
|
// Which id this is, for the console to render. Resolution keys on the
|
|
50
50
|
// id alone, because that is all the resolver has: it prefers the
|
|
51
51
|
// organization and falls back to the user, and by then the two are one
|
|
52
52
|
// string.
|
|
53
|
-
.addColumn('subjectKind',
|
|
53
|
+
.addColumn('subjectKind', ctx.text, (col) => col.notNull())
|
|
54
54
|
.addColumn('enabled', 'boolean', (col) => col.notNull())
|
|
55
|
-
.addColumn('grantedBy',
|
|
55
|
+
.addColumn('grantedBy', ctx.text)
|
|
56
56
|
.addColumn('grantedAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
57
57
|
.addPrimaryKeyConstraint('pikku_feature_flag_overrides_pk', [
|
|
58
58
|
'flag',
|
|
59
59
|
'subjectId',
|
|
60
|
-
])
|
|
60
|
+
])
|
|
61
|
+
.$call(ctx.foreignKeys('pikkuFeatureFlagOverrides', {
|
|
62
|
+
flag: 'pikkuFeatureFlags.name',
|
|
63
|
+
})),
|
|
61
64
|
],
|
|
62
65
|
};
|
|
@@ -4,15 +4,15 @@ export const incomingWebhookSchema = {
|
|
|
4
4
|
name: 'incoming-webhook',
|
|
5
5
|
ownedBy: ['incomingWebhookService'],
|
|
6
6
|
statements: [
|
|
7
|
-
(db) => db.schema
|
|
7
|
+
(db, _types, ctx) => db.schema
|
|
8
8
|
.createTable('webhookReceipt')
|
|
9
|
-
.addColumn('receiptId',
|
|
10
|
-
.addColumn('source',
|
|
11
|
-
.addColumn('event',
|
|
12
|
-
.addColumn('providerEventId',
|
|
13
|
-
.addColumn('status',
|
|
9
|
+
.addColumn('receiptId', ctx.key, (col) => col.primaryKey())
|
|
10
|
+
.addColumn('source', ctx.key, (col) => col.notNull())
|
|
11
|
+
.addColumn('event', ctx.key, (col) => col.notNull())
|
|
12
|
+
.addColumn('providerEventId', ctx.key)
|
|
13
|
+
.addColumn('status', ctx.text, (col) => col.defaultTo(ctx.defaultText('pending')).notNull())
|
|
14
14
|
.addColumn('attempts', 'integer', (col) => col.defaultTo(0).notNull())
|
|
15
|
-
.addColumn('lastError',
|
|
15
|
+
.addColumn('lastError', ctx.text)
|
|
16
16
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
17
17
|
.addColumn('deliveredAt', 'timestamp'),
|
|
18
18
|
(db) => db.schema
|
package/dist/src/schema/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CamelCasePlugin } from 'kysely';
|
|
1
|
+
import { CamelCasePlugin, sql } from 'kysely';
|
|
2
2
|
import { schemaContext, } from './pikku-schema.types.js';
|
|
3
3
|
import { agentSchema } from './agent.schema.js';
|
|
4
4
|
import { analyticsSchema } from './analytics.schema.js';
|
|
@@ -102,10 +102,30 @@ const bind = (db) => db.withPlugin(new CamelCasePlugin());
|
|
|
102
102
|
* connection they are handed. A caller that had to remember to say the schema
|
|
103
103
|
* twice would eventually say it once.
|
|
104
104
|
*/
|
|
105
|
-
const
|
|
106
|
-
.sql
|
|
107
|
-
/**
|
|
108
|
-
|
|
105
|
+
const probe = (db) => db.schema.createTable('pikkuSchemaProbe').addColumn('id', 'text').compile()
|
|
106
|
+
.sql;
|
|
107
|
+
/**
|
|
108
|
+
* The context for statements compiled against `db`, matching its binding and
|
|
109
|
+
* its dialect — MySQL is recognised by the backtick it quotes with.
|
|
110
|
+
*/
|
|
111
|
+
const contextFor = (db) => {
|
|
112
|
+
const sql = probe(db);
|
|
113
|
+
return schemaContext(CREATE_TABLE.exec(sql)?.[1], {
|
|
114
|
+
mysql: sql.includes('`'),
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* A MySQL column's full declared type — `varchar(36)`, not the `varchar` the
|
|
119
|
+
* introspector reports. The length is part of the type a foreign key has to
|
|
120
|
+
* match, and a bare `varchar` is not a type MySQL accepts.
|
|
121
|
+
*/
|
|
122
|
+
const mysqlColumnType = async (db, table, column) => {
|
|
123
|
+
const { rows } = await sql `
|
|
124
|
+
select column_type as type from information_schema.columns
|
|
125
|
+
where table_schema = database() and table_name = ${table} and column_name = ${column}
|
|
126
|
+
`.execute(db);
|
|
127
|
+
return rows[0].type;
|
|
128
|
+
};
|
|
109
129
|
/**
|
|
110
130
|
* Look up every prerequisite in `db`, reporting the gaps and the types found.
|
|
111
131
|
*
|
|
@@ -122,6 +142,7 @@ export const resolveRequirements = async (db, schemas = pikkuSchemas) => {
|
|
|
122
142
|
table.name,
|
|
123
143
|
table,
|
|
124
144
|
]));
|
|
145
|
+
const mysql = contextFor(bind(db)).mysql;
|
|
125
146
|
const types = {};
|
|
126
147
|
const unmet = [];
|
|
127
148
|
for (const schema of schemas) {
|
|
@@ -133,7 +154,9 @@ export const resolveRequirements = async (db, schemas = pikkuSchemas) => {
|
|
|
133
154
|
unmet.push({ schema, requirement });
|
|
134
155
|
}
|
|
135
156
|
else {
|
|
136
|
-
types[`${requirement.table}.${requirement.column}`] =
|
|
157
|
+
types[`${requirement.table}.${requirement.column}`] = mysql
|
|
158
|
+
? await mysqlColumnType(db, requirement.table, requirement.column)
|
|
159
|
+
: column.dataType;
|
|
137
160
|
}
|
|
138
161
|
}
|
|
139
162
|
}
|
|
@@ -234,7 +257,7 @@ const displayName = (table) => table.schema ? `${table.schema}.${table.name}` :
|
|
|
234
257
|
* identifier — matching the first one instead reads a `withSchema('app')`
|
|
235
258
|
* connection's DDL as a table called `app`, which is no table at all.
|
|
236
259
|
*/
|
|
237
|
-
const CREATE_TABLE = /^\s*create table (?:if not exists\s+)?(?:"([^"]+)"\.)?"([^"]+)"/i;
|
|
260
|
+
const CREATE_TABLE = /^\s*create table (?:if not exists\s+)?(?:["`]([^"`]+)["`]\.)?["`]([^"`]+)["`]/i;
|
|
238
261
|
/**
|
|
239
262
|
* The tables a schema creates, read back out of its own compiled SQL.
|
|
240
263
|
*
|
|
@@ -2,10 +2,10 @@ export const leaseSchema = {
|
|
|
2
2
|
name: 'lease',
|
|
3
3
|
ownedBy: ['leaseService', 'workflowService'],
|
|
4
4
|
statements: [
|
|
5
|
-
(db) => db.schema
|
|
5
|
+
(db, _types, ctx) => db.schema
|
|
6
6
|
.createTable('pikkuLease')
|
|
7
|
-
.addColumn('key',
|
|
8
|
-
.addColumn('holder',
|
|
7
|
+
.addColumn('key', ctx.key, (col) => col.primaryKey())
|
|
8
|
+
.addColumn('holder', ctx.text, (col) => col.notNull())
|
|
9
9
|
.addColumn('token', 'integer', (col) => col.notNull())
|
|
10
10
|
.addColumn('expiresAt', 'bigint', (col) => col.notNull()),
|
|
11
11
|
],
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type CompiledQuery, type Kysely, type RawBuilder } from 'kysely';
|
|
1
|
+
import { type ColumnDefinitionBuilder, type CompiledQuery, type CreateTableBuilder, type Kysely, type RawBuilder } from 'kysely';
|
|
2
|
+
type DataTypeExpression = Parameters<CreateTableBuilder<any, any>['addColumn']>[1];
|
|
2
3
|
/**
|
|
3
4
|
* One DDL statement, bound to a database.
|
|
4
5
|
*
|
|
@@ -21,6 +22,12 @@ export type SchemaStatementFactory = (db: Kysely<any>, types: RequiredTypes, ctx
|
|
|
21
22
|
* statement that spells its own SQL has to spell the qualifier too.
|
|
22
23
|
*/
|
|
23
24
|
export interface SchemaContext {
|
|
25
|
+
/**
|
|
26
|
+
* Whether the connection is MySQL, which is the one engine the declarations
|
|
27
|
+
* cannot spell the same way: it refuses a `TEXT` column in a key or with a
|
|
28
|
+
* literal default, and quotes with backticks.
|
|
29
|
+
*/
|
|
30
|
+
mysql: boolean;
|
|
24
31
|
/**
|
|
25
32
|
* A table as the surrounding DDL addresses it: `"app"."credentials"` on a
|
|
26
33
|
* schema-bound connection, `"credentials"` otherwise.
|
|
@@ -30,6 +37,36 @@ export interface SchemaContext {
|
|
|
30
37
|
* physical names throughout and this is no exception.
|
|
31
38
|
*/
|
|
32
39
|
table: (name: string) => RawBuilder<unknown>;
|
|
40
|
+
/**
|
|
41
|
+
* The type of a text column that is part of a key — primary, foreign, unique
|
|
42
|
+
* or indexed. `text` everywhere but MySQL, where a key needs a bounded type.
|
|
43
|
+
*/
|
|
44
|
+
key: DataTypeExpression;
|
|
45
|
+
/**
|
|
46
|
+
* The type of free text of any length. `text` everywhere but MySQL, where
|
|
47
|
+
* `TEXT` stops at 64KB and these columns hold serialized state and payloads.
|
|
48
|
+
*/
|
|
49
|
+
text: DataTypeExpression;
|
|
50
|
+
/**
|
|
51
|
+
* A literal default for a text column. MySQL refuses one on `TEXT`, so it
|
|
52
|
+
* takes the parenthesised expression form (8.0.13+); everywhere else the
|
|
53
|
+
* literal itself.
|
|
54
|
+
*/
|
|
55
|
+
defaultText: (value: string) => string | RawBuilder<unknown>;
|
|
56
|
+
/**
|
|
57
|
+
* An inline `references ... on delete cascade` on a column.
|
|
58
|
+
*
|
|
59
|
+
* A no-op on MySQL, which parses an inline `REFERENCES` and discards it — the
|
|
60
|
+
* constraint never exists. There the same relationship is declared once, at
|
|
61
|
+
* table level, through `foreignKeys`.
|
|
62
|
+
*/
|
|
63
|
+
references: (column: ColumnDefinitionBuilder, target: string) => ColumnDefinitionBuilder;
|
|
64
|
+
/**
|
|
65
|
+
* The table-level foreign keys MySQL needs in place of inline `references`,
|
|
66
|
+
* keyed by local column to `table.column` target. Identity everywhere else,
|
|
67
|
+
* where `references` has already done the work.
|
|
68
|
+
*/
|
|
69
|
+
foreignKeys: (table: string, keys: Record<string, string>) => <T extends CreateTableBuilder<any, any>>(builder: T) => T;
|
|
33
70
|
}
|
|
34
71
|
/**
|
|
35
72
|
* The `SchemaContext` for DDL that names no schema.
|
|
@@ -44,7 +81,9 @@ export declare const unqualifiedContext: SchemaContext;
|
|
|
44
81
|
* Identifiers are quoted rather than interpolated bare so a schema named after
|
|
45
82
|
* a reserved word still compiles.
|
|
46
83
|
*/
|
|
47
|
-
export declare const schemaContext: (schema: string | undefined
|
|
84
|
+
export declare const schemaContext: (schema: string | undefined, options?: {
|
|
85
|
+
mysql?: boolean;
|
|
86
|
+
}) => SchemaContext;
|
|
48
87
|
/**
|
|
49
88
|
* The physical types of the columns named in `requires`, keyed `table.column`.
|
|
50
89
|
*
|
|
@@ -129,3 +168,4 @@ export interface SchemaRequirement {
|
|
|
129
168
|
*/
|
|
130
169
|
export declare function rawStatement(fragment: RawBuilder<unknown>): SchemaStatementFactory;
|
|
131
170
|
export declare function rawStatement(build: (ctx: SchemaContext) => RawBuilder<unknown>): SchemaStatementFactory;
|
|
171
|
+
export {};
|
|
@@ -1,22 +1,38 @@
|
|
|
1
|
-
import { sql } from 'kysely';
|
|
1
|
+
import { sql, } from 'kysely';
|
|
2
2
|
/**
|
|
3
3
|
* The `SchemaContext` for DDL that names no schema.
|
|
4
4
|
*
|
|
5
5
|
* The default everywhere a schema has not been asked for, which is every engine
|
|
6
6
|
* but postgres and most postgres projects too.
|
|
7
7
|
*/
|
|
8
|
-
export const unqualifiedContext =
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
export const unqualifiedContext = buildContext(undefined, false);
|
|
9
|
+
function buildContext(schema, mysql) {
|
|
10
|
+
const quote = mysql ? '`' : '"';
|
|
11
|
+
const name = (table) => schema
|
|
12
|
+
? `${quote}${schema}${quote}.${quote}${table}${quote}`
|
|
13
|
+
: `${quote}${table}${quote}`;
|
|
14
|
+
return {
|
|
15
|
+
mysql,
|
|
16
|
+
table: (table) => sql.raw(name(table)),
|
|
17
|
+
key: mysql ? sql.raw('varchar(255)') : 'text',
|
|
18
|
+
text: mysql ? sql.raw('longtext') : 'text',
|
|
19
|
+
defaultText: (value) => (mysql ? sql `(${sql.lit(value)})` : value),
|
|
20
|
+
references: (column, target) => mysql ? column : column.references(target).onDelete('cascade'),
|
|
21
|
+
foreignKeys: (table, keys) => (builder) => mysql
|
|
22
|
+
? Object.entries(keys).reduce((acc, [column, target]) => {
|
|
23
|
+
const [targetTable, targetColumn] = target.split('.');
|
|
24
|
+
return acc.addForeignKeyConstraint(`${table}_${column}_fk`, [column], targetTable, [targetColumn], (fk) => fk.onDelete('cascade'));
|
|
25
|
+
}, builder)
|
|
26
|
+
: builder,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
11
29
|
/**
|
|
12
30
|
* A `SchemaContext` qualifying every table into `schema`.
|
|
13
31
|
*
|
|
14
32
|
* Identifiers are quoted rather than interpolated bare so a schema named after
|
|
15
33
|
* a reserved word still compiles.
|
|
16
34
|
*/
|
|
17
|
-
export const schemaContext = (schema) => schema
|
|
18
|
-
? { table: (name) => sql.raw(`"${schema}"."${name}"`) }
|
|
19
|
-
: unqualifiedContext;
|
|
35
|
+
export const schemaContext = (schema, options = {}) => buildContext(schema, options.mysql ?? false);
|
|
20
36
|
/**
|
|
21
37
|
* The declared type for a foreign key onto a column another source owns.
|
|
22
38
|
*
|
|
@@ -21,15 +21,15 @@ export const scopeSchema = {
|
|
|
21
21
|
ownedBy: ['scopeService'],
|
|
22
22
|
requires: [{ table: 'user', column: 'id', owner: 'Better Auth' }],
|
|
23
23
|
statements: [
|
|
24
|
-
(db) => db.schema
|
|
24
|
+
(db, _types, ctx) => db.schema
|
|
25
25
|
.createTable('pikkuScopes')
|
|
26
|
-
.addColumn('name',
|
|
27
|
-
.addColumn('description',
|
|
26
|
+
.addColumn('name', ctx.key, (col) => col.primaryKey())
|
|
27
|
+
.addColumn('description', ctx.text)
|
|
28
28
|
.addColumn('declared', 'boolean', (col) => col.defaultTo(true).notNull()),
|
|
29
|
-
(db) => db.schema
|
|
29
|
+
(db, _types, ctx) => db.schema
|
|
30
30
|
.createTable('pikkuRoles')
|
|
31
|
-
.addColumn('name',
|
|
32
|
-
.addColumn('description',
|
|
31
|
+
.addColumn('name', ctx.key, (col) => col.primaryKey())
|
|
32
|
+
.addColumn('description', ctx.text)
|
|
33
33
|
// Declared in code with `defineSystemRole` rather than composed by an
|
|
34
34
|
// admin. What it buys is the refusals: a system role cannot be renamed,
|
|
35
35
|
// re-scoped or deleted from the console, and a console role cannot be
|
|
@@ -43,30 +43,42 @@ export const scopeSchema = {
|
|
|
43
43
|
// be able to cause.
|
|
44
44
|
.addColumn('declared', 'boolean', (col) => col.defaultTo(true).notNull())
|
|
45
45
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull()),
|
|
46
|
-
(db) => db.schema
|
|
46
|
+
(db, _types, ctx) => db.schema
|
|
47
47
|
.createTable('pikkuRoleScopes')
|
|
48
|
-
.addColumn('role',
|
|
49
|
-
.addColumn('scope',
|
|
50
|
-
.addPrimaryKeyConstraint('pikku_role_scopes_pk', ['role', 'scope'])
|
|
51
|
-
|
|
48
|
+
.addColumn('role', ctx.key, (col) => ctx.references(col.notNull(), 'pikkuRoles.name'))
|
|
49
|
+
.addColumn('scope', ctx.key, (col) => ctx.references(col.notNull(), 'pikkuScopes.name'))
|
|
50
|
+
.addPrimaryKeyConstraint('pikku_role_scopes_pk', ['role', 'scope'])
|
|
51
|
+
.$call(ctx.foreignKeys('pikkuRoleScopes', {
|
|
52
|
+
role: 'pikkuRoles.name',
|
|
53
|
+
scope: 'pikkuScopes.name',
|
|
54
|
+
})),
|
|
55
|
+
(db, types, ctx) => db.schema
|
|
52
56
|
.createTable('pikkuUserRole')
|
|
53
|
-
.addColumn('userId', requiredType(types, 'user', 'id'), (col) => col.notNull()
|
|
54
|
-
.addColumn('role',
|
|
55
|
-
.addColumn('grantedBy',
|
|
57
|
+
.addColumn('userId', requiredType(types, 'user', 'id'), (col) => ctx.references(col.notNull(), 'user.id'))
|
|
58
|
+
.addColumn('role', ctx.key, (col) => ctx.references(col.notNull(), 'pikkuRoles.name'))
|
|
59
|
+
.addColumn('grantedBy', ctx.text)
|
|
56
60
|
.addColumn('grantedAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
57
|
-
.addPrimaryKeyConstraint('pikku_user_role_pk', ['userId', 'role'])
|
|
58
|
-
|
|
61
|
+
.addPrimaryKeyConstraint('pikku_user_role_pk', ['userId', 'role'])
|
|
62
|
+
.$call(ctx.foreignKeys('pikkuUserRole', {
|
|
63
|
+
userId: 'user.id',
|
|
64
|
+
role: 'pikkuRoles.name',
|
|
65
|
+
})),
|
|
66
|
+
(db, types, ctx) => db.schema
|
|
59
67
|
.createTable('pikkuUserScope')
|
|
60
|
-
.addColumn('userId', requiredType(types, 'user', 'id'), (col) => col.notNull()
|
|
61
|
-
.addColumn('scope',
|
|
62
|
-
.addColumn('grantedBy',
|
|
68
|
+
.addColumn('userId', requiredType(types, 'user', 'id'), (col) => ctx.references(col.notNull(), 'user.id'))
|
|
69
|
+
.addColumn('scope', ctx.key, (col) => ctx.references(col.notNull(), 'pikkuScopes.name'))
|
|
70
|
+
.addColumn('grantedBy', ctx.text)
|
|
63
71
|
.addColumn('grantedAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
64
|
-
.addPrimaryKeyConstraint('pikku_user_scope_pk', ['userId', 'scope'])
|
|
65
|
-
|
|
72
|
+
.addPrimaryKeyConstraint('pikku_user_scope_pk', ['userId', 'scope'])
|
|
73
|
+
.$call(ctx.foreignKeys('pikkuUserScope', {
|
|
74
|
+
userId: 'user.id',
|
|
75
|
+
scope: 'pikkuScopes.name',
|
|
76
|
+
})),
|
|
77
|
+
(db, _types, ctx) => db.schema
|
|
66
78
|
.createIndex('pikku_role_scopes_scope_idx')
|
|
67
79
|
.on('pikkuRoleScopes')
|
|
68
80
|
.column('scope'),
|
|
69
|
-
(db) => db.schema
|
|
81
|
+
(db, _types, ctx) => db.schema
|
|
70
82
|
.createIndex('pikku_user_role_role_idx')
|
|
71
83
|
.on('pikkuUserRole')
|
|
72
84
|
.column('role'),
|
|
@@ -11,20 +11,20 @@ import { sql } from 'kysely';
|
|
|
11
11
|
export const secretSchema = {
|
|
12
12
|
name: 'secret',
|
|
13
13
|
statements: [
|
|
14
|
-
(db) => db.schema
|
|
14
|
+
(db, _types, ctx) => db.schema
|
|
15
15
|
.createTable('secrets')
|
|
16
16
|
.addColumn('key', 'varchar(255)', (col) => col.primaryKey())
|
|
17
|
-
.addColumn('ciphertext',
|
|
18
|
-
.addColumn('wrappedDek',
|
|
17
|
+
.addColumn('ciphertext', ctx.text, (col) => col.notNull())
|
|
18
|
+
.addColumn('wrappedDek', ctx.text, (col) => col.notNull())
|
|
19
19
|
.addColumn('keyVersion', 'integer', (col) => col.notNull())
|
|
20
20
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
21
21
|
.addColumn('updatedAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull()),
|
|
22
|
-
(db) => db.schema
|
|
22
|
+
(db, _types, ctx) => db.schema
|
|
23
23
|
.createTable('secretKekSalts')
|
|
24
24
|
.addColumn('keyVersion', 'integer', (col) => col.primaryKey())
|
|
25
25
|
.addColumn('salt', 'varchar(64)', (col) => col.notNull())
|
|
26
26
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull()),
|
|
27
|
-
(db) => db.schema
|
|
27
|
+
(db, _types, ctx) => db.schema
|
|
28
28
|
.createTable('secretsAudit')
|
|
29
29
|
.addColumn('id', 'varchar(36)', (col) => col.primaryKey())
|
|
30
30
|
.addColumn('secretKey', 'varchar(255)', (col) => col.notNull())
|
|
@@ -3,10 +3,10 @@ import { sql } from 'kysely';
|
|
|
3
3
|
export const sessionSchema = {
|
|
4
4
|
name: 'session',
|
|
5
5
|
statements: [
|
|
6
|
-
(db) => db.schema
|
|
6
|
+
(db, _types, ctx) => db.schema
|
|
7
7
|
.createTable('pikkuUserSessions')
|
|
8
|
-
.addColumn('pikkuUserId',
|
|
9
|
-
.addColumn('session',
|
|
8
|
+
.addColumn('pikkuUserId', ctx.key, (col) => col.primaryKey())
|
|
9
|
+
.addColumn('session', ctx.text, (col) => col.notNull())
|
|
10
10
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
11
11
|
.addColumn('updatedAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull()),
|
|
12
12
|
],
|
|
@@ -7,17 +7,17 @@ export const triggerSourceSchema = {
|
|
|
7
7
|
name: 'trigger-source',
|
|
8
8
|
ownedBy: ['triggerSourceStore'],
|
|
9
9
|
statements: [
|
|
10
|
-
(db) => db.schema
|
|
10
|
+
(db, _types, ctx) => db.schema
|
|
11
11
|
.createTable('pikkuTriggerSource')
|
|
12
|
-
.addColumn('name',
|
|
13
|
-
.addColumn('kind',
|
|
14
|
-
.addColumn('baseUrl',
|
|
15
|
-
.addColumn('labelPrefix',
|
|
12
|
+
.addColumn('name', ctx.key, (col) => col.primaryKey())
|
|
13
|
+
.addColumn('kind', ctx.text, (col) => col.notNull())
|
|
14
|
+
.addColumn('baseUrl', ctx.text)
|
|
15
|
+
.addColumn('labelPrefix', ctx.text)
|
|
16
16
|
.addColumn('declared', 'boolean', (col) => col.defaultTo(true).notNull())
|
|
17
17
|
.addColumn('enabled', 'boolean', (col) => col.defaultTo(false).notNull())
|
|
18
|
-
.addColumn('status',
|
|
19
|
-
.addColumn('state',
|
|
20
|
-
.addColumn('detail',
|
|
18
|
+
.addColumn('status', ctx.text)
|
|
19
|
+
.addColumn('state', ctx.text)
|
|
20
|
+
.addColumn('detail', ctx.text)
|
|
21
21
|
.addColumn('updatedAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull()),
|
|
22
22
|
],
|
|
23
23
|
};
|
|
@@ -15,7 +15,7 @@ export const virtualUserScheduleSchema = {
|
|
|
15
15
|
name: 'virtual-user-schedule',
|
|
16
16
|
ownedBy: ['virtualUserScheduleStore'],
|
|
17
17
|
statements: [
|
|
18
|
-
(db) => db.schema
|
|
18
|
+
(db, _types, ctx) => db.schema
|
|
19
19
|
.createTable('virtualUserSchedule')
|
|
20
20
|
.addColumn('persona', 'varchar(255)', (col) => col.primaryKey())
|
|
21
21
|
// 0 or 1 rather than a boolean, matching the run tables: a bare sqlite
|
|
@@ -23,8 +23,8 @@ export const virtualUserScheduleSchema = {
|
|
|
23
23
|
// everywhere. Off by default, so creating the table spends nothing.
|
|
24
24
|
.addColumn('enabled', 'integer', (col) => col.defaultTo(0).notNull())
|
|
25
25
|
.addColumn('disposition', 'varchar(50)', (col) => col.notNull())
|
|
26
|
-
.addColumn('goals',
|
|
27
|
-
.addColumn('budget',
|
|
26
|
+
.addColumn('goals', ctx.text, (col) => col.defaultTo(ctx.defaultText('[]')).notNull())
|
|
27
|
+
.addColumn('budget', ctx.text)
|
|
28
28
|
// The gap to the next run is drawn between these rather than fixed, so
|
|
29
29
|
// the persona does not keep an appointment.
|
|
30
30
|
.addColumn('minIntervalMs', 'bigint', (col) => col.notNull())
|
|
@@ -35,7 +35,7 @@ export const virtualUserScheduleSchema = {
|
|
|
35
35
|
.addColumn('lastRunId', 'varchar(36)')
|
|
36
36
|
.addColumn('lastRunAt', 'timestamp'),
|
|
37
37
|
// The only read that matters at speed: which rows are due, on every tick.
|
|
38
|
-
(db) => db.schema
|
|
38
|
+
(db, _types, ctx) => db.schema
|
|
39
39
|
.createIndex('idx_virtual_user_schedule_due')
|
|
40
40
|
.on('virtualUserSchedule')
|
|
41
41
|
.columns(['enabled', 'nextRunAt']),
|
|
@@ -21,7 +21,7 @@ export const virtualUserSchema = {
|
|
|
21
21
|
name: 'virtual-user',
|
|
22
22
|
ownedBy: ['virtualUserRunStore'],
|
|
23
23
|
statements: [
|
|
24
|
-
(db) => db.schema
|
|
24
|
+
(db, _types, ctx) => db.schema
|
|
25
25
|
.createTable('virtualUserRun')
|
|
26
26
|
.addColumn('runId', 'varchar(36)', (col) => col.primaryKey())
|
|
27
27
|
.addColumn('persona', 'varchar(255)', (col) => col.notNull())
|
|
@@ -30,29 +30,29 @@ export const virtualUserSchema = {
|
|
|
30
30
|
// running | completed | failed. Not derived from `finishedAt` being
|
|
31
31
|
// null: a crashed run has no finish time either, and "crashed" and
|
|
32
32
|
// "still going" are not the same answer.
|
|
33
|
-
.addColumn('status', 'varchar(50)', (col) => col.defaultTo('running').notNull())
|
|
34
|
-
.addColumn('goals',
|
|
35
|
-
.addColumn('memory',
|
|
36
|
-
.addColumn('findings',
|
|
33
|
+
.addColumn('status', 'varchar(50)', (col) => col.defaultTo(ctx.defaultText('running')).notNull())
|
|
34
|
+
.addColumn('goals', ctx.text, (col) => col.defaultTo(ctx.defaultText('[]')).notNull())
|
|
35
|
+
.addColumn('memory', ctx.text, (col) => col.defaultTo(ctx.defaultText('{}')).notNull())
|
|
36
|
+
.addColumn('findings', ctx.text, (col) => col.defaultTo(ctx.defaultText('[]')).notNull())
|
|
37
37
|
// What the user set out to do and how far each one got. On the run row
|
|
38
38
|
// rather than beside the steps: there are a handful of them, and every
|
|
39
39
|
// read of the run wants them.
|
|
40
|
-
.addColumn('intents',
|
|
40
|
+
.addColumn('intents', ctx.text, (col) => col.defaultTo(ctx.defaultText('[]')).notNull())
|
|
41
41
|
// Counts the engine kept: steps, calls, mutations, tokens, elapsed.
|
|
42
|
-
.addColumn('tally',
|
|
42
|
+
.addColumn('tally', ctx.text)
|
|
43
43
|
.addColumn('stoppedBy', 'varchar(255)')
|
|
44
44
|
// Why the run itself failed, as opposed to what it found.
|
|
45
|
-
.addColumn('error',
|
|
45
|
+
.addColumn('error', ctx.text)
|
|
46
46
|
.addColumn('startedBy', 'varchar(255)')
|
|
47
47
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
48
48
|
.addColumn('finishedAt', 'timestamp'),
|
|
49
49
|
// The two reads: the run list newest-first, and one persona's history when
|
|
50
50
|
// a finding needs comparing against what that persona found before.
|
|
51
|
-
(db) => db.schema
|
|
51
|
+
(db, _types, ctx) => db.schema
|
|
52
52
|
.createIndex('idx_virtual_user_run_created')
|
|
53
53
|
.on('virtualUserRun')
|
|
54
54
|
.column('createdAt'),
|
|
55
|
-
(db) => db.schema
|
|
55
|
+
(db, _types, ctx) => db.schema
|
|
56
56
|
.createIndex('idx_virtual_user_run_persona')
|
|
57
57
|
.on('virtualUserRun')
|
|
58
58
|
.columns(['persona', 'createdAt']),
|
|
@@ -62,7 +62,7 @@ export const virtualUserSchema = {
|
|
|
62
62
|
// created by the store at boot on whatever engine the project uses, and a
|
|
63
63
|
// cascade that half the engines enforce differently is worse than the read
|
|
64
64
|
// rule that a step with no run is orphaned.
|
|
65
|
-
(db) => db.schema
|
|
65
|
+
(db, _types, ctx) => db.schema
|
|
66
66
|
.createTable('virtualUserRunStep')
|
|
67
67
|
.addColumn('runId', 'varchar(36)', (col) => col.notNull())
|
|
68
68
|
// The engine's own step number, which is what the intent records point
|
|
@@ -72,7 +72,7 @@ export const virtualUserSchema = {
|
|
|
72
72
|
.addColumn('intentId', 'varchar(255)')
|
|
73
73
|
// The action as the engine scheduled it, including the `invalid` shape
|
|
74
74
|
// for a turn the model got wrong — that turn is the interesting one.
|
|
75
|
-
.addColumn('action',
|
|
75
|
+
.addColumn('action', ctx.text, (col) => col.notNull())
|
|
76
76
|
.addColumn('status', 'integer')
|
|
77
77
|
// 0 or 1 rather than a boolean, because a bare sqlite driver cannot
|
|
78
78
|
// bind one at all and `SerializePlugin` is not installed everywhere.
|
|
@@ -81,8 +81,8 @@ export const virtualUserSchema = {
|
|
|
81
81
|
// raw: a truncated API response usually starts with a brace, which
|
|
82
82
|
// `SerializePlugin` would read back as an object rather than the string
|
|
83
83
|
// the engine actually saw.
|
|
84
|
-
.addColumn('response',
|
|
85
|
-
.addColumn('findingKinds',
|
|
84
|
+
.addColumn('response', ctx.text)
|
|
85
|
+
.addColumn('findingKinds', ctx.text)
|
|
86
86
|
.addColumn('tokensIn', 'integer', (col) => col.defaultTo(0).notNull())
|
|
87
87
|
.addColumn('tokensOut', 'integer', (col) => col.defaultTo(0).notNull())
|
|
88
88
|
.addPrimaryKeyConstraint('pk_virtual_user_run_step', [
|
|
@@ -4,34 +4,34 @@ export const webhookSchema = {
|
|
|
4
4
|
name: 'webhook',
|
|
5
5
|
ownedBy: ['webhookService'],
|
|
6
6
|
statements: [
|
|
7
|
-
(db) => db.schema
|
|
7
|
+
(db, _types, ctx) => db.schema
|
|
8
8
|
.createTable('webhookDelivery')
|
|
9
|
-
.addColumn('deliveryId',
|
|
10
|
-
.addColumn('organizationId',
|
|
11
|
-
.addColumn('url',
|
|
12
|
-
.addColumn('event',
|
|
13
|
-
.addColumn('status',
|
|
9
|
+
.addColumn('deliveryId', ctx.key, (col) => col.primaryKey())
|
|
10
|
+
.addColumn('organizationId', ctx.key)
|
|
11
|
+
.addColumn('url', ctx.text, (col) => col.notNull())
|
|
12
|
+
.addColumn('event', ctx.text)
|
|
13
|
+
.addColumn('status', ctx.text, (col) => col.defaultTo(ctx.defaultText('pending')).notNull())
|
|
14
14
|
.addColumn('attempts', 'integer', (col) => col.defaultTo(0).notNull())
|
|
15
15
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
16
16
|
.addColumn('updatedAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
17
17
|
.addColumn('deliveredAt', 'timestamp'),
|
|
18
|
-
(db) => db.schema
|
|
18
|
+
(db, _types, ctx) => db.schema
|
|
19
19
|
.createTable('webhookDeliveryAttempt')
|
|
20
|
-
.addColumn('attemptId',
|
|
21
|
-
.addColumn('deliveryId',
|
|
22
|
-
.notNull()
|
|
23
|
-
.references('webhookDelivery.deliveryId')
|
|
24
|
-
.onDelete('cascade'))
|
|
20
|
+
.addColumn('attemptId', ctx.key, (col) => col.primaryKey())
|
|
21
|
+
.addColumn('deliveryId', ctx.key, (col) => ctx.references(col.notNull(), 'webhookDelivery.deliveryId'))
|
|
25
22
|
.addColumn('attemptNumber', 'integer', (col) => col.notNull())
|
|
26
23
|
.addColumn('statusCode', 'integer')
|
|
27
|
-
.addColumn('responseBody',
|
|
28
|
-
.addColumn('error',
|
|
29
|
-
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
30
|
-
|
|
24
|
+
.addColumn('responseBody', ctx.text)
|
|
25
|
+
.addColumn('error', ctx.text)
|
|
26
|
+
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
27
|
+
.$call(ctx.foreignKeys('webhookDeliveryAttempt', {
|
|
28
|
+
deliveryId: 'webhookDelivery.deliveryId',
|
|
29
|
+
})),
|
|
30
|
+
(db, _types, ctx) => db.schema
|
|
31
31
|
.createIndex('idx_webhook_delivery_org')
|
|
32
32
|
.on('webhookDelivery')
|
|
33
33
|
.column('organizationId'),
|
|
34
|
-
(db) => db.schema
|
|
34
|
+
(db, _types, ctx) => db.schema
|
|
35
35
|
.createIndex('idx_webhook_delivery_attempt_delivery')
|
|
36
36
|
.on('webhookDeliveryAttempt')
|
|
37
37
|
.column('deliveryId'),
|
|
@@ -18,40 +18,37 @@ export const workflowSchema = {
|
|
|
18
18
|
name: 'workflow',
|
|
19
19
|
ownedBy: ['workflowService', 'workflowRunService'],
|
|
20
20
|
statements: [
|
|
21
|
-
(db) => db.schema
|
|
21
|
+
(db, _types, ctx) => db.schema
|
|
22
22
|
.createTable('workflowRuns')
|
|
23
|
-
.addColumn('workflowRunId',
|
|
24
|
-
.addColumn('workflow',
|
|
25
|
-
.addColumn('status',
|
|
26
|
-
.addColumn('input',
|
|
27
|
-
.addColumn('output',
|
|
28
|
-
.addColumn('error',
|
|
29
|
-
.addColumn('state',
|
|
23
|
+
.addColumn('workflowRunId', ctx.key, (col) => col.primaryKey())
|
|
24
|
+
.addColumn('workflow', ctx.key, (col) => col.notNull())
|
|
25
|
+
.addColumn('status', ctx.key, (col) => col.notNull())
|
|
26
|
+
.addColumn('input', ctx.text, (col) => col.notNull())
|
|
27
|
+
.addColumn('output', ctx.text)
|
|
28
|
+
.addColumn('error', ctx.text)
|
|
29
|
+
.addColumn('state', ctx.text, (col) => col.defaultTo(ctx.defaultText('{}')))
|
|
30
30
|
.addColumn('inline', 'boolean', (col) => col.defaultTo(false))
|
|
31
|
-
.addColumn('graphHash',
|
|
31
|
+
.addColumn('graphHash', ctx.key)
|
|
32
32
|
.addColumn('deterministic', 'boolean', (col) => col.defaultTo(false))
|
|
33
|
-
.addColumn('plannedSteps',
|
|
34
|
-
.addColumn('wire',
|
|
33
|
+
.addColumn('plannedSteps', ctx.text)
|
|
34
|
+
.addColumn('wire', ctx.text)
|
|
35
35
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
36
36
|
.addColumn('updatedAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull()),
|
|
37
|
-
(db) => db.schema
|
|
37
|
+
(db, _types, ctx) => db.schema
|
|
38
38
|
.createTable('workflowStep')
|
|
39
|
-
.addColumn('workflowStepId',
|
|
40
|
-
.addColumn('workflowRunId',
|
|
41
|
-
.notNull()
|
|
42
|
-
.
|
|
43
|
-
.
|
|
44
|
-
.addColumn('
|
|
45
|
-
.addColumn('
|
|
46
|
-
.addColumn('
|
|
47
|
-
.addColumn('
|
|
48
|
-
.addColumn('
|
|
49
|
-
.addColumn('error', 'text')
|
|
50
|
-
.addColumn('childRunId', 'text')
|
|
51
|
-
.addColumn('branchTaken', 'text')
|
|
39
|
+
.addColumn('workflowStepId', ctx.key, (col) => col.primaryKey())
|
|
40
|
+
.addColumn('workflowRunId', ctx.key, (col) => ctx.references(col.notNull(), 'workflowRuns.workflowRunId'))
|
|
41
|
+
.addColumn('stepName', ctx.key, (col) => col.notNull())
|
|
42
|
+
.addColumn('rpcName', ctx.text)
|
|
43
|
+
.addColumn('data', ctx.text)
|
|
44
|
+
.addColumn('status', ctx.key, (col) => col.notNull().defaultTo(ctx.defaultText('pending')))
|
|
45
|
+
.addColumn('result', ctx.text)
|
|
46
|
+
.addColumn('error', ctx.text)
|
|
47
|
+
.addColumn('childRunId', ctx.text)
|
|
48
|
+
.addColumn('branchTaken', ctx.text)
|
|
52
49
|
.addColumn('retries', 'integer')
|
|
53
|
-
.addColumn('retryDelay',
|
|
54
|
-
.addColumn('fromStepName',
|
|
50
|
+
.addColumn('retryDelay', ctx.text)
|
|
51
|
+
.addColumn('fromStepName', ctx.text)
|
|
55
52
|
.addColumn('currentAttempt', 'integer')
|
|
56
53
|
.addColumn('leaseExpiresAt', 'bigint')
|
|
57
54
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
@@ -59,30 +56,33 @@ export const workflowSchema = {
|
|
|
59
56
|
.addUniqueConstraint('workflow_step_run_name_unique', [
|
|
60
57
|
'workflowRunId',
|
|
61
58
|
'stepName',
|
|
62
|
-
])
|
|
63
|
-
|
|
59
|
+
])
|
|
60
|
+
.$call(ctx.foreignKeys('workflowStep', {
|
|
61
|
+
workflowRunId: 'workflowRuns.workflowRunId',
|
|
62
|
+
})),
|
|
63
|
+
(db, _types, ctx) => db.schema
|
|
64
64
|
.createTable('workflowStepHistory')
|
|
65
|
-
.addColumn('historyId',
|
|
66
|
-
.addColumn('workflowStepId',
|
|
67
|
-
.notNull()
|
|
68
|
-
.
|
|
69
|
-
.
|
|
70
|
-
.addColumn('status', 'text', (col) => col.notNull())
|
|
71
|
-
.addColumn('result', 'text')
|
|
72
|
-
.addColumn('error', 'text')
|
|
65
|
+
.addColumn('historyId', ctx.key, (col) => col.primaryKey())
|
|
66
|
+
.addColumn('workflowStepId', ctx.key, (col) => ctx.references(col.notNull(), 'workflowStep.workflowStepId'))
|
|
67
|
+
.addColumn('status', ctx.key, (col) => col.notNull())
|
|
68
|
+
.addColumn('result', ctx.text)
|
|
69
|
+
.addColumn('error', ctx.text)
|
|
73
70
|
.addColumn('attempt', 'integer')
|
|
74
71
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
75
72
|
.addColumn('runningAt', 'timestamp')
|
|
76
73
|
.addColumn('scheduledAt', 'timestamp')
|
|
77
74
|
.addColumn('succeededAt', 'timestamp')
|
|
78
|
-
.addColumn('failedAt', 'timestamp')
|
|
79
|
-
|
|
75
|
+
.addColumn('failedAt', 'timestamp')
|
|
76
|
+
.$call(ctx.foreignKeys('workflowStepHistory', {
|
|
77
|
+
workflowStepId: 'workflowStep.workflowStepId',
|
|
78
|
+
})),
|
|
79
|
+
(db, _types, ctx) => db.schema
|
|
80
80
|
.createTable('workflowVersions')
|
|
81
|
-
.addColumn('workflowName',
|
|
82
|
-
.addColumn('graphHash',
|
|
83
|
-
.addColumn('graph',
|
|
84
|
-
.addColumn('source',
|
|
85
|
-
.addColumn('status',
|
|
81
|
+
.addColumn('workflowName', ctx.key, (col) => col.notNull())
|
|
82
|
+
.addColumn('graphHash', ctx.key, (col) => col.notNull())
|
|
83
|
+
.addColumn('graph', ctx.text, (col) => col.notNull())
|
|
84
|
+
.addColumn('source', ctx.key, (col) => col.notNull())
|
|
85
|
+
.addColumn('status', ctx.key, (col) => col.notNull().defaultTo(ctx.defaultText('active')))
|
|
86
86
|
.addColumn('createdAt', 'timestamp', (col) => col.defaultTo(sql `CURRENT_TIMESTAMP`).notNull())
|
|
87
87
|
.addPrimaryKeyConstraint('workflow_versions_pk', [
|
|
88
88
|
'workflowName',
|
|
@@ -90,23 +90,23 @@ export const workflowSchema = {
|
|
|
90
90
|
]),
|
|
91
91
|
// The indexes trail the tables so that a table is never indexed before it
|
|
92
92
|
// exists, whatever order the declarations are read in.
|
|
93
|
-
(db) => db.schema
|
|
93
|
+
(db, _types, ctx) => db.schema
|
|
94
94
|
.createIndex('idx_workflow_runs_status_created')
|
|
95
95
|
.on('workflowRuns')
|
|
96
96
|
.columns(['status', 'createdAt']),
|
|
97
|
-
(db) => db.schema
|
|
97
|
+
(db, _types, ctx) => db.schema
|
|
98
98
|
.createIndex('idx_workflow_runs_workflow_created')
|
|
99
99
|
.on('workflowRuns')
|
|
100
100
|
.columns(['workflow', 'createdAt']),
|
|
101
|
-
(db) => db.schema
|
|
101
|
+
(db, _types, ctx) => db.schema
|
|
102
102
|
.createIndex('idx_workflow_step_run_status')
|
|
103
103
|
.on('workflowStep')
|
|
104
104
|
.columns(['workflowRunId', 'status']),
|
|
105
|
-
(db) => db.schema
|
|
105
|
+
(db, _types, ctx) => db.schema
|
|
106
106
|
.createIndex('idx_workflow_step_history_step')
|
|
107
107
|
.on('workflowStepHistory')
|
|
108
108
|
.columns(['workflowStepId', 'createdAt']),
|
|
109
|
-
(db) => db.schema
|
|
109
|
+
(db, _types, ctx) => db.schema
|
|
110
110
|
.createIndex('idx_workflow_versions_source_status')
|
|
111
111
|
.on('workflowVersions')
|
|
112
112
|
.columns(['source', 'status']),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/kysely",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.34",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/pikkujs/pikku.git",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"prepublishOnly": "bun run build"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
|
-
"@pikku/core": "^0.12.
|
|
29
|
+
"@pikku/core": "^0.12.136"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"kysely": "^0.29.5"
|