okmodel 0.7.0 → 0.9.0
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 +14 -0
- package/dist/adapters/capabilities.d.ts +32 -0
- package/dist/adapters/failure.d.ts +1 -1
- package/dist/adapters/pg/bun-sql.d.ts +53 -0
- package/dist/adapters/pg/bunsql-extra.d.ts +1 -1
- package/dist/adapters/pg/bunsql.d.ts +1 -1
- package/dist/adapters/pg/neon-extra.d.ts +18 -0
- package/dist/adapters/pg/neon.d.ts +104 -0
- package/dist/adapters/pg/no-inflight-timeout.d.ts +1 -1
- package/dist/contracts/error.d.ts +1 -1
- package/dist/dialects/pg/ext/btree-gin.d.ts +26 -0
- package/dist/dialects/pg/ext/btree-gin.js +20 -0
- package/dist/dialects/pg/ext/btree-gist.d.ts +26 -0
- package/dist/dialects/pg/ext/btree-gist.js +20 -0
- package/dist/dialects/pg/ext/call.d.ts +53 -0
- package/dist/dialects/pg/ext/citext.js +1 -1
- package/dist/dialects/pg/ext/feature.d.ts +26 -0
- package/dist/dialects/pg/ext/fuzzystrmatch.d.ts +34 -0
- package/dist/dialects/pg/ext/fuzzystrmatch.js +33 -0
- package/dist/dialects/pg/ext/hstore.d.ts +41 -0
- package/dist/dialects/pg/ext/hstore.js +29 -0
- package/dist/dialects/pg/ext/index.d.ts +56 -0
- package/dist/dialects/pg/ext/index.js +1 -1
- package/dist/dialects/pg/ext/ltree.d.ts +41 -0
- package/dist/dialects/pg/ext/ltree.js +29 -0
- package/dist/dialects/pg/ext/pg-trgm.js +4 -13
- package/dist/dialects/pg/ext/pgcrypto.d.ts +33 -0
- package/dist/dialects/pg/ext/pgcrypto.js +33 -0
- package/dist/dialects/pg/ext/unaccent.d.ts +26 -0
- package/dist/dialects/pg/ext/unaccent.js +21 -0
- package/dist/dialects/pg/ext/using.d.ts +23 -0
- package/dist/dialects/pg/ext/versions.d.ts +36 -0
- package/dist/dialects/pg/external.d.ts +19 -0
- package/dist/dialects/pg/fn/index.d.ts +39 -1
- package/dist/dialects/pg/fn/index.js +118 -26
- package/dist/dialects/pg/index.d.ts +3 -0
- package/dist/dialects/pg/index.js +394 -14
- package/dist/dialects/pg/introspect.d.ts +11 -0
- package/dist/dialects/pg/operators.d.ts +1 -1
- package/dist/dialects/pg/ops/fragment.d.ts +119 -0
- package/dist/dialects/pg/ops/lane.d.ts +49 -0
- package/dist/dialects/pg/view/client.d.ts +14 -6
- package/dist/dialects/pg/view/index.d.ts +73 -1
- package/dist/dialects/pg/view/index.js +156 -5
- package/dist/dialects/pg/view/scratch.d.ts +11 -5
- package/dist/runtime/artifact-file.d.ts +22 -0
- package/dist/runtime/client.d.ts +10 -0
- package/dist/runtime/drift-detail.d.ts +2 -1
- package/dist/runtime/drift.d.ts +3 -10
- package/dist/runtime/otel.d.ts +105 -0
- package/dist/runtime/otel.js +97 -0
- package/dist/runtime/pg/bun.js +4 -4
- package/dist/runtime/pg/neon.d.ts +38 -0
- package/dist/runtime/pg/neon.js +64 -0
- package/dist/runtime/pg/pg.js +4 -4
- package/dist/runtime/pg/pglite.js +4 -4
- package/dist/runtime/pg/postgresjs.js +4 -4
- package/dist/runtime/plan.d.ts +1 -1
- package/dist/runtime/server-check.d.ts +36 -6
- package/dist/runtime/sql-fragment.d.ts +43 -0
- package/dist/runtime/tenancy/index.js +10 -10
- package/dist/runtime/topology.d.ts +1 -1
- package/dist/runtime/traits/index.js +16 -17
- package/dist/runtime/types.d.ts +15 -1
- package/dist/runtime/validate/index.js +4 -4
- package/dist/shared/{81ebdx9p.js → 0j6qe91y.js} +4 -4
- package/dist/shared/{qq3899ht.js → 12z7aznj.js} +243 -14
- package/dist/shared/{gzaveazc.js → 1d9q9cv2.js} +29 -2
- package/dist/shared/{w79hsckn.js → 1mxm04fy.js} +5 -5
- package/dist/shared/{7k9grvf6.js → 2szgv6yj.js} +5 -5
- package/dist/shared/{gs74dbj5.js → 2zdxkt7b.js} +933 -111
- package/dist/shared/{m6p12kbr.js → 3456242y.js} +23 -23
- package/dist/shared/3bb7wsqt.js +99 -0
- package/dist/shared/{y6njgyda.js → 3t6kw83m.js} +2 -2
- package/dist/shared/{xhfsfkgk.js → 4vbf83xx.js} +9 -2
- package/dist/shared/{pt94kz7f.js → 5kyb3tqx.js} +1 -1
- package/dist/shared/61bmrmhr.js +35 -0
- package/dist/shared/{x933k9a3.js → 62b603gr.js} +10 -10
- package/dist/shared/{jgqj11w4.js → 6f0z3hzh.js} +4 -0
- package/dist/shared/{tsvww22q.js → 6nae0spm.js} +156 -95
- package/dist/shared/{mtaszv5a.js → 71n0jmhc.js} +102 -4
- package/dist/shared/{5e3tf63j.js → 760ppr76.js} +14 -6
- package/dist/shared/7ba5h6pb.js +17 -0
- package/dist/shared/{sfz1ksn6.js → 8jesqsrk.js} +2 -2
- package/dist/shared/{5v3xf80k.js → 8n688yjg.js} +1 -1
- package/dist/shared/{rs73fca9.js → 8qzkd9f3.js} +6 -6
- package/dist/shared/{ax7qv55k.js → 90sg0w5a.js} +202 -25
- package/dist/shared/{zm0ptry0.js → 99qp9vtg.js} +1 -1
- package/dist/shared/{xnxsed62.js → 9dr2qnx7.js} +14 -14
- package/dist/shared/{1w508jbr.js → 9dtgn1z2.js} +21 -17
- package/dist/shared/{h15jx9bc.js → 9dvh1dr6.js} +1 -1
- package/dist/shared/{q5c6ngn3.js → a62rb2da.js} +1 -1
- package/dist/shared/{te5as7z7.js → aksb89mn.js} +3 -3
- package/dist/shared/{bz84tkzm.js → bphrgwz9.js} +2 -2
- package/dist/shared/bsek72fg.js +225 -0
- package/dist/shared/{7mnme5tn.js → c3mvnq7a.js} +1 -1
- package/dist/shared/{p6qc5gcp.js → ccsmhv9r.js} +25 -7
- package/dist/shared/{pbp1ss85.js → cexb7z6b.js} +2 -2
- package/dist/shared/{ab9gmbwy.js → cf8zdz5p.js} +5 -5
- package/dist/shared/{jvd0mqag.js → ckz05z15.js} +5 -5
- package/dist/shared/{dk8v79p3.js → d5nmj7vv.js} +1 -1
- package/dist/shared/{14vx95q4.js → dd5pmnky.js} +7 -7
- package/dist/shared/{vb6qfyve.js → ds229x4r.js} +2 -2
- package/dist/shared/{1qa0qajz.js → e275q7sd.js} +1 -1
- package/dist/shared/{zp9fmend.js → ebhz8vh6.js} +4 -4
- package/dist/shared/{hyh73qk6.js → ecn8mfdq.js} +5 -5
- package/dist/shared/{je4axnm8.js → fdsz3w80.js} +2 -2
- package/dist/shared/{9s0ypp87.js → fk9vef30.js} +85 -74
- package/dist/shared/{g6evj1j3.js → g89fmz5s.js} +1 -1
- package/dist/shared/{aytqh5y2.js → ghqzdp94.js} +2 -2
- package/dist/shared/h9811jjm.js +17 -0
- package/dist/shared/{dkxgzaqd.js → hqpxf4a4.js} +1 -1
- package/dist/shared/{8skf0cam.js → jpybhf98.js} +1 -1
- package/dist/shared/{67txcrcw.js → kgwp4jdd.js} +4 -4
- package/dist/shared/kzgrnckd.js +29 -0
- package/dist/shared/mazpbcdj.js +233 -0
- package/dist/shared/{kb2sdhfb.js → mfvx6kjx.js} +17 -1
- package/dist/shared/{svncdeh5.js → mgaq2sd3.js} +11 -8
- package/dist/shared/{5mtf6cj3.js → mvmm3xpb.js} +5 -2
- package/dist/shared/{b5pftnn2.js → myk8fswx.js} +66 -21
- package/dist/shared/{2shdbn8q.js → n306gqkd.js} +9 -9
- package/dist/shared/{n816peh1.js → n454kcnw.js} +1 -1
- package/dist/shared/n5whk3mt.js +665 -0
- package/dist/shared/n7kg8mmx.js +61 -0
- package/dist/shared/{vqrjpcqn.js → nmnsgj7x.js} +1 -1
- package/dist/shared/{tbrvgw6z.js → npdftanb.js} +19 -26
- package/dist/shared/{ek2wt2dz.js → pg4ezgyf.js} +11 -30
- package/dist/shared/{5fe3kbsh.js → pgsak1yw.js} +1 -1
- package/dist/shared/{bm22fvzr.js → qfw14tna.js} +2 -2
- package/dist/shared/{wa07eas9.js → qvwwp1mp.js} +62 -41
- package/dist/shared/rbxt795q.js +1766 -0
- package/dist/shared/{xjk7hnn5.js → s7he5e5d.js} +2 -2
- package/dist/shared/{w72kgg4q.js → ss2kv2rs.js} +6 -6
- package/dist/shared/stfa9xcw.js +450 -0
- package/dist/shared/{3v7t1yrv.js → th3be82n.js} +2 -2
- package/dist/shared/{79dt02vc.js → tr64w5p0.js} +1 -1
- package/dist/shared/{cn957f8d.js → tw1nvvfj.js} +3 -3
- package/dist/shared/{ed0b8k4s.js → typ3vy7t.js} +1 -1
- package/dist/shared/{9628a9xt.js → vk7rag46.js} +1 -1
- package/dist/shared/{ze4hxsmy.js → w9ejzaqf.js} +1 -1
- package/dist/shared/{vczs8gd4.js → wvtjg5m3.js} +2 -2
- package/dist/shared/{9y3mmmh1.js → xfhe73sb.js} +1 -1
- package/dist/shared/xqacq37x.js +61 -0
- package/dist/shared/{1est4ezg.js → xtsydxjg.js} +3 -3
- package/dist/shared/xv8qj97g.js +96 -0
- package/dist/shared/{bg3rym3g.js → xwhdcrm4.js} +2 -2
- package/dist/shared/{kr0jzbw2.js → yvabyg9k.js} +7 -7
- package/dist/shared/yybhre6n.js +136 -0
- package/dist/shared/zdqf8k5d.js +8 -0
- package/dist/shared/{jznfax0y.js → zq1he88x.js} +4 -4
- package/dist/tooling/cli.js +108 -23
- package/dist/tooling/driver-run.js +4654 -0
- package/dist/tooling/driver-test.d.ts +36 -0
- package/dist/tooling/github/comment.d.ts +50 -0
- package/dist/tooling/github/post-comment.d.ts +17 -0
- package/dist/tooling/migrate/commands.d.ts +3 -2
- package/dist/tooling/migrate/config.d.ts +13 -0
- package/dist/tooling/migrate/export.d.ts +165 -0
- package/dist/tooling/migrate/ext-surface.d.ts +80 -0
- package/dist/tooling/migrate/ext.d.ts +31 -4
- package/dist/tooling/migrate/import-drizzle.d.ts +40 -0
- package/dist/tooling/migrate/index.d.ts +3 -0
- package/dist/tooling/migrate/index.js +55 -10
- package/dist/tooling/migrate/lint-rules.d.ts +18 -1
- package/dist/tooling/migrate/lint.d.ts +14 -1
- package/dist/tooling/migrate/place.d.ts +18 -0
- package/dist/tooling/migrate/plan-json.d.ts +65 -0
- package/dist/tooling/migrate/project.d.ts +13 -1
- package/dist/tooling/migrate/pull-emit.d.ts +98 -0
- package/dist/tooling/migrate/pull-routines.d.ts +126 -0
- package/dist/tooling/migrate/pull-verify.d.ts +26 -0
- package/dist/tooling/migrate/pull.d.ts +62 -0
- package/dist/tooling/migrate/reprint.d.ts +32 -0
- package/dist/tooling/migrate/sandbox.d.ts +8 -2
- package/dist/tooling/migrate/schema-api.d.ts +43 -0
- package/dist/tooling/migrate/sql-lex.d.ts +18 -0
- package/dist/tooling/shared/04svnxxj.js +344 -0
- package/dist/tooling/shared/0j0jtse1.js +13 -0
- package/dist/tooling/shared/0r05zhyq.js +618 -0
- package/dist/tooling/shared/1800eymw.js +49 -0
- package/dist/tooling/shared/35zemrmf.js +12 -0
- package/dist/tooling/shared/3rmaz3pq.js +140 -0
- package/dist/tooling/shared/3yn79q5m.js +12 -0
- package/dist/tooling/shared/54tqkxja.js +51 -0
- package/dist/tooling/shared/57btdkgm.js +209 -0
- package/dist/tooling/shared/5bmksndh.js +118 -0
- package/dist/tooling/shared/5p8km5jb.js +38 -0
- package/dist/tooling/shared/5x3pf400.js +185 -0
- package/dist/tooling/shared/5zrzffnk.js +6 -0
- package/dist/tooling/shared/62fxpc1p.js +332 -0
- package/dist/tooling/shared/68tf18v4.js +20 -0
- package/dist/tooling/shared/6vk28rjp.js +98 -0
- package/dist/tooling/shared/76pv6qff.js +9 -0
- package/dist/tooling/shared/7aews1zg.js +311 -0
- package/dist/tooling/shared/7b3xp9gc.js +195 -0
- package/dist/tooling/shared/7kms6fvj.js +20 -0
- package/dist/tooling/shared/7pxncnzs.js +40 -0
- package/dist/tooling/shared/829fjxyw.js +198 -0
- package/dist/tooling/shared/8m5znpdt.js +66 -0
- package/dist/tooling/shared/8yr7ges1.js +211 -0
- package/dist/tooling/shared/96ps4g1z.js +32 -0
- package/dist/tooling/shared/9qr9rkbh.js +143 -0
- package/dist/tooling/shared/9sfbtwsk.js +49 -0
- package/dist/tooling/shared/9wsnsvbf.js +10 -0
- package/dist/tooling/shared/a2xe04bm.js +18 -0
- package/dist/tooling/shared/a4pzghha.js +20 -0
- package/dist/tooling/shared/am04v8na.js +233 -0
- package/dist/tooling/shared/asgr07mp.js +194 -0
- package/dist/tooling/shared/c0xevn1h.js +312 -0
- package/dist/tooling/shared/dhatassp.js +134 -0
- package/dist/tooling/shared/ezqn88nj.js +1696 -0
- package/dist/tooling/shared/f77nnfqy.js +231 -0
- package/dist/tooling/shared/fh07z1dt.js +15 -0
- package/dist/tooling/shared/gqwevek4.js +81 -0
- package/dist/tooling/shared/hfq3n3bd.js +4116 -0
- package/dist/tooling/shared/htnaj77v.js +17 -0
- package/dist/tooling/shared/j664qjrt.js +64 -0
- package/dist/tooling/shared/jpgmjsx3.js +38 -0
- package/dist/tooling/shared/jr2nmr81.js +497 -0
- package/dist/tooling/shared/jsjjz875.js +139 -0
- package/dist/tooling/shared/kbqnrs1x.js +1425 -0
- package/dist/tooling/shared/kz715295.js +94 -0
- package/dist/tooling/shared/m3xt8b1h.js +22 -0
- package/dist/tooling/shared/m4hhb8aa.js +9 -0
- package/dist/tooling/shared/mw5npye0.js +16 -0
- package/dist/tooling/shared/n4jqhpqz.js +27 -0
- package/dist/tooling/shared/nxq95eb6.js +42 -0
- package/dist/tooling/shared/qartgazh.js +70 -0
- package/dist/tooling/shared/rcywj2w8.js +190 -0
- package/dist/tooling/shared/s6qha57m.js +16 -0
- package/dist/tooling/shared/shjs0379.js +150 -0
- package/dist/tooling/shared/sjwkt1pg.js +16 -0
- package/dist/tooling/shared/stebqyyd.js +401 -0
- package/dist/tooling/shared/t4xveemq.js +250 -0
- package/dist/tooling/shared/t6zjeake.js +261 -0
- package/dist/tooling/shared/tcwpjvxe.js +9 -0
- package/dist/tooling/shared/tpssp7ac.js +160 -0
- package/dist/tooling/shared/v6j1ep6w.js +42 -0
- package/dist/tooling/shared/vwr2y833.js +270 -0
- package/dist/tooling/shared/w17sj05d.js +7 -0
- package/dist/tooling/shared/w5d89rb4.js +131 -0
- package/dist/tooling/shared/wbwq1jsa.js +157 -0
- package/dist/tooling/shared/wezxf3h8.js +17 -0
- package/dist/tooling/shared/yb4kd19s.js +12 -0
- package/dist/tooling/shared/ybdew6j7.js +294 -0
- package/dist/tooling/shared/yfedr1zb.js +6 -0
- package/dist/tooling/shared/yhp829bx.js +177 -0
- package/dist/tooling/shared/ytk1tjs0.js +604 -0
- package/dist/tooling/shared/zs9aymcp.js +210 -0
- package/dist/tooling/shared/zx3v9phv.js +8 -0
- package/dist/tooling/testing/index.js +3 -3
- package/package.json +50 -9
- package/dist/shared/ktz42yez.js +0 -113
- package/dist/shared/ttsqgp4p.js +0 -71
- package/dist/shared/y34a8714.js +0 -150
- package/dist/shared/zy8r7qvz.js +0 -116
- package/dist/shared/{ywr8hmey.js → 606g0nbf.js} +3 -3
- package/dist/shared/{rpycarcr.js → gcefca6p.js} +4 -4
|
@@ -28,21 +28,29 @@ export declare function viewMentions(query: string, name: string): boolean;
|
|
|
28
28
|
export type ViewInstall = (model: {
|
|
29
29
|
[name: string]: TableModel;
|
|
30
30
|
}, tenancy: ColumnTenancy | undefined, tables: readonly AnyTable[], casing: "snake" | undefined, scoped: Set<string>) => void;
|
|
31
|
+
/** A value, or a function `install` calls once casing is known. */
|
|
32
|
+
type ColumnSource = readonly {
|
|
33
|
+
readonly name: string;
|
|
34
|
+
readonly type: string;
|
|
35
|
+
}[] | (() => readonly {
|
|
36
|
+
readonly name: string;
|
|
37
|
+
readonly type: string;
|
|
38
|
+
}[]);
|
|
39
|
+
/** A query string, or a function `install` calls once casing is known. */
|
|
40
|
+
type QuerySource = string | (() => string);
|
|
31
41
|
/**
|
|
32
42
|
* Client name, read model, and the hook that moves the handle under `views`.
|
|
33
43
|
*
|
|
34
44
|
* @param name - SQL name of the view
|
|
35
|
-
* @param columns - Declared output columns
|
|
36
|
-
* @param query - Author SQL
|
|
45
|
+
* @param columns - Declared output columns, or a getter `install` calls
|
|
46
|
+
* @param query - Author SQL, or a getter `install` calls
|
|
37
47
|
* @param tenancy - `global("reason")`, when the view opts out
|
|
38
48
|
* @param refresh - `plain` stores no `refresh`. A materialized view is `blocking` or `concurrently`
|
|
39
49
|
* @returns Methods stored on the declaration
|
|
40
50
|
*/
|
|
41
|
-
export declare function viewClient(name: string, columns:
|
|
42
|
-
readonly name: string;
|
|
43
|
-
readonly type: string;
|
|
44
|
-
}[], query: string, tenancy: unknown, refresh?: "plain" | "blocking" | "concurrently"): {
|
|
51
|
+
export declare function viewClient(name: string, columns: ColumnSource, query: QuerySource, tenancy: unknown, refresh?: "plain" | "blocking" | "concurrently"): {
|
|
45
52
|
readonly field: string;
|
|
46
53
|
readonly install: ViewInstall;
|
|
47
54
|
readonly hook: SchemaHook;
|
|
48
55
|
};
|
|
56
|
+
export {};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { CatalogObject } from "../../../contracts/catalog/types.js";
|
|
10
10
|
import type { SchemaHook } from "../model.js";
|
|
11
|
-
import type
|
|
11
|
+
import { type AnyTable, type SqlText } from "../table.js";
|
|
12
12
|
import { type ViewInstall } from "./client.js";
|
|
13
13
|
/** One declared output column. `type` is the Postgres type name. */
|
|
14
14
|
export type ViewColumnInput = {
|
|
@@ -29,6 +29,66 @@ export type ViewOptions = {
|
|
|
29
29
|
*/
|
|
30
30
|
readonly tenancy?: unknown;
|
|
31
31
|
};
|
|
32
|
+
/** Output columns of {@link ViewFrom.from}. A tuple keeps each name. */
|
|
33
|
+
type TupleColumns<K extends readonly string[]> = K extends readonly [] ? readonly [] : K extends readonly [infer H extends string, ...infer R extends readonly string[]] ? readonly [{
|
|
34
|
+
readonly name: H;
|
|
35
|
+
readonly type: string;
|
|
36
|
+
}, ...TupleColumns<R>] : readonly {
|
|
37
|
+
readonly name: K[number];
|
|
38
|
+
readonly type: string;
|
|
39
|
+
}[];
|
|
40
|
+
/** Every column of a table, when `from` is not given a list. */
|
|
41
|
+
type AllColumns<T extends AnyTable> = readonly {
|
|
42
|
+
readonly name: keyof T["columns"] & string;
|
|
43
|
+
readonly type: string;
|
|
44
|
+
}[];
|
|
45
|
+
/**
|
|
46
|
+
* The value `(q) => q.from(...)` returns.
|
|
47
|
+
*
|
|
48
|
+
* @typeParam C - Output columns, for `db.views`
|
|
49
|
+
*/
|
|
50
|
+
export type ViewBuilt<C extends readonly ViewColumnInput[] = readonly ViewColumnInput[]> = {
|
|
51
|
+
/** Declared columns. Present for the type. The catalog uses the SQL names. */
|
|
52
|
+
readonly "~columns"?: C;
|
|
53
|
+
/**
|
|
54
|
+
* Adds a WHERE clause.
|
|
55
|
+
*
|
|
56
|
+
* The text is stored as written, the same way `query` is.
|
|
57
|
+
*
|
|
58
|
+
* @param predicate - SQL after `where`
|
|
59
|
+
* @returns The same view, with the clause
|
|
60
|
+
*/
|
|
61
|
+
where(predicate: SqlText | string): ViewBuilt<C>;
|
|
62
|
+
/**
|
|
63
|
+
* Opts the view out of tenancy.
|
|
64
|
+
*
|
|
65
|
+
* Pass `global("reason")` from `okmodel/tenancy`.
|
|
66
|
+
*
|
|
67
|
+
* @param mark - `global("reason")`
|
|
68
|
+
* @returns The same view, opted out
|
|
69
|
+
*/
|
|
70
|
+
tenancy(mark: unknown): ViewBuilt<C>;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* The argument of `view(name, (q) => q.from(...))`.
|
|
74
|
+
*/
|
|
75
|
+
export type ViewFrom = {
|
|
76
|
+
/**
|
|
77
|
+
* Selects every column of `table`.
|
|
78
|
+
*
|
|
79
|
+
* @param table - Source table
|
|
80
|
+
* @returns The view query
|
|
81
|
+
*/
|
|
82
|
+
from<const T extends AnyTable>(table: T): ViewBuilt<AllColumns<T>>;
|
|
83
|
+
/**
|
|
84
|
+
* Selects `columns` from `table`, in that order.
|
|
85
|
+
*
|
|
86
|
+
* @param table - Source table
|
|
87
|
+
* @param columns - Output columns. Names are the table's fields
|
|
88
|
+
* @returns The view query
|
|
89
|
+
*/
|
|
90
|
+
from<const T extends AnyTable, const K extends readonly (keyof T["columns"] & string)[]>(table: T, columns: K): ViewBuilt<TupleColumns<K>>;
|
|
91
|
+
};
|
|
32
92
|
/**
|
|
33
93
|
* One declared view.
|
|
34
94
|
*
|
|
@@ -117,6 +177,17 @@ export type MaterializedViewDeclaration<N extends string = string, C extends rea
|
|
|
117
177
|
export declare function view<const N extends string, const C extends readonly ViewColumnInput[]>(name: N, options: ViewOptions & {
|
|
118
178
|
readonly columns: C;
|
|
119
179
|
}): ViewDeclaration<N, C>;
|
|
180
|
+
/**
|
|
181
|
+
* Declares a view from a table.
|
|
182
|
+
*
|
|
183
|
+
* `view(name, (q) => q.from(table))` selects that table's columns. Pass a
|
|
184
|
+
* column list to project. `.where` adds a predicate. `.tenancy` opts out.
|
|
185
|
+
*
|
|
186
|
+
* @param name - View name
|
|
187
|
+
* @param build - `q.from(...)`
|
|
188
|
+
* @returns The definition object `schema({ views })` stores
|
|
189
|
+
*/
|
|
190
|
+
export declare function view<const N extends string, const C extends readonly ViewColumnInput[]>(name: N, build: (q: ViewFrom) => ViewBuilt<C>): ViewDeclaration<N, C>;
|
|
120
191
|
/**
|
|
121
192
|
* Declares a materialized view.
|
|
122
193
|
*
|
|
@@ -130,3 +201,4 @@ export declare function view<const N extends string, const C extends readonly Vi
|
|
|
130
201
|
export declare function materializedView<const N extends string, const C extends readonly ViewColumnInput[]>(name: N, options: MaterializedViewOptions & {
|
|
131
202
|
readonly columns: C;
|
|
132
203
|
}): MaterializedViewDeclaration<N, C>;
|
|
204
|
+
export {};
|
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
viewClient
|
|
3
|
-
} from "../../../shared/5e3tf63j.js";
|
|
4
1
|
import {
|
|
5
2
|
viewObject,
|
|
6
3
|
materializedViewObject,
|
|
7
4
|
materializedViewIndex
|
|
8
|
-
} from "../../../shared/
|
|
5
|
+
} from "../../../shared/12z7aznj.js";
|
|
6
|
+
import {
|
|
7
|
+
quoteIdent2
|
|
8
|
+
} from "../../../shared/fk9vef30.js";
|
|
9
|
+
import {
|
|
10
|
+
viewClient
|
|
11
|
+
} from "../../../shared/760ppr76.js";
|
|
12
|
+
import {
|
|
13
|
+
snakeCase
|
|
14
|
+
} from "../../../shared/gcefca6p.js";
|
|
15
|
+
import {
|
|
16
|
+
formatType
|
|
17
|
+
} from "../../../shared/606g0nbf.js";
|
|
9
18
|
import {
|
|
10
19
|
staticNamespace2
|
|
11
20
|
} from "../../../shared/358zsv4r.js";
|
|
@@ -14,7 +23,11 @@ import {
|
|
|
14
23
|
} from "../../../shared/52szzakm.js";
|
|
15
24
|
|
|
16
25
|
// src/dialects/pg/view/index.ts
|
|
17
|
-
|
|
26
|
+
var BUILT = Symbol("okmodel.view.from");
|
|
27
|
+
function view(name, source) {
|
|
28
|
+
if (typeof source === "function")
|
|
29
|
+
return viewFrom(name, source);
|
|
30
|
+
const options = source;
|
|
18
31
|
const schema = options.schema ?? "public";
|
|
19
32
|
const columns = options.columns.map((column) => ({ name: column.name, dataType: column.type }));
|
|
20
33
|
const query = bodyText(options.query);
|
|
@@ -100,6 +113,144 @@ function materializedView(name, options) {
|
|
|
100
113
|
}
|
|
101
114
|
};
|
|
102
115
|
}
|
|
116
|
+
var viewFromApi = {
|
|
117
|
+
from(table, columns) {
|
|
118
|
+
return finish({
|
|
119
|
+
[BUILT]: true,
|
|
120
|
+
table,
|
|
121
|
+
picked: columns,
|
|
122
|
+
predicate: undefined,
|
|
123
|
+
mark: undefined
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
function viewFrom(name, build) {
|
|
128
|
+
const built = build(viewFromApi);
|
|
129
|
+
if (!isRecipe(built)) {
|
|
130
|
+
throw new OkmError2("OKM1121", `View ${name} must return q.from(...).`, {
|
|
131
|
+
fix: { summary: "Return q.from(table), and chain where() or tenancy() on that value." }
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
const recipe = built;
|
|
135
|
+
let casingMode;
|
|
136
|
+
let rendered;
|
|
137
|
+
const render = () => {
|
|
138
|
+
rendered ??= renderQuery(name, recipe, casingMode);
|
|
139
|
+
return rendered;
|
|
140
|
+
};
|
|
141
|
+
const bound = viewClient(name, () => render().columns, () => render().query, recipe.mark, "plain");
|
|
142
|
+
let securityInvoker = false;
|
|
143
|
+
return {
|
|
144
|
+
name,
|
|
145
|
+
schema: "public",
|
|
146
|
+
"~kind": "view",
|
|
147
|
+
install(model, tenancy, tables, casing, scoped) {
|
|
148
|
+
casingMode = casing;
|
|
149
|
+
rendered = undefined;
|
|
150
|
+
bound.install(model, tenancy, tables, casing, scoped);
|
|
151
|
+
securityInvoker = tenancy?.strategy === "rls" && scoped.has(name);
|
|
152
|
+
},
|
|
153
|
+
hook: bound.hook,
|
|
154
|
+
contribute(peers, builtObjects) {
|
|
155
|
+
assertPeers(peers);
|
|
156
|
+
assertNoTable(builtObjects, name);
|
|
157
|
+
const query = render().query;
|
|
158
|
+
const columns = render().columns.map((column) => ({
|
|
159
|
+
name: column.name,
|
|
160
|
+
dataType: column.type
|
|
161
|
+
}));
|
|
162
|
+
const provenance = { origin: "file", name };
|
|
163
|
+
return [
|
|
164
|
+
viewObject({
|
|
165
|
+
namespace: staticNamespace2("public"),
|
|
166
|
+
name,
|
|
167
|
+
columns,
|
|
168
|
+
query,
|
|
169
|
+
provenance,
|
|
170
|
+
...securityInvoker ? { securityInvoker: true } : {}
|
|
171
|
+
})
|
|
172
|
+
];
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function isRecipe(value) {
|
|
177
|
+
return typeof value === "object" && value !== null && BUILT in value;
|
|
178
|
+
}
|
|
179
|
+
function finish(recipe) {
|
|
180
|
+
const built = {
|
|
181
|
+
...recipe,
|
|
182
|
+
where(predicate) {
|
|
183
|
+
return finish({ ...recipe, predicate: bodyText(predicate) });
|
|
184
|
+
},
|
|
185
|
+
tenancy(mark) {
|
|
186
|
+
return finish({ ...recipe, mark });
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
return built;
|
|
190
|
+
}
|
|
191
|
+
function renderQuery(name, recipe, casing) {
|
|
192
|
+
const fields = recipe.picked ?? Object.keys(recipe.table.columns);
|
|
193
|
+
if (fields.length === 0) {
|
|
194
|
+
throw new OkmError2("OKM1120", `View ${name} selects no columns.`, {
|
|
195
|
+
fix: { summary: "Pick at least one column of the table." }
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
const columns = [];
|
|
199
|
+
const selected = [];
|
|
200
|
+
for (const field of fields) {
|
|
201
|
+
const column = recipe.table.columns[field];
|
|
202
|
+
if (column === undefined || typeof column !== "object" || column === null) {
|
|
203
|
+
throw new OkmError2("OKM1020", `View ${name} names ${field}, which ${recipe.table.name} does not have.`, { fix: { summary: "Pass a column of that table." } });
|
|
204
|
+
}
|
|
205
|
+
const sqlName = columnSql(column, field, casing);
|
|
206
|
+
columns.push({ name: sqlName, type: columnType(column, field) });
|
|
207
|
+
selected.push(quoteIdent2(sqlName));
|
|
208
|
+
}
|
|
209
|
+
const tableName = tableSql(recipe.table, casing);
|
|
210
|
+
let query = `select ${selected.join(", ")} from ${quoteIdent2(tableName)}`;
|
|
211
|
+
if (recipe.predicate !== undefined && recipe.predicate.trim().length > 0) {
|
|
212
|
+
query += ` where ${recipe.predicate}`;
|
|
213
|
+
}
|
|
214
|
+
return { query, columns };
|
|
215
|
+
}
|
|
216
|
+
function tableSql(table, casing) {
|
|
217
|
+
const options = table.options;
|
|
218
|
+
if (typeof options?.sqlName === "string" && options.sqlName.length > 0)
|
|
219
|
+
return options.sqlName;
|
|
220
|
+
return casing === "snake" ? snakeCase(table.name) : table.name;
|
|
221
|
+
}
|
|
222
|
+
function columnSql(column, field, casing) {
|
|
223
|
+
const state = readState(column, field);
|
|
224
|
+
if (state.sqlName !== undefined && state.sqlName.length > 0)
|
|
225
|
+
return state.sqlName;
|
|
226
|
+
return casing === "snake" ? snakeCase(field) : field;
|
|
227
|
+
}
|
|
228
|
+
function columnType(column, field) {
|
|
229
|
+
const state = readState(column, field);
|
|
230
|
+
return formatType(state.baseType, state.dims);
|
|
231
|
+
}
|
|
232
|
+
function readState(column, field) {
|
|
233
|
+
if (!("state" in column)) {
|
|
234
|
+
throw new OkmError2("OKM1020", `Column ${field} has no type.`, {
|
|
235
|
+
fix: { summary: "Pass a column built with t." }
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
const state = column.state;
|
|
239
|
+
if (typeof state !== "object" || state === null || !("baseType" in state)) {
|
|
240
|
+
throw new OkmError2("OKM1020", `Column ${field} has no type.`, {
|
|
241
|
+
fix: { summary: "Pass a column built with t." }
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
const baseType = state.baseType;
|
|
245
|
+
const dims = "dims" in state && typeof state.dims === "number" ? state.dims : 0;
|
|
246
|
+
const sqlName = "sqlName" in state && typeof state.sqlName === "string" ? state.sqlName : undefined;
|
|
247
|
+
if (typeof baseType !== "string" || baseType.length === 0) {
|
|
248
|
+
throw new OkmError2("OKM1020", `Column ${field} has no type.`, {
|
|
249
|
+
fix: { summary: "Pass a column built with t." }
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
return { baseType, dims, sqlName };
|
|
253
|
+
}
|
|
103
254
|
function bodyText(body) {
|
|
104
255
|
return typeof body === "string" ? body : body.text;
|
|
105
256
|
}
|
|
@@ -4,19 +4,25 @@
|
|
|
4
4
|
* Domain and enum types from the catalog are created there, then the tables,
|
|
5
5
|
* then the functions a view may call, then each view. `pg_get_viewdef`
|
|
6
6
|
* replaces the author query and `pg_depend` supplies column edges (D117).
|
|
7
|
-
*
|
|
7
|
+
* A `BEGIN ATOMIC` body is replaced with the `pg_get_functiondef` block, so a
|
|
8
|
+
* plan from the live catalog does not treat Postgres's reprint as a change
|
|
9
|
+
* (D273). A name that appears once is that row. Overloads compare identity
|
|
10
|
+
* arguments after typmods and aliases are folded, so two overloads do not
|
|
11
|
+
* share a body. The scratch schema is dropped before this returns. Plans
|
|
12
|
+
* never use it.
|
|
8
13
|
*/
|
|
9
14
|
import type { Catalog } from "../../../contracts/catalog/types.js";
|
|
10
|
-
import type
|
|
15
|
+
import { type CatalogQuery } from "../introspect.js";
|
|
11
16
|
/**
|
|
12
17
|
* Reads dependencies and reprints for every view in `source`.
|
|
13
18
|
*
|
|
14
19
|
* The returned catalog matches what introspection prints for those views
|
|
15
20
|
* when the same query is applied. A declared column list that disagrees
|
|
16
|
-
* with the database is OKM1020.
|
|
21
|
+
* with the database is OKM1020. A `BEGIN ATOMIC` function body is the
|
|
22
|
+
* server reprint, including an argument qualifier such as `by_id.n`.
|
|
17
23
|
*
|
|
18
24
|
* @param runner - Database connection. Statements share its session
|
|
19
|
-
* @param source - Catalog whose views are still author SQL
|
|
20
|
-
* @returns A catalog whose views carry the reprint
|
|
25
|
+
* @param source - Catalog whose views and atomic bodies are still author SQL
|
|
26
|
+
* @returns A catalog whose views and atomic bodies carry the reprint
|
|
21
27
|
*/
|
|
22
28
|
export declare function sealViews(runner: CatalogQuery, source: Catalog): Promise<Catalog>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional build files under `.okm`.
|
|
3
|
+
*
|
|
4
|
+
* The runtime layer cannot import `node:fs`. Bun and Node expose a file read
|
|
5
|
+
* without that import. A missing file is `undefined`.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Directory of `catalog.hash` and `catalog.json`.
|
|
9
|
+
*
|
|
10
|
+
* A trailing `/` or `\` is removed so the joined file name is one path.
|
|
11
|
+
*
|
|
12
|
+
* @param catalogDir - Directory the caller passed, or the default `.okm`
|
|
13
|
+
* @returns The directory, without a trailing slash
|
|
14
|
+
*/
|
|
15
|
+
export declare function artifactDir(catalogDir: string | undefined): string;
|
|
16
|
+
/**
|
|
17
|
+
* Reads an optional build artifact.
|
|
18
|
+
*
|
|
19
|
+
* @param path - File path
|
|
20
|
+
* @returns The text, or `undefined` when the file is missing
|
|
21
|
+
*/
|
|
22
|
+
export declare function readText(path: string): Promise<string | undefined>;
|
package/dist/runtime/client.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import type { DriverPool } from "../contracts/driver.js";
|
|
8
8
|
import type { IdGenerators } from "../contracts/generator.js";
|
|
9
9
|
import { OkmError, type ErrorStatuses, type OkmErrorOptions } from "../contracts/error.js";
|
|
10
|
+
import type { MapPostgresErrorOptions } from "../dialects/pg/errors.js";
|
|
10
11
|
import type { PresetUse, QuerySchema } from "../dialects/pg/model.js";
|
|
11
12
|
import { type ArchiveView, type Plan, type ReadCall, type CallScope, type ReadOp } from "./plan.js";
|
|
12
13
|
import type { CatalogArtifact, Connected, Hookm, Timeouts } from "./types.js";
|
|
@@ -148,6 +149,15 @@ export declare function withHttp(http: ErrorStatuses | undefined, options: OkmEr
|
|
|
148
149
|
* @returns The error `toHttp()` reads
|
|
149
150
|
*/
|
|
150
151
|
export declare function attachHttp(http: ErrorStatuses | undefined, error: OkmError): OkmError;
|
|
152
|
+
/**
|
|
153
|
+
* Statuses and schema the Postgres error mapper reads.
|
|
154
|
+
*
|
|
155
|
+
* @param http - Status overrides from `connect`
|
|
156
|
+
* @param includeValues - When true, a mapped error may include bound values
|
|
157
|
+
* @param schema - Schema whose names the mapper can mention
|
|
158
|
+
* @returns Mapper options
|
|
159
|
+
*/
|
|
160
|
+
export declare function mapOptions(http: ErrorStatuses | undefined, includeValues: boolean, schema: QuerySchema): MapPostgresErrorOptions;
|
|
151
161
|
/**
|
|
152
162
|
* Maps a driver or query error and records it on the session logger.
|
|
153
163
|
*
|
|
@@ -44,5 +44,6 @@ export declare function driftVerdict(codeHash: string, recordedHash: string, mig
|
|
|
44
44
|
* @param codeHash - Hash of the code's catalog
|
|
45
45
|
* @param recordedHash - Hash from the startup query
|
|
46
46
|
* @param options - The call's cancellation and deadline
|
|
47
|
+
* @param namespace - Schema that stores `okm_history`. `public` stays unqualified
|
|
47
48
|
*/
|
|
48
|
-
export declare function assertDrift(pool: DriverPool, codeHash: string, recordedHash: string, options: ExecuteOptions | undefined): Promise<void>;
|
|
49
|
+
export declare function assertDrift(pool: DriverPool, codeHash: string, recordedHash: string, options: ExecuteOptions | undefined, namespace?: string): Promise<void>;
|
package/dist/runtime/drift.d.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { DriverPool, ExecuteOptions } from "../contracts/driver.js";
|
|
10
10
|
import type { QuerySchema } from "../dialects/pg/model.js";
|
|
11
|
+
export { artifactDir } from "./artifact-file.js";
|
|
11
12
|
/** Build artifact `okm build` wrote. */
|
|
12
13
|
export type CatalogArtifact = {
|
|
13
14
|
readonly text: string;
|
|
@@ -24,17 +25,9 @@ export type CatalogArtifact = {
|
|
|
24
25
|
* @param recordedHash - Hash from the startup query
|
|
25
26
|
* @param source - Optional build artifact, or a directory that contains one
|
|
26
27
|
* @param options - Cancellation and deadline for the history query
|
|
28
|
+
* @param namespace - Schema that stores `okm_history`. `public` stays unqualified
|
|
27
29
|
*/
|
|
28
30
|
export declare function assertCompatible(pool: DriverPool, schema: QuerySchema, recordedHash: string, source: {
|
|
29
31
|
readonly catalog?: CatalogArtifact;
|
|
30
32
|
readonly catalogDir?: string;
|
|
31
|
-
}, options: ExecuteOptions | undefined): Promise<void>;
|
|
32
|
-
/**
|
|
33
|
-
* Directory of `catalog.hash` and `catalog.json`.
|
|
34
|
-
*
|
|
35
|
-
* A trailing `/` or `\` is removed so the joined file name is one path.
|
|
36
|
-
*
|
|
37
|
-
* @param catalogDir - Directory the caller passed, or the default `.okm`
|
|
38
|
-
* @returns The directory, without a trailing slash
|
|
39
|
-
*/
|
|
40
|
-
export declare function artifactDir(catalogDir: string | undefined): string;
|
|
33
|
+
}, options: ExecuteOptions | undefined, namespace?: string): Promise<void>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenTelemetry observers (`okmodel/otel`).
|
|
3
|
+
*
|
|
4
|
+
* The package does not import `@opentelemetry/*`. Pass a tracer you already
|
|
5
|
+
* have. The observers are `hookm`, `onRoute`, and an `inspect()` result.
|
|
6
|
+
* Statement text is off unless `statement` is true. Parameters and tenant ids
|
|
7
|
+
* are never attributes (spec §5.5, D267).
|
|
8
|
+
*/
|
|
9
|
+
import type { RouteEvent } from "./topology.js";
|
|
10
|
+
import type { Hookm, Inspection } from "./types.js";
|
|
11
|
+
/** A scalar OpenTelemetry attribute. Arrays are not used. */
|
|
12
|
+
export type OtelAttribute = string | number | boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Status codes from the OpenTelemetry API.
|
|
15
|
+
*
|
|
16
|
+
* `0` is unset, `1` is OK, and `2` is ERROR.
|
|
17
|
+
*/
|
|
18
|
+
export type OtelStatusCode = 0 | 1 | 2;
|
|
19
|
+
/**
|
|
20
|
+
* The span methods this entry calls.
|
|
21
|
+
*
|
|
22
|
+
* A tracer from `@opentelemetry/api` satisfies this shape.
|
|
23
|
+
*/
|
|
24
|
+
export interface OtelSpan {
|
|
25
|
+
/** Sets one attribute. */
|
|
26
|
+
setAttribute(key: string, value: OtelAttribute): void;
|
|
27
|
+
/** Sets the span status. `message` is never sent. */
|
|
28
|
+
setStatus(status: {
|
|
29
|
+
readonly code: OtelStatusCode;
|
|
30
|
+
}): void;
|
|
31
|
+
/**
|
|
32
|
+
* Records an exception.
|
|
33
|
+
*
|
|
34
|
+
* `name` is the error name. `code` is an OKM code when the error has one.
|
|
35
|
+
* Message and stack are omitted.
|
|
36
|
+
*/
|
|
37
|
+
recordException(exception: {
|
|
38
|
+
readonly name: string;
|
|
39
|
+
readonly code?: string;
|
|
40
|
+
}): void;
|
|
41
|
+
/** Adds a span event. */
|
|
42
|
+
addEvent(name: string, attributes?: Readonly<Record<string, OtelAttribute>>): void;
|
|
43
|
+
/** Ends the span. */
|
|
44
|
+
end(): void;
|
|
45
|
+
}
|
|
46
|
+
/** Options passed to `startSpan`. `kind` is `2` (client). */
|
|
47
|
+
export interface OtelSpanOptions {
|
|
48
|
+
/** OpenTelemetry span kind. This entry always passes `2`. */
|
|
49
|
+
readonly kind?: number;
|
|
50
|
+
/** Attributes set when the span starts. */
|
|
51
|
+
readonly attributes?: Readonly<Record<string, OtelAttribute>>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The tracer methods this entry calls.
|
|
55
|
+
*
|
|
56
|
+
* A tracer from `@opentelemetry/api` satisfies this shape.
|
|
57
|
+
*/
|
|
58
|
+
export interface OtelTracer {
|
|
59
|
+
/**
|
|
60
|
+
* Starts a span.
|
|
61
|
+
*
|
|
62
|
+
* @param name - Span name
|
|
63
|
+
* @param options - Kind and attributes
|
|
64
|
+
*/
|
|
65
|
+
startSpan(name: string, options?: OtelSpanOptions): OtelSpan;
|
|
66
|
+
}
|
|
67
|
+
/** What {@link otel} accepts. */
|
|
68
|
+
export interface OtelOptions {
|
|
69
|
+
/** Tracer the caller owns. This module does not construct one. */
|
|
70
|
+
readonly tracer: OtelTracer;
|
|
71
|
+
/**
|
|
72
|
+
* Record `db.query.text` from `inspect()`.
|
|
73
|
+
*
|
|
74
|
+
* Omitted or false, the text is left off. Parameters stay off either way.
|
|
75
|
+
*/
|
|
76
|
+
readonly statement?: boolean;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Observers to pass to `connect`, plus `query` for one `inspect()` result.
|
|
80
|
+
*/
|
|
81
|
+
export interface OtelObservers {
|
|
82
|
+
/** Pass this in `connect({ hookm })`. */
|
|
83
|
+
readonly hookm: Hookm;
|
|
84
|
+
/** Pass this in `connect({ onRoute })`. A topology calls it. */
|
|
85
|
+
readonly onRoute: (event: RouteEvent) => void;
|
|
86
|
+
/**
|
|
87
|
+
* Records `db.query.summary` from `inspect()`.
|
|
88
|
+
*
|
|
89
|
+
* The fingerprint is that summary. `db.query.text` is included only when
|
|
90
|
+
* `statement` is true.
|
|
91
|
+
*
|
|
92
|
+
* @param inspection - The result of `inspect()`
|
|
93
|
+
*/
|
|
94
|
+
readonly query: (inspection: Inspection) => void;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Connects the existing observers to a tracer.
|
|
98
|
+
*
|
|
99
|
+
* `onRoute` spans start and end in that call, because the hook fires once.
|
|
100
|
+
* A transaction span stays open from `start` until `commit` or `rollback`.
|
|
101
|
+
*
|
|
102
|
+
* @param options - Tracer, and whether statement text is recorded
|
|
103
|
+
* @returns `hookm`, `onRoute`, and `query`
|
|
104
|
+
*/
|
|
105
|
+
export declare function otel(options: OtelOptions): OtelObservers;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// src/runtime/otel.ts
|
|
2
|
+
var SYSTEM = "postgresql";
|
|
3
|
+
var CLIENT = 2;
|
|
4
|
+
var STATUS_OK = 1;
|
|
5
|
+
var STATUS_ERROR = 2;
|
|
6
|
+
function otel(options) {
|
|
7
|
+
const tracer = options.tracer;
|
|
8
|
+
const statement = options.statement === true;
|
|
9
|
+
const open = [];
|
|
10
|
+
const hookm = {
|
|
11
|
+
onTransaction(event) {
|
|
12
|
+
if (event.phase === "start") {
|
|
13
|
+
const name = event.depth === 0 ? "transaction" : "savepoint";
|
|
14
|
+
open.push({
|
|
15
|
+
depth: event.depth,
|
|
16
|
+
span: begin(tracer, name, {
|
|
17
|
+
"db.system.name": SYSTEM,
|
|
18
|
+
"db.operation.name": name
|
|
19
|
+
})
|
|
20
|
+
});
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const index = latest(open, event.depth);
|
|
24
|
+
const found = index < 0 ? undefined : open[index];
|
|
25
|
+
if (found === undefined)
|
|
26
|
+
return;
|
|
27
|
+
open.splice(index, 1);
|
|
28
|
+
if (event.phase === "rollback") {
|
|
29
|
+
found.span.setAttribute("error.type", "rollback");
|
|
30
|
+
found.span.setStatus({ code: STATUS_ERROR });
|
|
31
|
+
} else {
|
|
32
|
+
found.span.setStatus({ code: STATUS_OK });
|
|
33
|
+
}
|
|
34
|
+
found.span.end();
|
|
35
|
+
},
|
|
36
|
+
onError(error) {
|
|
37
|
+
const span = begin(tracer, "error", {
|
|
38
|
+
"db.system.name": SYSTEM,
|
|
39
|
+
"error.type": errorType(error)
|
|
40
|
+
});
|
|
41
|
+
span.recordException(recordedException(error));
|
|
42
|
+
span.setStatus({ code: STATUS_ERROR });
|
|
43
|
+
span.end();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
hookm,
|
|
48
|
+
onRoute(event) {
|
|
49
|
+
const span = begin(tracer, event.op, {
|
|
50
|
+
"db.system.name": SYSTEM,
|
|
51
|
+
"db.operation.name": event.op
|
|
52
|
+
});
|
|
53
|
+
span.addEvent("route", { endpoint: event.endpoint, reason: event.reason });
|
|
54
|
+
span.end();
|
|
55
|
+
},
|
|
56
|
+
query(inspection) {
|
|
57
|
+
const op = inspection.intent.op;
|
|
58
|
+
const table = inspection.intent.table;
|
|
59
|
+
const attributes = {
|
|
60
|
+
"db.system.name": SYSTEM,
|
|
61
|
+
"db.operation.name": op,
|
|
62
|
+
"db.collection.name": table,
|
|
63
|
+
"db.query.summary": inspection.plan.fingerprint
|
|
64
|
+
};
|
|
65
|
+
if (statement)
|
|
66
|
+
attributes["db.query.text"] = inspection.sql.text;
|
|
67
|
+
begin(tracer, `${op} ${table}`, attributes).end();
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function begin(tracer, name, attributes) {
|
|
72
|
+
return tracer.startSpan(name, { kind: CLIENT, attributes });
|
|
73
|
+
}
|
|
74
|
+
function latest(open, depth) {
|
|
75
|
+
for (let index = open.length - 1;index >= 0; index -= 1) {
|
|
76
|
+
if (open[index]?.depth === depth)
|
|
77
|
+
return index;
|
|
78
|
+
}
|
|
79
|
+
return -1;
|
|
80
|
+
}
|
|
81
|
+
function errorType(error) {
|
|
82
|
+
return error instanceof Error && error.name.length > 0 ? error.name : "error";
|
|
83
|
+
}
|
|
84
|
+
function recordedException(error) {
|
|
85
|
+
const name = errorType(error);
|
|
86
|
+
const code = okmCode(error);
|
|
87
|
+
return code === undefined ? { name } : { name, code };
|
|
88
|
+
}
|
|
89
|
+
function okmCode(error) {
|
|
90
|
+
if (typeof error !== "object" || error === null || !("code" in error))
|
|
91
|
+
return;
|
|
92
|
+
const code = error.code;
|
|
93
|
+
return typeof code === "string" && /^OKM\d+$/.test(code) ? code : undefined;
|
|
94
|
+
}
|
|
95
|
+
export {
|
|
96
|
+
otel
|
|
97
|
+
};
|
package/dist/runtime/pg/bun.js
CHANGED
|
@@ -4,20 +4,20 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
markClientPool,
|
|
6
6
|
open5
|
|
7
|
-
} from "../../shared/
|
|
7
|
+
} from "../../shared/62b603gr.js";
|
|
8
8
|
import {
|
|
9
9
|
BUNSQL_CAPABILITIES,
|
|
10
10
|
readCapability2,
|
|
11
11
|
hasCapability2
|
|
12
|
-
} from "../../shared/
|
|
12
|
+
} from "../../shared/mfvx6kjx.js";
|
|
13
13
|
import {
|
|
14
14
|
createClient
|
|
15
|
-
} from "../../shared/
|
|
15
|
+
} from "../../shared/npdftanb.js";
|
|
16
16
|
|
|
17
17
|
// src/runtime/pg/bun.ts
|
|
18
18
|
function connect(target, options) {
|
|
19
19
|
if (typeof target === "object" && !isPool(target)) {
|
|
20
|
-
return import("../../shared/
|
|
20
|
+
return import("../../shared/71n0jmhc.js").then((mod) => mod.default(target, options, (config) => {
|
|
21
21
|
const pool = open5(config);
|
|
22
22
|
markClientPool(pool);
|
|
23
23
|
return pool;
|