@pepys/schema 0.0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pepys/schema",
3
- "version": "0.0.1",
3
+ "version": "0.1.1",
4
4
  "description": "The pepys consumer manifest: the types and the strict schema of consumers.json, with its shared case file",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -19,7 +19,7 @@
19
19
  "access": "public"
20
20
  },
21
21
  "dependencies": {
22
- "@pepys/kit": "0.0.1",
22
+ "@pepys/kit": "0.1.1",
23
23
  "@zgeoff/std": "0.4.3",
24
24
  "ts-pattern": "5.9.2",
25
25
  "zod": "4.6.7"
@@ -16,6 +16,7 @@ const reservedTableNames = new Set([
16
16
  'change_log',
17
17
  'applied_facts',
18
18
  'scope_row',
19
+ 'scope_fact',
19
20
  ]);
20
21
 
21
22
  const hashSchema = z.custom<VersionHash>(
@@ -8,10 +8,10 @@
8
8
  "consumers": [
9
9
  {
10
10
  "name": "github_pull_request",
11
- "module": "a25e6b685249d115d765f543ff3ed84fea7b8a52dfff3fa04a23a7bdf4897b02",
12
- "path": "github_pull_request/a25e6b685249d115d765f543ff3ed84fea7b8a52dfff3fa04a23a7bdf4897b02.wasm",
11
+ "module": "6898a97f1d34f1bb912cf8d137376c27b5548565af9f60e338c7cdfcfad3c3cc",
12
+ "path": "github_pull_request/6898a97f1d34f1bb912cf8d137376c27b5548565af9f60e338c7cdfcfad3c3cc.wasm",
13
13
  "pins": {},
14
- "version": "8ccc9611c23dc9a1aa81ef14ad89d259672c713f92d498fcfec75900451cd291",
14
+ "version": "b533bfb21df70fa506382ebda24a2860cb32ca5df57c1327a5b942ef0fcfae4e",
15
15
  "manifest": {
16
16
  "name": "github_pull_request",
17
17
  "input": {
@@ -96,10 +96,322 @@
96
96
  },
97
97
  "primaryKey": ["id"],
98
98
  "indexes": [["repository_id"]]
99
+ },
100
+ "github_release_bump": {
101
+ "columns": {
102
+ "pull_request_id": {
103
+ "kind": "entityID",
104
+ "nullable": false
105
+ },
106
+ "release_repository": {
107
+ "kind": "text",
108
+ "nullable": false
109
+ },
110
+ "release_tag": {
111
+ "kind": "text",
112
+ "nullable": false
113
+ }
114
+ },
115
+ "primaryKey": ["pull_request_id", "release_repository", "release_tag"],
116
+ "indexes": [["release_repository", "release_tag"]]
117
+ }
118
+ },
119
+ "links": [],
120
+ "schema": "CREATE TABLE \"github_pull_request\" (\n \"id\" TEXT NOT NULL,\n \"number\" INTEGER NOT NULL,\n \"repository_id\" TEXT NOT NULL,\n \"title\" TEXT NOT NULL,\n \"state\" TEXT NOT NULL,\n \"is_draft\" INTEGER NOT NULL,\n \"is_merged\" INTEGER NOT NULL,\n \"author_id\" TEXT,\n \"url\" TEXT NOT NULL,\n \"merge_commit_sha\" TEXT,\n \"created_at\" TEXT NOT NULL,\n \"updated_at\" TEXT NOT NULL,\n \"closed_at\" TEXT,\n \"merged_at\" TEXT,\n \"payload\" TEXT NOT NULL,\n PRIMARY KEY (\"id\")\n);\n\nCREATE INDEX \"github_pull_request_repository_id_idx\" ON \"github_pull_request\" (\"repository_id\");\n\nCREATE TABLE \"github_release_bump\" (\n \"pull_request_id\" TEXT NOT NULL,\n \"release_repository\" TEXT NOT NULL,\n \"release_tag\" TEXT NOT NULL,\n PRIMARY KEY (\"pull_request_id\", \"release_repository\", \"release_tag\")\n);\n\nCREATE INDEX \"github_release_bump_release_repository_release_tag_idx\" ON \"github_release_bump\" (\"release_repository\", \"release_tag\");\n\nCREATE VIEW \"entity\" AS\nSELECT\n \"id\" AS \"id\",\n 'github:pull_request' AS \"kind\",\n \"title\" AS \"title\",\n \"url\" AS \"url\",\n \"author_id\" AS \"actor\",\n \"updated_at\" AS \"updated_at\"\nFROM \"github_pull_request\";\n"
121
+ }
122
+ },
123
+ {
124
+ "name": "github_release",
125
+ "module": "b0aef4796c8553963fa89fc8d854994c8fe4f85dfbb22bb6ee05dc963c41d6b6",
126
+ "path": "github_release/b0aef4796c8553963fa89fc8d854994c8fe4f85dfbb22bb6ee05dc963c41d6b6.wasm",
127
+ "pins": {},
128
+ "version": "d1d737314ec0bcaecc73f1f364bedd095cf331e2998f8a6c6f32946983d72f52",
129
+ "manifest": {
130
+ "name": "github_release",
131
+ "input": {
132
+ "mode": "fact",
133
+ "streams": ["facts.github.release"]
134
+ },
135
+ "exports": {
136
+ "init": "github_release_init",
137
+ "apply": "github_release_apply_fact"
138
+ },
139
+ "imports": [
140
+ {
141
+ "kind": "row",
142
+ "table": "github_release",
143
+ "length": "readGithubReleaseLength",
144
+ "into": "readGithubReleaseInto"
145
+ }
146
+ ],
147
+ "tables": {
148
+ "github_release": {
149
+ "columns": {
150
+ "id": {
151
+ "kind": "entityID",
152
+ "nullable": false
153
+ },
154
+ "repository_id": {
155
+ "kind": "entityID",
156
+ "nullable": false
157
+ },
158
+ "repository_full_name": {
159
+ "kind": "text",
160
+ "nullable": false
161
+ },
162
+ "tag_name": {
163
+ "kind": "text",
164
+ "nullable": false
165
+ },
166
+ "target_commitish": {
167
+ "kind": "text",
168
+ "nullable": false
169
+ },
170
+ "name": {
171
+ "kind": "text",
172
+ "nullable": false
173
+ },
174
+ "url": {
175
+ "kind": "text",
176
+ "nullable": false
177
+ },
178
+ "is_draft": {
179
+ "kind": "boolean",
180
+ "nullable": false
181
+ },
182
+ "is_prerelease": {
183
+ "kind": "boolean",
184
+ "nullable": false
185
+ },
186
+ "created_at": {
187
+ "kind": "timestamp",
188
+ "nullable": false
189
+ },
190
+ "published_at": {
191
+ "kind": "timestamp",
192
+ "nullable": true
193
+ },
194
+ "updated_at": {
195
+ "kind": "timestamp",
196
+ "nullable": false
197
+ },
198
+ "deleted_at": {
199
+ "kind": "timestamp",
200
+ "nullable": true
201
+ }
202
+ },
203
+ "primaryKey": ["id"],
204
+ "indexes": [["repository_id"], ["repository_full_name", "tag_name"]]
205
+ }
206
+ },
207
+ "links": [],
208
+ "schema": "CREATE TABLE \"github_release\" (\n \"id\" TEXT NOT NULL,\n \"repository_id\" TEXT NOT NULL,\n \"repository_full_name\" TEXT NOT NULL,\n \"tag_name\" TEXT NOT NULL,\n \"target_commitish\" TEXT NOT NULL,\n \"name\" TEXT NOT NULL,\n \"url\" TEXT NOT NULL,\n \"is_draft\" INTEGER NOT NULL,\n \"is_prerelease\" INTEGER NOT NULL,\n \"created_at\" TEXT NOT NULL,\n \"published_at\" TEXT,\n \"updated_at\" TEXT NOT NULL,\n \"deleted_at\" TEXT,\n PRIMARY KEY (\"id\")\n);\n\nCREATE INDEX \"github_release_repository_id_idx\" ON \"github_release\" (\"repository_id\");\n\nCREATE INDEX \"github_release_repository_full_name_tag_name_idx\" ON \"github_release\" (\"repository_full_name\", \"tag_name\");\n\nCREATE VIEW \"entity\" AS\nSELECT\n \"id\" AS \"id\",\n 'github:release' AS \"kind\",\n \"name\" AS \"title\",\n \"url\" AS \"url\",\n NULL AS \"actor\",\n \"updated_at\" AS \"updated_at\"\nFROM \"github_release\";\n"
209
+ }
210
+ },
211
+ {
212
+ "name": "github_ref",
213
+ "module": "5061a9e3d17544a8cdae4c96a324343e930cf8c0fdeffc118091ae86474da4c0",
214
+ "path": "github_ref/5061a9e3d17544a8cdae4c96a324343e930cf8c0fdeffc118091ae86474da4c0.wasm",
215
+ "pins": {},
216
+ "version": "3e38fef998ff484a41c13a5db4440ac605c9a0f98b36b8a60c285a20a02da9ef",
217
+ "manifest": {
218
+ "name": "github_ref",
219
+ "input": {
220
+ "mode": "fact",
221
+ "streams": ["facts.github.ref"]
222
+ },
223
+ "exports": {
224
+ "init": "github_ref_init",
225
+ "apply": "github_ref_apply_fact"
226
+ },
227
+ "imports": [],
228
+ "tables": {
229
+ "github_commit": {
230
+ "columns": {
231
+ "repository_id": {
232
+ "kind": "entityID",
233
+ "nullable": false
234
+ },
235
+ "sha": {
236
+ "kind": "text",
237
+ "nullable": false
238
+ },
239
+ "committed_at": {
240
+ "kind": "timestamp",
241
+ "nullable": false
242
+ }
243
+ },
244
+ "primaryKey": ["repository_id", "sha"],
245
+ "indexes": []
99
246
  }
100
247
  },
101
248
  "links": [],
102
- "schema": "CREATE TABLE \"github_pull_request\" (\n \"id\" TEXT NOT NULL,\n \"number\" INTEGER NOT NULL,\n \"repository_id\" TEXT NOT NULL,\n \"title\" TEXT NOT NULL,\n \"state\" TEXT NOT NULL,\n \"is_draft\" INTEGER NOT NULL,\n \"is_merged\" INTEGER NOT NULL,\n \"author_id\" TEXT,\n \"url\" TEXT NOT NULL,\n \"merge_commit_sha\" TEXT,\n \"created_at\" TEXT NOT NULL,\n \"updated_at\" TEXT NOT NULL,\n \"closed_at\" TEXT,\n \"merged_at\" TEXT,\n \"payload\" TEXT NOT NULL,\n PRIMARY KEY (\"id\")\n);\n\nCREATE INDEX \"github_pull_request_repository_id_idx\" ON \"github_pull_request\" (\"repository_id\");\n\nCREATE VIEW \"entity\" AS\nSELECT\n \"id\" AS \"id\",\n 'github:pull_request' AS \"kind\",\n \"title\" AS \"title\",\n \"url\" AS \"url\",\n \"author_id\" AS \"actor\",\n \"updated_at\" AS \"updated_at\"\nFROM \"github_pull_request\";\n"
249
+ "schema": "CREATE TABLE \"github_commit\" (\n \"repository_id\" TEXT NOT NULL,\n \"sha\" TEXT NOT NULL,\n \"committed_at\" TEXT NOT NULL,\n PRIMARY KEY (\"repository_id\", \"sha\")\n);\n"
250
+ }
251
+ },
252
+ {
253
+ "name": "github_deploy",
254
+ "module": "37d2c9701694153eebce58387f0a770019c119fc88a80d556c137d87c6a181ed",
255
+ "path": "github_deploy/37d2c9701694153eebce58387f0a770019c119fc88a80d556c137d87c6a181ed.wasm",
256
+ "pins": {},
257
+ "version": "7a7a12ff4163ed0a7af378a8550684b10590d91580347c44044988c7093aba41",
258
+ "manifest": {
259
+ "name": "github_deploy",
260
+ "input": {
261
+ "mode": "fact",
262
+ "streams": ["facts.github.ref", "facts.github.deployment"]
263
+ },
264
+ "exports": {
265
+ "init": "github_deploy_init",
266
+ "apply": "github_deploy_apply_fact"
267
+ },
268
+ "imports": [
269
+ {
270
+ "kind": "row",
271
+ "table": "github_deploy",
272
+ "length": "readGithubDeployLength",
273
+ "into": "readGithubDeployInto"
274
+ }
275
+ ],
276
+ "tables": {
277
+ "github_deploy": {
278
+ "columns": {
279
+ "id": {
280
+ "kind": "entityID",
281
+ "nullable": false
282
+ },
283
+ "repository_id": {
284
+ "kind": "entityID",
285
+ "nullable": false
286
+ },
287
+ "environment": {
288
+ "kind": "text",
289
+ "nullable": false
290
+ },
291
+ "target": {
292
+ "kind": "text",
293
+ "nullable": true
294
+ },
295
+ "sha": {
296
+ "kind": "text",
297
+ "nullable": false
298
+ },
299
+ "signal": {
300
+ "kind": "text",
301
+ "nullable": false
302
+ },
303
+ "deployed_at": {
304
+ "kind": "timestamp",
305
+ "nullable": false
306
+ }
307
+ },
308
+ "primaryKey": ["id"],
309
+ "indexes": [["repository_id", "environment"]]
310
+ }
311
+ },
312
+ "links": [],
313
+ "schema": "CREATE TABLE \"github_deploy\" (\n \"id\" TEXT NOT NULL,\n \"repository_id\" TEXT NOT NULL,\n \"environment\" TEXT NOT NULL,\n \"target\" TEXT,\n \"sha\" TEXT NOT NULL,\n \"signal\" TEXT NOT NULL,\n \"deployed_at\" TEXT NOT NULL,\n PRIMARY KEY (\"id\")\n);\n\nCREATE INDEX \"github_deploy_repository_id_environment_idx\" ON \"github_deploy\" (\"repository_id\", \"environment\");\n\nCREATE VIEW \"entity\" AS\nSELECT\n \"id\" AS \"id\",\n 'github:deploy' AS \"kind\",\n \"sha\" AS \"title\",\n NULL AS \"url\",\n NULL AS \"actor\",\n \"deployed_at\" AS \"updated_at\"\nFROM \"github_deploy\";\n"
314
+ }
315
+ },
316
+ {
317
+ "name": "ledger_account",
318
+ "module": "0b49326796795c2edd16ee3914e3a8291220891908f03e3f6246a0d2ca86ba79",
319
+ "path": "ledger_account/0b49326796795c2edd16ee3914e3a8291220891908f03e3f6246a0d2ca86ba79.wasm",
320
+ "pins": {},
321
+ "version": "5fc963ba7bcf33da678f7d8020f185693bad5619703d029afa24a03a041d56b7",
322
+ "manifest": {
323
+ "name": "ledger_account",
324
+ "input": {
325
+ "mode": "scope",
326
+ "scopeKind": "ledger:account",
327
+ "streams": ["facts.ledger.account"]
328
+ },
329
+ "exports": {
330
+ "init": "ledger_account_init",
331
+ "apply": "ledger_account_apply_scope"
332
+ },
333
+ "imports": [
334
+ {
335
+ "kind": "scope_facts",
336
+ "length": "readScopeFactsLength",
337
+ "into": "readScopeFactsInto"
338
+ }
339
+ ],
340
+ "tables": {
341
+ "ledger_account": {
342
+ "columns": {
343
+ "id": {
344
+ "kind": "entityID",
345
+ "nullable": false
346
+ },
347
+ "name": {
348
+ "kind": "text",
349
+ "nullable": true
350
+ },
351
+ "balance": {
352
+ "kind": "integer",
353
+ "nullable": false
354
+ },
355
+ "is_closed": {
356
+ "kind": "boolean",
357
+ "nullable": false
358
+ },
359
+ "opened_at": {
360
+ "kind": "timestamp",
361
+ "nullable": true
362
+ },
363
+ "updated_at": {
364
+ "kind": "timestamp",
365
+ "nullable": false
366
+ }
367
+ },
368
+ "primaryKey": ["id"],
369
+ "indexes": []
370
+ },
371
+ "ledger_entry": {
372
+ "columns": {
373
+ "id": {
374
+ "kind": "entityID",
375
+ "nullable": false
376
+ },
377
+ "account_id": {
378
+ "kind": "entityID",
379
+ "nullable": false
380
+ },
381
+ "amount": {
382
+ "kind": "integer",
383
+ "nullable": false
384
+ },
385
+ "rate": {
386
+ "kind": "real",
387
+ "nullable": false
388
+ },
389
+ "memo": {
390
+ "kind": "text",
391
+ "nullable": false
392
+ },
393
+ "details": {
394
+ "kind": "json",
395
+ "nullable": false
396
+ },
397
+ "posted_at": {
398
+ "kind": "timestamp",
399
+ "nullable": false
400
+ }
401
+ },
402
+ "primaryKey": ["id"],
403
+ "indexes": [["account_id"]]
404
+ }
405
+ },
406
+ "links": [
407
+ {
408
+ "name": "entry_of",
409
+ "from": ["ledger:entry"],
410
+ "to": ["ledger:account"],
411
+ "hub": false
412
+ }
413
+ ],
414
+ "schema": "CREATE TABLE \"ledger_account\" (\n \"id\" TEXT NOT NULL,\n \"name\" TEXT,\n \"balance\" INTEGER NOT NULL,\n \"is_closed\" INTEGER NOT NULL,\n \"opened_at\" TEXT,\n \"updated_at\" TEXT NOT NULL,\n PRIMARY KEY (\"id\")\n);\n\nCREATE TABLE \"ledger_entry\" (\n \"id\" TEXT NOT NULL,\n \"account_id\" TEXT NOT NULL,\n \"amount\" INTEGER NOT NULL,\n \"rate\" REAL NOT NULL,\n \"memo\" TEXT NOT NULL,\n \"details\" TEXT NOT NULL,\n \"posted_at\" TEXT NOT NULL,\n PRIMARY KEY (\"id\")\n);\n\nCREATE INDEX \"ledger_entry_account_id_idx\" ON \"ledger_entry\" (\"account_id\");\n\nCREATE VIEW \"entity\" AS\nSELECT\n \"id\" AS \"id\",\n 'ledger:account' AS \"kind\",\n \"name\" AS \"title\",\n NULL AS \"url\",\n NULL AS \"actor\",\n \"updated_at\" AS \"updated_at\"\nFROM \"ledger_account\"\nUNION ALL\nSELECT\n \"id\" AS \"id\",\n 'ledger:entry' AS \"kind\",\n \"memo\" AS \"title\",\n NULL AS \"url\",\n NULL AS \"actor\",\n \"posted_at\" AS \"updated_at\"\nFROM \"ledger_entry\";\n"
103
415
  }
104
416
  }
105
417
  ]
@@ -2295,6 +2607,68 @@
2295
2607
  },
2296
2608
  "isValid": false
2297
2609
  },
2610
+ {
2611
+ "title": "refuses a table named scope_fact, which the host reserves",
2612
+ "file": {
2613
+ "kit": 1,
2614
+ "deployment": "harbour",
2615
+ "consumers": [
2616
+ {
2617
+ "name": "tide_log",
2618
+ "module": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
2619
+ "path": "tide_log/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.wasm",
2620
+ "pins": {},
2621
+ "version": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
2622
+ "manifest": {
2623
+ "name": "tide_log",
2624
+ "input": {
2625
+ "mode": "fact",
2626
+ "streams": ["facts.harbour.tide"]
2627
+ },
2628
+ "exports": {
2629
+ "init": "tide_log_init",
2630
+ "apply": "tide_log_apply_fact"
2631
+ },
2632
+ "imports": [
2633
+ {
2634
+ "kind": "row",
2635
+ "table": "scope_fact",
2636
+ "length": "readTideReadingLength",
2637
+ "into": "readTideReadingInto"
2638
+ }
2639
+ ],
2640
+ "tables": {
2641
+ "scope_fact": {
2642
+ "columns": {
2643
+ "id": {
2644
+ "kind": "entityID",
2645
+ "nullable": false
2646
+ },
2647
+ "height_cm": {
2648
+ "kind": "integer",
2649
+ "nullable": false
2650
+ },
2651
+ "note": {
2652
+ "kind": "text",
2653
+ "nullable": true
2654
+ },
2655
+ "read_at": {
2656
+ "kind": "timestamp",
2657
+ "nullable": false
2658
+ }
2659
+ },
2660
+ "primaryKey": ["id"],
2661
+ "indexes": [["read_at"]]
2662
+ }
2663
+ },
2664
+ "links": [],
2665
+ "schema": "CREATE TABLE \"tide_reading\" (\n \"id\" TEXT NOT NULL\n);\n"
2666
+ }
2667
+ }
2668
+ ]
2669
+ },
2670
+ "isValid": false
2671
+ },
2298
2672
  {
2299
2673
  "title": "refuses a link type declared twice",
2300
2674
  "file": {
@@ -18,6 +18,69 @@ export interface GithubPullRequestRow {
18
18
  payload: unknown;
19
19
  }
20
20
 
21
+ export interface GithubReleaseBumpRow {
22
+ pull_request_id: string;
23
+ release_repository: string;
24
+ release_tag: string;
25
+ }
26
+
27
+ export interface GithubReleaseRow {
28
+ id: string;
29
+ repository_id: string;
30
+ repository_full_name: string;
31
+ tag_name: string;
32
+ target_commitish: string;
33
+ name: string;
34
+ url: string;
35
+ is_draft: 0 | 1;
36
+ is_prerelease: 0 | 1;
37
+ created_at: string;
38
+ published_at: string | null;
39
+ updated_at: string;
40
+ deleted_at: string | null;
41
+ }
42
+
43
+ export interface GithubCommitRow {
44
+ repository_id: string;
45
+ sha: string;
46
+ committed_at: string;
47
+ }
48
+
49
+ export interface GithubDeployRow {
50
+ id: string;
51
+ repository_id: string;
52
+ environment: string;
53
+ target: string | null;
54
+ sha: string;
55
+ signal: string;
56
+ deployed_at: string;
57
+ }
58
+
59
+ export interface LedgerAccountRow {
60
+ id: string;
61
+ name: string | null;
62
+ balance: number;
63
+ is_closed: 0 | 1;
64
+ opened_at: string | null;
65
+ updated_at: string;
66
+ }
67
+
68
+ export interface LedgerEntryRow {
69
+ id: string;
70
+ account_id: string;
71
+ amount: number;
72
+ rate: number;
73
+ memo: string;
74
+ details: unknown;
75
+ posted_at: string;
76
+ }
77
+
21
78
  export interface DB {
22
79
  github_pull_request: GithubPullRequestRow;
80
+ github_release_bump: GithubReleaseBumpRow;
81
+ github_release: GithubReleaseRow;
82
+ github_commit: GithubCommitRow;
83
+ github_deploy: GithubDeployRow;
84
+ ledger_account: LedgerAccountRow;
85
+ ledger_entry: LedgerEntryRow;
23
86
  }
package/src/index.ts CHANGED
@@ -2,7 +2,6 @@ export { consumerBuildManifestSchema } from './consumer-manifest/consumer-build-
2
2
  export type * from './consumer-execution/types.ts';
3
3
  export type * from './consumer-manifest/types.ts';
4
4
  export { generateKyselyTypes } from './generators/generate-kysely-types.ts';
5
- export { generateRustTypes } from './generators/generate-rust-types.ts';
6
5
  export type { DB } from './generated/kysely-db.ts';
7
6
  export { isEntityOfKind } from './link-registry/is-entity-of-kind.ts';
8
7
  export type * from './link-registry/link-registry.ts';
@@ -1,269 +0,0 @@
1
- import type { ColumnDeclaration, ConsumerDeclaration, TableDeclaration } from '@pepys/kit';
2
- import { toPascalCase } from '@pepys/kit/generators';
3
- import { match } from 'ts-pattern';
4
- import { toSnakeCase } from './to-snake-case.ts';
5
-
6
- export function generateRustTypes(consumers: readonly ConsumerDeclaration[]): string {
7
- const items = [
8
- [
9
- '#[derive(Debug, Clone, Copy, PartialEq, Eq)]',
10
- 'pub struct ReadImport {',
11
- " pub table: &'static str,",
12
- " pub length: &'static str,",
13
- " pub into: &'static str,",
14
- '}',
15
- ].join('\n'),
16
- [
17
- '#[derive(Debug, Clone, Copy, PartialEq, Eq)]',
18
- 'pub enum ColumnKind {',
19
- ' Text,',
20
- ' Integer,',
21
- ' Real,',
22
- ' Boolean,',
23
- ' Json,',
24
- ' EntityId,',
25
- ' Timestamp,',
26
- '}',
27
- ].join('\n'),
28
- [
29
- '#[derive(Debug, Clone, Copy, PartialEq, Eq)]',
30
- 'pub struct ColumnInfo {',
31
- " pub name: &'static str,",
32
- ' pub kind: ColumnKind,',
33
- ' pub nullable: bool,',
34
- '}',
35
- ].join('\n'),
36
- [
37
- '#[derive(Debug, Clone, Copy, PartialEq, Eq)]',
38
- 'pub struct TableInfo {',
39
- " pub name: &'static str,",
40
- " pub columns: &'static [ColumnInfo],",
41
- " pub primary_key: &'static [&'static str],",
42
- '}',
43
- ].join('\n'),
44
- ...consumers.flatMap((consumer) => formatConsumer(consumer)),
45
- ];
46
-
47
- return `${items.join('\n\n')}\n`;
48
- }
49
-
50
- const derives = '#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]';
51
-
52
- function formatConsumer(consumer: ConsumerDeclaration): string[] {
53
- const tables = Object.entries(consumer.tables);
54
- const consumerName = toPascalCase(consumer.name);
55
-
56
- return [
57
- ...tables.flatMap(([name, table]) => [
58
- formatStruct(`${toPascalCase(name)}Row`, table, Object.keys(table.columns)),
59
- formatStruct(`${toPascalCase(name)}Key`, table, table.primaryKey),
60
- ]),
61
- formatTableEnum(`${consumerName}Upsert`, tables, 'Row'),
62
- formatTableEnum(`${consumerName}Delete`, tables, 'Key'),
63
- [
64
- derives,
65
- '#[serde(rename_all = "snake_case")]',
66
- `pub enum ${consumerName}Operation {`,
67
- ` Upsert(Box<${consumerName}Upsert>),`,
68
- ` Delete(${consumerName}Delete),`,
69
- '}',
70
- ].join('\n'),
71
- formatTables(consumer),
72
- formatReads(consumer),
73
- ];
74
- }
75
-
76
- function formatStruct(
77
- structName: string,
78
- table: TableDeclaration,
79
- columnNames: readonly string[],
80
- ): string {
81
- const fields = columnNames.flatMap((columnName) => {
82
- const column = table.columns[columnName];
83
-
84
- return column === undefined ? [] : formatField(columnName, column);
85
- });
86
-
87
- return [derives, `pub struct ${structName} {`, ...fields, '}'].join('\n');
88
- }
89
-
90
- function formatField(columnName: string, column: ColumnDeclaration): string[] {
91
- const snakeName = toSnakeCase(columnName);
92
- const identifier = toRustIdentifier(snakeName);
93
- const rename = identifier.replace(/^r#/u, '') === columnName ? [] : [columnName];
94
- const type = toRustType(column);
95
-
96
- return [
97
- ...rename.map((sqlName) => ` #[serde(rename = "${sqlName}")]`),
98
- ` pub ${identifier}: ${type},`,
99
- ];
100
- }
101
-
102
- const rawIdentifiers = new Set([
103
- 'abstract',
104
- 'as',
105
- 'async',
106
- 'await',
107
- 'become',
108
- 'box',
109
- 'break',
110
- 'const',
111
- 'continue',
112
- 'do',
113
- 'dyn',
114
- 'else',
115
- 'enum',
116
- 'extern',
117
- 'false',
118
- 'final',
119
- 'fn',
120
- 'for',
121
- 'gen',
122
- 'if',
123
- 'impl',
124
- 'in',
125
- 'let',
126
- 'loop',
127
- 'macro',
128
- 'match',
129
- 'mod',
130
- 'move',
131
- 'mut',
132
- 'override',
133
- 'priv',
134
- 'pub',
135
- 'ref',
136
- 'return',
137
- 'static',
138
- 'struct',
139
- 'trait',
140
- 'true',
141
- 'try',
142
- 'type',
143
- 'typeof',
144
- 'unsafe',
145
- 'unsized',
146
- 'use',
147
- 'virtual',
148
- 'where',
149
- 'while',
150
- 'yield',
151
- ]);
152
-
153
- const unescapableIdentifiers = new Set(['crate', 'self', 'Self', 'super']);
154
-
155
- function toRustIdentifier(name: string): string {
156
- if (unescapableIdentifiers.has(name)) {
157
- return `${name}_`;
158
- }
159
-
160
- return rawIdentifiers.has(name) ? `r#${name}` : name;
161
- }
162
-
163
- function toRustType(column: ColumnDeclaration): string {
164
- const type = match(column.kind)
165
- .with('text', 'entityID', 'timestamp', () => 'String')
166
- .with('integer', () => 'i64')
167
- .with('real', () => 'f64')
168
- .with('boolean', () => 'bool')
169
- .with('json', () => 'serde_json::Value')
170
- .exhaustive();
171
-
172
- return column.nullable === true ? `Option<${type}>` : type;
173
- }
174
-
175
- function formatTableEnum(
176
- enumName: string,
177
- tables: readonly (readonly [string, TableDeclaration])[],
178
- payloadSuffix: 'Row' | 'Key',
179
- ): string {
180
- const variants = tables.flatMap(([name]) => [
181
- ` #[serde(rename = "${name}")]`,
182
- ` ${toPascalCase(name)}(${toPascalCase(name)}${payloadSuffix}),`,
183
- ]);
184
-
185
- return [derives, `pub enum ${enumName} {`, ...variants, '}'].join('\n');
186
- }
187
-
188
- function formatTables(consumer: ConsumerDeclaration): string {
189
- const tables = Object.entries(consumer.tables);
190
- const constantName = `${toSnakeCase(consumer.name).toUpperCase()}_TABLES`;
191
-
192
- const entries = tables.flatMap(([name, table]) => [
193
- 'TableInfo {',
194
- ` name: "${name}",`,
195
- ' columns: &[',
196
- ...Object.entries(table.columns).flatMap(([columnName, column]) =>
197
- formatColumnInfo(columnName, column).map((line) => ` ${line}`),
198
- ),
199
- ' ],',
200
- ` primary_key: &[${table.primaryKey.map((columnName) => `"${columnName}"`).join(', ')}],`,
201
- '},',
202
- ]);
203
-
204
- // rustfmt hugs the brackets around a lone element and puts each of several on its own lines.
205
- if (tables.length === 1) {
206
- return [
207
- `pub const ${constantName}: [TableInfo; 1] = [${entries[0]}`,
208
- ...entries.slice(1, -1),
209
- '}];',
210
- ].join('\n');
211
- }
212
-
213
- return [
214
- `pub const ${constantName}: [TableInfo; ${tables.length}] = [`,
215
- ...entries.map((line) => ` ${line}`),
216
- '];',
217
- ].join('\n');
218
- }
219
-
220
- function formatColumnInfo(columnName: string, column: ColumnDeclaration): string[] {
221
- const kind = match(column.kind)
222
- .with('text', () => 'Text')
223
- .with('integer', () => 'Integer')
224
- .with('real', () => 'Real')
225
- .with('boolean', () => 'Boolean')
226
- .with('json', () => 'Json')
227
- .with('entityID', () => 'EntityId')
228
- .with('timestamp', () => 'Timestamp')
229
- .exhaustive();
230
-
231
- return [
232
- 'ColumnInfo {',
233
- ` name: "${columnName}",`,
234
- ` kind: ColumnKind::${kind},`,
235
- ` nullable: ${column.nullable === true ? 'true' : 'false'},`,
236
- '},',
237
- ];
238
- }
239
-
240
- function formatReads(consumer: ConsumerDeclaration): string {
241
- const constantName = `${toSnakeCase(consumer.name).toUpperCase()}_READS`;
242
- const declaration = `pub const ${constantName}: [ReadImport; ${consumer.reads.length}] =`;
243
-
244
- if (consumer.reads.length === 0) {
245
- return `${declaration} [];`;
246
- }
247
-
248
- const imports = consumer.reads.map((table) =>
249
- [
250
- 'ReadImport {',
251
- ` table: "${table}",`,
252
- ` length: "read${toPascalCase(table)}Length",`,
253
- ` into: "read${toPascalCase(table)}Into",`,
254
- '}',
255
- ].join('\n'),
256
- );
257
-
258
- // rustfmt hugs the brackets around a lone element and puts each of several on its own lines.
259
- if (imports.length === 1) {
260
- return `${declaration} [${imports.join('')}];`;
261
- }
262
-
263
- const lines = imports
264
- .map((entry) => `${entry},`)
265
- .join('\n')
266
- .split('\n');
267
-
268
- return [`${declaration} [`, ...lines.map((line) => ` ${line}`), '];'].join('\n');
269
- }
@@ -1,6 +0,0 @@
1
- export function toSnakeCase(name: string): string {
2
- return name
3
- .replaceAll(/(?<lower>[a-z0-9])(?<upper>[A-Z])/gu, '$<lower>_$<upper>')
4
- .replaceAll(/[^A-Za-z0-9]+/gu, '_')
5
- .toLowerCase();
6
- }