@zeronsh/orbit 0.1.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/LICENSE +201 -0
- package/dist/adapter-C-AhY9cw.d.ts +18 -0
- package/dist/chunk-2R6QPZNI.js +274 -0
- package/dist/chunk-2R6QPZNI.js.map +1 -0
- package/dist/chunk-7CMFTRDQ.js +253 -0
- package/dist/chunk-7CMFTRDQ.js.map +1 -0
- package/dist/chunk-N2NAKHMU.js +1951 -0
- package/dist/chunk-N2NAKHMU.js.map +1 -0
- package/dist/chunk-QR3NSGHJ.js +131 -0
- package/dist/chunk-QR3NSGHJ.js.map +1 -0
- package/dist/client.d.ts +349 -0
- package/dist/client.js +3 -0
- package/dist/client.js.map +1 -0
- package/dist/custom-DzMQ-nY2.d.ts +81 -0
- package/dist/drizzle/cli/bin.d.ts +1 -0
- package/dist/drizzle/cli/bin.js +51 -0
- package/dist/drizzle/cli/bin.js.map +1 -0
- package/dist/drizzle/cli.d.ts +63 -0
- package/dist/drizzle/cli.js +6 -0
- package/dist/drizzle/cli.js.map +1 -0
- package/dist/drizzle.d.ts +21 -0
- package/dist/drizzle.js +20 -0
- package/dist/drizzle.js.map +1 -0
- package/dist/introspect-zNCdXfuc.d.ts +31 -0
- package/dist/ir-DE_CZz0D.d.ts +49 -0
- package/dist/orm-core.d.ts +33 -0
- package/dist/orm-core.js +4 -0
- package/dist/orm-core.js.map +1 -0
- package/dist/query-BMK1cXAS.d.ts +296 -0
- package/dist/react.d.ts +16 -0
- package/dist/react.js +27 -0
- package/dist/react.js.map +1 -0
- package/dist/schema-BNM6bks7.d.ts +108 -0
- package/dist/server/pg.d.ts +18 -0
- package/dist/server/pg.js +35 -0
- package/dist/server/pg.js.map +1 -0
- package/dist/server.d.ts +41 -0
- package/dist/server.js +81 -0
- package/dist/server.js.map +1 -0
- package/package.json +96 -0
package/dist/drizzle.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { drizzleToIR } from './chunk-2R6QPZNI.js';
|
|
2
|
+
export { drizzleToIR } from './chunk-2R6QPZNI.js';
|
|
3
|
+
import { buildOrbitSchema } from './chunk-7CMFTRDQ.js';
|
|
4
|
+
import './chunk-N2NAKHMU.js';
|
|
5
|
+
|
|
6
|
+
// drizzle/src/index.ts
|
|
7
|
+
var drizzleAdapter = {
|
|
8
|
+
name: "drizzle",
|
|
9
|
+
toIR: drizzleToIR
|
|
10
|
+
};
|
|
11
|
+
function defineOrbitSchema(schema, config) {
|
|
12
|
+
return buildOrbitSchema(drizzleToIR(schema, config));
|
|
13
|
+
}
|
|
14
|
+
function drizzleToSchemaIR(schema, config) {
|
|
15
|
+
return drizzleToIR(schema, config);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { defineOrbitSchema, drizzleAdapter, drizzleToSchemaIR };
|
|
19
|
+
//# sourceMappingURL=drizzle.js.map
|
|
20
|
+
//# sourceMappingURL=drizzle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../drizzle/src/index.ts"],"names":[],"mappings":";;;;;;AAgBO,IAAM,cAAA,GAA4E;AAAA,EACvF,IAAA,EAAM,SAAA;AAAA,EACN,IAAA,EAAM;AACR;AAUO,SAAS,iBAAA,CAAkB,QAAiC,MAAA,EAA0C;AAC3G,EAAA,OAAO,gBAAA,CAAiB,WAAA,CAAY,MAAA,EAAQ,MAAM,CAAC,CAAA;AACrD;AAGO,SAAS,iBAAA,CAAkB,QAAiC,MAAA,EAAyC;AAC1G,EAAA,OAAO,WAAA,CAAY,QAAQ,MAAM,CAAA;AACnC","file":"drizzle.js","sourcesContent":["// @orbit/drizzle — generate an Orbit schema from a Drizzle ORM schema.\n//\n// import * as schema from './db/schema';\n// import { relations } from './db/relations'; // defineRelations(...) (optional)\n// export const orbitSchema = defineOrbitSchema(schema, { relations });\n//\n// `defineOrbitSchema` builds the schema at runtime (fast, no codegen) but cannot\n// see `$type<>()` custom types — those are type-level only. For a fully-typed\n// schema (custom types + enums preserved), use the `orbit-drizzle generate` CLI,\n// which resolves types with the TypeScript compiler and emits an `*.gen.ts`.\n\nimport { buildOrbitSchema, type OrmAdapter, type SchemaIR } from '../../orm-core/src/index.ts';\nimport type { SchemaDef } from '../../client/src/index.ts';\nimport { drizzleToIR, type DrizzleAdapterConfig } from './introspect.ts';\n\n/** The Drizzle → Orbit adapter (implements the ORM-agnostic `OrmAdapter`). */\nexport const drizzleAdapter: OrmAdapter<Record<string, unknown>, DrizzleAdapterConfig> = {\n name: 'drizzle',\n toIR: drizzleToIR,\n};\n\n/**\n * Build a live Orbit schema object from a Drizzle schema (runtime path).\n *\n * Returns a generic {@link SchemaDef}: correct at runtime and usable with\n * `createBuilder` / `new Orbit({ schema })`. For a fully-typed schema that\n * preserves `.$type<>()` custom types + enums, use the `orbit-drizzle` CLI (it\n * resolves types with the TypeScript compiler — see the README).\n */\nexport function defineOrbitSchema(schema: Record<string, unknown>, config?: DrizzleAdapterConfig): SchemaDef {\n return buildOrbitSchema(drizzleToIR(schema, config));\n}\n\n/** Convert a Drizzle schema directly to the normalized IR (advanced / codegen). */\nexport function drizzleToSchemaIR(schema: Record<string, unknown>, config?: DrizzleAdapterConfig): SchemaIR {\n return drizzleToIR(schema, config);\n}\n\nexport { drizzleToIR };\nexport type { DrizzleAdapterConfig };\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { S as SchemaIR } from './ir-DE_CZz0D.js';
|
|
2
|
+
|
|
3
|
+
interface DrizzleAdapterConfig {
|
|
4
|
+
/**
|
|
5
|
+
* The Relations v2 object (`defineRelations(...)`), if it isn't one of the
|
|
6
|
+
* exports in the schema you passed. When omitted, it is auto-detected among the
|
|
7
|
+
* schema's exports; failing that, relationships are derived from foreign keys.
|
|
8
|
+
*/
|
|
9
|
+
readonly relations?: unknown;
|
|
10
|
+
/**
|
|
11
|
+
* Per-table selection. Omit for "all tables, all columns". `false` excludes a
|
|
12
|
+
* table; an object selects columns (`{ id: true, secret: false }`). Primary-key
|
|
13
|
+
* columns are always included.
|
|
14
|
+
*/
|
|
15
|
+
readonly tables?: Record<string, boolean | Record<string, boolean>>;
|
|
16
|
+
/**
|
|
17
|
+
* Custom TypeScript types per `table.column` (database names), supplied by the
|
|
18
|
+
* CLI's type resolver so `$type<>()` survives into codegen. Runtime callers
|
|
19
|
+
* can't read `$type` (it is type-level only), so this is normally CLI-only.
|
|
20
|
+
*/
|
|
21
|
+
readonly customTypes?: Record<string, Record<string, string>>;
|
|
22
|
+
/** Synthesize relationships from foreign keys when no Relations object exists. Default true. */
|
|
23
|
+
readonly fkRelationships?: boolean;
|
|
24
|
+
/** Print what was skipped / inferred. */
|
|
25
|
+
readonly debug?: boolean;
|
|
26
|
+
}
|
|
27
|
+
type AnyRecord = Record<string, unknown>;
|
|
28
|
+
/** Convert a Drizzle schema (`import * as schema`) into Orbit's {@link SchemaIR}. */
|
|
29
|
+
declare function drizzleToIR(input: AnyRecord, config?: DrizzleAdapterConfig): SchemaIR;
|
|
30
|
+
|
|
31
|
+
export { type DrizzleAdapterConfig as D, drizzleToIR as d };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** Orbit's column value types (mirrors `@orbit/client`'s `ValueType`, sans null). */
|
|
2
|
+
type OrbitValueType = 'string' | 'number' | 'boolean' | 'json';
|
|
3
|
+
interface IRColumn {
|
|
4
|
+
/** Orbit field name (the key used in queries/mutators). For Orbit this is the
|
|
5
|
+
* database column name, since Orbit syncs raw Postgres rows. */
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly type: OrbitValueType;
|
|
8
|
+
/** Nullable / has a database default the client can't supply. */
|
|
9
|
+
readonly optional: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* A TypeScript *type expression* to specialize the column with (e.g.
|
|
12
|
+
* `` `${string}@${string}` ``, `'active' | 'inactive'`, `{ theme: string }`).
|
|
13
|
+
* Emitted as `string<...>()` / `json<...>()` etc. so a Drizzle `$type<>()` and
|
|
14
|
+
* enums survive into the generated schema. Type-level only; ignored at runtime.
|
|
15
|
+
*/
|
|
16
|
+
readonly customType?: string;
|
|
17
|
+
/** Source ORM column type, for diagnostics only. */
|
|
18
|
+
readonly sourceType?: string;
|
|
19
|
+
}
|
|
20
|
+
interface IRTable {
|
|
21
|
+
/** Orbit table name (the database table name). */
|
|
22
|
+
readonly name: string;
|
|
23
|
+
readonly columns: readonly IRColumn[];
|
|
24
|
+
readonly primaryKey: readonly string[];
|
|
25
|
+
}
|
|
26
|
+
type Cardinality = 'one' | 'many';
|
|
27
|
+
/** One hop of a relationship chain. */
|
|
28
|
+
interface IRConnection {
|
|
29
|
+
readonly sourceField: readonly string[];
|
|
30
|
+
readonly destField: readonly string[];
|
|
31
|
+
/** Destination table name (a key into `tables`). */
|
|
32
|
+
readonly destSchema: string;
|
|
33
|
+
readonly cardinality: Cardinality;
|
|
34
|
+
}
|
|
35
|
+
interface IRRelationship {
|
|
36
|
+
/** Source table name. */
|
|
37
|
+
readonly table: string;
|
|
38
|
+
/** Relationship name (used as `q.related('<name>')`). */
|
|
39
|
+
readonly name: string;
|
|
40
|
+
/** 1 connection = direct (FK); 2 connections = many-to-many through a junction. */
|
|
41
|
+
readonly chain: readonly IRConnection[];
|
|
42
|
+
}
|
|
43
|
+
/** The complete normalized schema an adapter produces. */
|
|
44
|
+
interface SchemaIR {
|
|
45
|
+
readonly tables: readonly IRTable[];
|
|
46
|
+
readonly relationships: readonly IRRelationship[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type { Cardinality as C, IRColumn as I, OrbitValueType as O, SchemaIR as S, IRConnection as a, IRRelationship as b, IRTable as c };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { S as SchemaIR } from './ir-DE_CZz0D.js';
|
|
2
|
+
export { C as Cardinality, I as IRColumn, a as IRConnection, b as IRRelationship, c as IRTable, O as OrbitValueType } from './ir-DE_CZz0D.js';
|
|
3
|
+
export { O as OrmAdapter, d as defineAdapter } from './adapter-C-AhY9cw.js';
|
|
4
|
+
import { S as SchemaDef } from './schema-BNM6bks7.js';
|
|
5
|
+
|
|
6
|
+
/** Build a live Orbit schema object from the IR. */
|
|
7
|
+
declare function buildOrbitSchema(ir: SchemaIR): SchemaDef;
|
|
8
|
+
|
|
9
|
+
interface EmitOptions {
|
|
10
|
+
/** Module the Orbit schema helpers are imported from. Default `@orbit/client`. */
|
|
11
|
+
readonly importFrom?: string;
|
|
12
|
+
/** Append `.js` to the import (Node16/NodeNext ESM). Default false. */
|
|
13
|
+
readonly jsExtension?: boolean;
|
|
14
|
+
/** Exported schema const name. Default `schema`. */
|
|
15
|
+
readonly schemaName?: string;
|
|
16
|
+
/** Also emit `export type <Table> = RowOf<typeof <table>>` for each table. Default true. */
|
|
17
|
+
readonly rowTypes?: boolean;
|
|
18
|
+
/** Header comment lines (without leading `//`). */
|
|
19
|
+
readonly header?: readonly string[];
|
|
20
|
+
/**
|
|
21
|
+
* Extra `import type { ... } from '...'` lines to prepend — used to bring in the
|
|
22
|
+
* named TypeScript types referenced by resolved custom column types (e.g. a
|
|
23
|
+
* `jsonb().$type<PostMeta>()` resolves to `PostMeta`, imported from the schema).
|
|
24
|
+
*/
|
|
25
|
+
readonly typeImports?: readonly {
|
|
26
|
+
readonly module: string;
|
|
27
|
+
readonly names: readonly string[];
|
|
28
|
+
}[];
|
|
29
|
+
}
|
|
30
|
+
/** Emit the full Orbit-schema TypeScript source for an IR. */
|
|
31
|
+
declare function emitSchema(ir: SchemaIR, options?: EmitOptions): string;
|
|
32
|
+
|
|
33
|
+
export { type EmitOptions, SchemaIR, buildOrbitSchema, emitSchema };
|
package/dist/orm-core.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"orm-core.js"}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { S as SchemaDef, a as Relationship, C as Connection, R as RowOf } from './schema-BNM6bks7.js';
|
|
2
|
+
|
|
3
|
+
type Value = string | number | boolean | null;
|
|
4
|
+
type Row = Record<string, Value | unknown>;
|
|
5
|
+
type Direction = 'asc' | 'desc';
|
|
6
|
+
type OrderPart = readonly [field: string, dir: Direction];
|
|
7
|
+
type SimpleOperator = '=' | '!=' | 'IS' | 'IS NOT' | '<' | '>' | '<=' | '>=' | 'LIKE' | 'NOT LIKE' | 'ILIKE' | 'NOT ILIKE' | 'IN' | 'NOT IN';
|
|
8
|
+
type ValuePosition = {
|
|
9
|
+
type: 'literal';
|
|
10
|
+
value: Value | readonly (string | number | boolean)[];
|
|
11
|
+
} | {
|
|
12
|
+
type: 'column';
|
|
13
|
+
name: string;
|
|
14
|
+
} | {
|
|
15
|
+
type: 'static';
|
|
16
|
+
anchor: 'authData' | 'preMutationRow';
|
|
17
|
+
field: string | string[];
|
|
18
|
+
};
|
|
19
|
+
type Condition = {
|
|
20
|
+
type: 'simple';
|
|
21
|
+
op: SimpleOperator;
|
|
22
|
+
left: ValuePosition;
|
|
23
|
+
right: ValuePosition;
|
|
24
|
+
} | {
|
|
25
|
+
type: 'and';
|
|
26
|
+
conditions: Condition[];
|
|
27
|
+
} | {
|
|
28
|
+
type: 'or';
|
|
29
|
+
conditions: Condition[];
|
|
30
|
+
} | {
|
|
31
|
+
type: 'correlatedSubquery';
|
|
32
|
+
related: CorrelatedSubquery;
|
|
33
|
+
op: 'EXISTS' | 'NOT EXISTS';
|
|
34
|
+
};
|
|
35
|
+
type Correlation = {
|
|
36
|
+
parentField: string[];
|
|
37
|
+
childField: string[];
|
|
38
|
+
};
|
|
39
|
+
type CorrelatedSubquery = {
|
|
40
|
+
correlation: Correlation;
|
|
41
|
+
subquery: AST;
|
|
42
|
+
hidden?: boolean;
|
|
43
|
+
/** A `.one()` relationship — the client unwraps it to a single row (or undefined). */
|
|
44
|
+
singular?: boolean;
|
|
45
|
+
};
|
|
46
|
+
type AST = {
|
|
47
|
+
table: string;
|
|
48
|
+
alias?: string;
|
|
49
|
+
where?: Condition;
|
|
50
|
+
related?: CorrelatedSubquery[];
|
|
51
|
+
start?: {
|
|
52
|
+
row: Row;
|
|
53
|
+
exclusive: boolean;
|
|
54
|
+
};
|
|
55
|
+
limit?: number;
|
|
56
|
+
orderBy?: OrderPart[];
|
|
57
|
+
};
|
|
58
|
+
type RowPatchOp = {
|
|
59
|
+
op: 'put';
|
|
60
|
+
tableName: string;
|
|
61
|
+
value: Row;
|
|
62
|
+
} | {
|
|
63
|
+
op: 'update';
|
|
64
|
+
tableName: string;
|
|
65
|
+
id: Row;
|
|
66
|
+
merge?: Row;
|
|
67
|
+
constrain?: string[];
|
|
68
|
+
} | {
|
|
69
|
+
op: 'del';
|
|
70
|
+
tableName: string;
|
|
71
|
+
id: Row;
|
|
72
|
+
} | {
|
|
73
|
+
op: 'clear';
|
|
74
|
+
};
|
|
75
|
+
type QueriesPatchOp = {
|
|
76
|
+
op: 'put';
|
|
77
|
+
hash: string;
|
|
78
|
+
ttl?: number;
|
|
79
|
+
ast?: AST;
|
|
80
|
+
name?: string;
|
|
81
|
+
args?: unknown[];
|
|
82
|
+
} | {
|
|
83
|
+
op: 'del';
|
|
84
|
+
hash: string;
|
|
85
|
+
} | {
|
|
86
|
+
op: 'clear';
|
|
87
|
+
};
|
|
88
|
+
type Downstream = ['connected', {
|
|
89
|
+
wsid: string;
|
|
90
|
+
timestamp?: number;
|
|
91
|
+
}] | ['pokeStart', {
|
|
92
|
+
pokeID: string;
|
|
93
|
+
baseCookie: string | null;
|
|
94
|
+
}] | [
|
|
95
|
+
'pokePart',
|
|
96
|
+
{
|
|
97
|
+
pokeID: string;
|
|
98
|
+
lastMutationIDChanges?: Record<string, number>;
|
|
99
|
+
gotQueriesPatch?: QueriesPatchOp[];
|
|
100
|
+
rowsPatch?: RowPatchOp[];
|
|
101
|
+
}
|
|
102
|
+
] | ['pokeEnd', {
|
|
103
|
+
pokeID: string;
|
|
104
|
+
cookie: string;
|
|
105
|
+
cancel?: boolean;
|
|
106
|
+
}] | ['pong', Record<string, never>] | ['error', {
|
|
107
|
+
kind: string;
|
|
108
|
+
message: string;
|
|
109
|
+
}];
|
|
110
|
+
type CrudOp = {
|
|
111
|
+
op: 'insert';
|
|
112
|
+
tableName: string;
|
|
113
|
+
primaryKey: string[];
|
|
114
|
+
value: Row;
|
|
115
|
+
} | {
|
|
116
|
+
op: 'upsert';
|
|
117
|
+
tableName: string;
|
|
118
|
+
primaryKey: string[];
|
|
119
|
+
value: Row;
|
|
120
|
+
} | {
|
|
121
|
+
op: 'update';
|
|
122
|
+
tableName: string;
|
|
123
|
+
primaryKey: string[];
|
|
124
|
+
value: Row;
|
|
125
|
+
} | {
|
|
126
|
+
op: 'delete';
|
|
127
|
+
tableName: string;
|
|
128
|
+
primaryKey: string[];
|
|
129
|
+
value: Row;
|
|
130
|
+
};
|
|
131
|
+
type Mutation = {
|
|
132
|
+
type: 'crud';
|
|
133
|
+
id: number;
|
|
134
|
+
clientID: string;
|
|
135
|
+
name: '_zero_crud';
|
|
136
|
+
args: [{
|
|
137
|
+
ops: CrudOp[];
|
|
138
|
+
}];
|
|
139
|
+
timestamp: number;
|
|
140
|
+
} | {
|
|
141
|
+
type: 'custom';
|
|
142
|
+
id: number;
|
|
143
|
+
clientID: string;
|
|
144
|
+
name: string;
|
|
145
|
+
args: unknown[];
|
|
146
|
+
timestamp: number;
|
|
147
|
+
};
|
|
148
|
+
type Upstream = ['initConnection', {
|
|
149
|
+
desiredQueriesPatch: QueriesPatchOp[];
|
|
150
|
+
}] | ['changeDesiredQueries', {
|
|
151
|
+
desiredQueriesPatch: QueriesPatchOp[];
|
|
152
|
+
}] | [
|
|
153
|
+
'push',
|
|
154
|
+
{
|
|
155
|
+
clientGroupID: string;
|
|
156
|
+
mutations: Mutation[];
|
|
157
|
+
pushVersion: number;
|
|
158
|
+
timestamp: number;
|
|
159
|
+
requestID: string;
|
|
160
|
+
}
|
|
161
|
+
] | ['ping', Record<string, never>];
|
|
162
|
+
declare const PROTOCOL_VERSION = 51;
|
|
163
|
+
/** A simple stable string hash; the server treats the result as an opaque key. */
|
|
164
|
+
declare function hashString(s: string): string;
|
|
165
|
+
/** Stable hash of a query AST (matches the server's expectation of a string key). */
|
|
166
|
+
declare function hashAST(ast: AST): string;
|
|
167
|
+
|
|
168
|
+
declare class Query {
|
|
169
|
+
#private;
|
|
170
|
+
private constructor();
|
|
171
|
+
static from(table: string): Query;
|
|
172
|
+
where(field: string, op: SimpleOperator, value: Value | readonly (string | number | boolean)[]): Query;
|
|
173
|
+
whereExists(correlation: Correlation, subquery: Query, negated?: boolean): Query;
|
|
174
|
+
related(name: string, correlation: Correlation, subquery: Query): Query;
|
|
175
|
+
/** Append a fully-formed related entry (used for junction/`hidden` chains). */
|
|
176
|
+
addRelated(entry: CorrelatedSubquery): Query;
|
|
177
|
+
orderBy(field: string, dir: Direction): Query;
|
|
178
|
+
limit(n: number): Query;
|
|
179
|
+
one(): Query;
|
|
180
|
+
start(row: Row, exclusive?: boolean): Query;
|
|
181
|
+
/** Whether this query was marked `.one()` (singular). */
|
|
182
|
+
isSingular(): boolean;
|
|
183
|
+
ast(): AST;
|
|
184
|
+
}
|
|
185
|
+
/** A live view's read surface (avoids a circular import on `View`). */
|
|
186
|
+
type ViewLike<T> = {
|
|
187
|
+
data: T[];
|
|
188
|
+
subscribe(fn: () => void): () => void;
|
|
189
|
+
/** Release the view + its query subscription (enables TTL/GC). */
|
|
190
|
+
destroy?(): void;
|
|
191
|
+
};
|
|
192
|
+
/** Anything `useQuery` can subscribe to (a typed query or a named query). */
|
|
193
|
+
interface Subscribable<T> {
|
|
194
|
+
materialize(): ViewLike<T>;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* A query builder result (a {@link TypedQuery} or {@link SchemaQuery}): subscribable
|
|
198
|
+
* and able to expose its AST. Custom query defs return one of these so the client
|
|
199
|
+
* can derive the AST and so the result row type can be inferred.
|
|
200
|
+
*/
|
|
201
|
+
interface QueryBuilder<T extends Row> extends Subscribable<T> {
|
|
202
|
+
ast(): AST;
|
|
203
|
+
query(): Query;
|
|
204
|
+
}
|
|
205
|
+
/** What a [`TypedQuery`] needs from the client to materialize itself. */
|
|
206
|
+
interface QueryHost {
|
|
207
|
+
materialize(q: Query): ViewLike<Row>;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* A query bound to a row type `T` (from the schema) and to its client, mirroring
|
|
211
|
+
* Zero's `z.query.<table>`. `where`/`orderBy` are checked against `T`'s columns,
|
|
212
|
+
* and the materialized result is typed `T[]`. The `One` type parameter tracks
|
|
213
|
+
* `.one()` so that when this query is used as a `related` child it types as a
|
|
214
|
+
* single row (`R | undefined`) instead of an array (`R[]`).
|
|
215
|
+
*/
|
|
216
|
+
declare class TypedQuery<T extends Row, One extends boolean = false> implements Subscribable<T> {
|
|
217
|
+
#private;
|
|
218
|
+
constructor(host: QueryHost | null, q: Query);
|
|
219
|
+
where<K extends keyof T & string>(field: K, op: SimpleOperator, value: T[K] | readonly NonNullable<T[K]>[]): TypedQuery<T, One>;
|
|
220
|
+
whereExists(correlation: Correlation, subquery: TypedQuery<Row, boolean> | Query, negated?: boolean): TypedQuery<T, One>;
|
|
221
|
+
/**
|
|
222
|
+
* Add a nested relationship. The result type gains `name`: a `R[]` array, or
|
|
223
|
+
* `R | undefined` if the child query was `.one()`.
|
|
224
|
+
*/
|
|
225
|
+
related<Name extends string, R extends Row, ROne extends boolean>(name: Name, correlation: Correlation, subquery: TypedQuery<R, ROne>): TypedQuery<T & {
|
|
226
|
+
[K in Name]: ROne extends true ? R | undefined : R[];
|
|
227
|
+
}, One>;
|
|
228
|
+
orderBy<K extends keyof T & string>(field: K, dir: Direction): TypedQuery<T, One>;
|
|
229
|
+
limit(n: number): TypedQuery<T, One>;
|
|
230
|
+
one(): TypedQuery<T, true>;
|
|
231
|
+
start(row: Partial<T>, exclusive?: boolean): TypedQuery<T, One>;
|
|
232
|
+
/** The underlying untyped query (escape hatch). */
|
|
233
|
+
query(): Query;
|
|
234
|
+
ast(): AST;
|
|
235
|
+
/** Materialize into a live, typed view. */
|
|
236
|
+
materialize(): ViewLike<T>;
|
|
237
|
+
}
|
|
238
|
+
/** The last hop of a relationship chain (direct → only; junction → second). */
|
|
239
|
+
type LastConn<R extends Relationship> = R extends readonly [Connection] ? R[0] : R extends readonly [Connection, infer Second extends Connection] ? Second : never;
|
|
240
|
+
/** The relationships declared for table `N` of schema `S`. */
|
|
241
|
+
type RelsOf<S extends SchemaDef, N extends string> = N extends keyof S['relationships'] ? S['relationships'][N] : Record<never, never>;
|
|
242
|
+
/** Relationship names available on table `N`. */
|
|
243
|
+
type RelNames<S extends SchemaDef, N extends string> = keyof RelsOf<S, N> & string;
|
|
244
|
+
type RelChain<S extends SchemaDef, N extends string, Rel extends RelNames<S, N>> = RelsOf<S, N>[Rel] extends Relationship ? RelsOf<S, N>[Rel] : never;
|
|
245
|
+
/** Destination table name of relationship `Rel` (last hop). */
|
|
246
|
+
type DestName<S extends SchemaDef, N extends string, Rel extends RelNames<S, N>> = LastConn<RelChain<S, N, Rel>>['destSchema'] & string;
|
|
247
|
+
/** `'one' | 'many'` of relationship `Rel` (last hop). */
|
|
248
|
+
type DestCard<S extends SchemaDef, N extends string, Rel extends RelNames<S, N>> = LastConn<RelChain<S, N, Rel>>['cardinality'];
|
|
249
|
+
/** The row type of a named table in the schema. */
|
|
250
|
+
type TableRow<S extends SchemaDef, Name extends string> = Name extends keyof S['tables'] ? RowOf<S['tables'][Name]> : Row;
|
|
251
|
+
/** Apply cardinality (relationship `many`/`one`, or a `.one()` child) to a row type. */
|
|
252
|
+
type WithCard<Card extends Cardinality, R extends Row, ChildOne extends boolean> = (Card extends 'one' ? true : ChildOne) extends true ? R | undefined : R[];
|
|
253
|
+
type Cardinality = 'one' | 'many';
|
|
254
|
+
/** Result shape of `.related(rel)` with no callback (uses the schema row + cardinality). */
|
|
255
|
+
type RelResult<S extends SchemaDef, N extends string, Rel extends RelNames<S, N>> = WithCard<DestCard<S, N, Rel>, TableRow<S, DestName<S, N, Rel>>, false>;
|
|
256
|
+
declare class SchemaQuery<S extends SchemaDef, N extends string, T extends Row, One extends boolean = false> implements Subscribable<T> {
|
|
257
|
+
#private;
|
|
258
|
+
constructor(host: QueryHost | null, schema: S, table: N, q: Query);
|
|
259
|
+
where<K extends keyof T & string>(field: K, op: SimpleOperator, value: T[K] | readonly NonNullable<T[K]>[]): SchemaQuery<S, N, T, One>;
|
|
260
|
+
whereExists(correlation: Correlation, subquery: SchemaQuery<S, string, Row, boolean> | Query, negated?: boolean): SchemaQuery<S, N, T, One>;
|
|
261
|
+
orderBy<K extends keyof T & string>(field: K, dir: Direction): SchemaQuery<S, N, T, One>;
|
|
262
|
+
limit(n: number): SchemaQuery<S, N, T, One>;
|
|
263
|
+
one(): SchemaQuery<S, N, T, true>;
|
|
264
|
+
start(row: Partial<T>, exclusive?: boolean): SchemaQuery<S, N, T, One>;
|
|
265
|
+
/** Add a relationship by name (resolved from the schema), with an optional child query. */
|
|
266
|
+
related<Rel extends RelNames<S, N>>(name: Rel): SchemaQuery<S, N, T & {
|
|
267
|
+
[K in Rel]: RelResult<S, N, Rel>;
|
|
268
|
+
}, One>;
|
|
269
|
+
related<Rel extends RelNames<S, N>, CT extends Row, COne extends boolean>(name: Rel, cb: (q: SchemaQuery<S, DestName<S, N, Rel>, TableRow<S, DestName<S, N, Rel>>>) => SchemaQuery<S, string, CT, COne>): SchemaQuery<S, N, T & {
|
|
270
|
+
[K in Rel]: WithCard<DestCard<S, N, Rel>, CT, COne>;
|
|
271
|
+
}, One>;
|
|
272
|
+
/** Add a relationship with an explicit correlation (schema-less escape hatch). */
|
|
273
|
+
related<Name extends string, R extends Row, ROne extends boolean>(name: Name, correlation: Correlation, subquery: SchemaQuery<S, string, R, ROne> | TypedQuery<R, ROne> | Query): SchemaQuery<S, N, T & {
|
|
274
|
+
[K in Name]: ROne extends true ? R | undefined : R[];
|
|
275
|
+
}, One>;
|
|
276
|
+
isSingular(): boolean;
|
|
277
|
+
/** The underlying untyped query (escape hatch). */
|
|
278
|
+
query(): Query;
|
|
279
|
+
ast(): AST;
|
|
280
|
+
materialize(): ViewLike<T>;
|
|
281
|
+
}
|
|
282
|
+
/** Every table of a schema as a {@link SchemaQuery}, optionally bound to a host. */
|
|
283
|
+
type SchemaQueries<S extends SchemaDef> = {
|
|
284
|
+
[K in keyof S['tables'] & string]: SchemaQuery<S, K, RowOf<S['tables'][K]>>;
|
|
285
|
+
};
|
|
286
|
+
/**
|
|
287
|
+
* Standalone, schema-aware query builders (mirrors Zero's `createBuilder`). Use
|
|
288
|
+
* inside query definitions: `builder.issue.where('id', '=', args.id).related('author')`.
|
|
289
|
+
* Relationships declared in the schema are available by name and fully typed. The
|
|
290
|
+
* returned queries are unbound (used to produce ASTs, not subscribed directly).
|
|
291
|
+
*/
|
|
292
|
+
declare function createBuilder<S extends SchemaDef>(schema: S): SchemaQueries<S>;
|
|
293
|
+
/** Build the per-table {@link SchemaQuery} map, optionally bound to a host. */
|
|
294
|
+
declare function buildSchemaQueries<S extends SchemaDef>(schema: S, host: QueryHost | null): SchemaQueries<S>;
|
|
295
|
+
|
|
296
|
+
export { type AST as A, type CrudOp as C, type Direction as D, type Mutation as M, type OrderPart as O, PROTOCOL_VERSION as P, type QueryBuilder as Q, type Row as R, type Subscribable as S, TypedQuery as T, type Upstream as U, type Value as V, type QueriesPatchOp as a, type RowPatchOp as b, type QueryHost as c, type SchemaQueries as d, Query as e, type Condition as f, type CorrelatedSubquery as g, type Correlation as h, type Downstream as i, SchemaQuery as j, type SimpleOperator as k, type ValuePosition as l, type ViewLike as m, buildSchemaQueries as n, createBuilder as o, hashAST as p, hashString as q };
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { R as Row, S as Subscribable } from './query-BMK1cXAS.js';
|
|
2
|
+
import './schema-BNM6bks7.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Subscribe to a query and re-render on change. Mirrors `useQuery` from
|
|
6
|
+
* `@rocicorp/zero/react`. Accepts a typed query (`orbit.query.todo`) or a named
|
|
7
|
+
* query (`orbit.queryNamed(...)`); the result is typed either way.
|
|
8
|
+
*
|
|
9
|
+
* ```tsx
|
|
10
|
+
* const todos = orbit.query.todo.orderBy('created', 'asc');
|
|
11
|
+
* const rows = useQuery(todos); // rows: Todo[]
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
declare function useQuery<T extends Row>(query: Subscribable<T>): T[];
|
|
15
|
+
|
|
16
|
+
export { useQuery };
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useRef, useState, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
// react/src/index.ts
|
|
4
|
+
function useQuery(query) {
|
|
5
|
+
const ref = useRef(null);
|
|
6
|
+
const [, force] = useState(0);
|
|
7
|
+
if (ref.current === null || ref.current.q !== query) {
|
|
8
|
+
ref.current = { q: query, view: query.materialize() };
|
|
9
|
+
}
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (ref.current === null || ref.current.q !== query) {
|
|
12
|
+
ref.current = { q: query, view: query.materialize() };
|
|
13
|
+
}
|
|
14
|
+
const entry = ref.current;
|
|
15
|
+
const unsub = entry.view.subscribe(() => force((n) => n + 1));
|
|
16
|
+
return () => {
|
|
17
|
+
unsub();
|
|
18
|
+
entry.view.destroy?.();
|
|
19
|
+
if (ref.current === entry) ref.current = null;
|
|
20
|
+
};
|
|
21
|
+
}, [query]);
|
|
22
|
+
return ref.current.view.data;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { useQuery };
|
|
26
|
+
//# sourceMappingURL=react.js.map
|
|
27
|
+
//# sourceMappingURL=react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../react/src/index.ts"],"names":[],"mappings":";;;AAeO,SAAS,SAAwB,KAAA,EAA6B;AAMnE,EAAA,MAAM,GAAA,GAAM,OAAyD,IAAI,CAAA;AACzE,EAAA,MAAM,GAAG,KAAK,CAAA,GAAI,SAAS,CAAC,CAAA;AAI5B,EAAA,IAAI,IAAI,OAAA,KAAY,IAAA,IAAQ,GAAA,CAAI,OAAA,CAAQ,MAAM,KAAA,EAAO;AACnD,IAAA,GAAA,CAAI,UAAU,EAAE,CAAA,EAAG,OAAO,IAAA,EAAM,KAAA,CAAM,aAAY,EAAE;AAAA,EACtD;AAEA,EAAA,SAAA,CAAU,MAAM;AAId,IAAA,IAAI,IAAI,OAAA,KAAY,IAAA,IAAQ,GAAA,CAAI,OAAA,CAAQ,MAAM,KAAA,EAAO;AACnD,MAAA,GAAA,CAAI,UAAU,EAAE,CAAA,EAAG,OAAO,IAAA,EAAM,KAAA,CAAM,aAAY,EAAE;AAAA,IACtD;AACA,IAAA,MAAM,QAAQ,GAAA,CAAI,OAAA;AAClB,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,IAAA,CAAK,SAAA,CAAU,MAAM,MAAM,CAAC,CAAA,KAAM,CAAA,GAAI,CAAC,CAAC,CAAA;AAC5D,IAAA,OAAO,MAAM;AACX,MAAA,KAAA,EAAM;AACN,MAAA,KAAA,CAAM,KAAK,OAAA,IAAU;AAGrB,MAAA,IAAI,GAAA,CAAI,OAAA,KAAY,KAAA,EAAO,GAAA,CAAI,OAAA,GAAU,IAAA;AAAA,IAC3C,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAEV,EAAA,OAAO,GAAA,CAAI,QAAS,IAAA,CAAK,IAAA;AAC3B","file":"react.js","sourcesContent":["// React bindings for Orbit, mirroring Zero's `@rocicorp/zero/react` `useQuery`.\n\nimport { useEffect, useRef, useState } from 'react';\nimport type { Row, Subscribable, ViewLike } from '../../client/src/index.ts';\n\n/**\n * Subscribe to a query and re-render on change. Mirrors `useQuery` from\n * `@rocicorp/zero/react`. Accepts a typed query (`orbit.query.todo`) or a named\n * query (`orbit.queryNamed(...)`); the result is typed either way.\n *\n * ```tsx\n * const todos = orbit.query.todo.orderBy('created', 'asc');\n * const rows = useQuery(todos); // rows: Todo[]\n * ```\n */\nexport function useQuery<T extends Row>(query: Subscribable<T>): T[] {\n // Track the live view together with the query it belongs to, so a *changed*\n // query (e.g. a route param flipping `issue({id})` to a new id without\n // remounting the component) re-materializes instead of showing the stale view.\n // The caller is expected to keep `query` referentially stable across renders\n // that don't change it (e.g. `useMemo`), as is conventional for query hooks.\n const ref = useRef<{ q: Subscribable<T>; view: ViewLike<T> } | null>(null);\n const [, force] = useState(0);\n\n // Materialize synchronously on first render or when the query changes, so this\n // render already reflects the current query.\n if (ref.current === null || ref.current.q !== query) {\n ref.current = { q: query, view: query.materialize() };\n }\n\n useEffect(() => {\n // The view may have been released by a prior cleanup (React Strict Mode's\n // double-invoke, or a query change between render and commit); ensure a live\n // view for THIS query.\n if (ref.current === null || ref.current.q !== query) {\n ref.current = { q: query, view: query.materialize() };\n }\n const entry = ref.current;\n const unsub = entry.view.subscribe(() => force((n) => n + 1));\n return () => {\n unsub();\n entry.view.destroy?.(); // releases the query subscription → enables TTL/GC\n // Only clear the shared ref if it still points at the view we just tore\n // down — a query change already replaced it with the next view.\n if (ref.current === entry) ref.current = null;\n };\n }, [query]);\n\n return ref.current!.view.data;\n}\n"]}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
type ValueType = 'string' | 'number' | 'boolean' | 'json' | 'null';
|
|
2
|
+
/** A column definition. The TS type it produces is carried in the `_type` phantom. */
|
|
3
|
+
type Column<T = unknown> = {
|
|
4
|
+
readonly type: ValueType;
|
|
5
|
+
readonly optional: boolean;
|
|
6
|
+
/** Phantom — never present at runtime; carries the column's TS type. */
|
|
7
|
+
readonly _type?: T;
|
|
8
|
+
};
|
|
9
|
+
declare const string: <T extends string = string>() => Column<T>;
|
|
10
|
+
declare const number: <T extends number = number>() => Column<T>;
|
|
11
|
+
declare const boolean: <T extends boolean = boolean>() => Column<T>;
|
|
12
|
+
declare const json: <T = unknown>() => Column<T>;
|
|
13
|
+
/** Mark a column nullable (its TS type gains `| null`). */
|
|
14
|
+
declare const optional: <T>(c: Column<T>) => Column<T | null>;
|
|
15
|
+
type Columns = Record<string, Column>;
|
|
16
|
+
type TableDef<Name extends string = string, C extends Columns = Columns, PK extends keyof C & string = keyof C & string> = {
|
|
17
|
+
readonly name: Name;
|
|
18
|
+
readonly columns: C;
|
|
19
|
+
readonly primaryKey: readonly PK[];
|
|
20
|
+
};
|
|
21
|
+
/** `table('todo').columns({ ... }).primaryKey('id')` */
|
|
22
|
+
declare function table<Name extends string>(name: Name): {
|
|
23
|
+
columns<C extends Columns>(columns: C): {
|
|
24
|
+
primaryKey<PK extends keyof C & string>(...primaryKey: PK[]): TableDef<Name, C, PK>;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
type Cardinality = 'one' | 'many';
|
|
28
|
+
/** One hop of a relationship: which fields correlate and to which table. */
|
|
29
|
+
type Connection = {
|
|
30
|
+
readonly sourceField: readonly string[];
|
|
31
|
+
readonly destField: readonly string[];
|
|
32
|
+
/** Destination table *name*. */
|
|
33
|
+
readonly destSchema: string;
|
|
34
|
+
readonly cardinality: Cardinality;
|
|
35
|
+
};
|
|
36
|
+
/** A relationship = a 1- (direct) or 2- (junction) element connection chain. */
|
|
37
|
+
type Relationship = readonly [Connection] | readonly [Connection, Connection];
|
|
38
|
+
/** The relationships declared for one source table. */
|
|
39
|
+
type RelationshipsDef<Name extends string = string, R extends Record<string, Relationship> = Record<string, Relationship>> = {
|
|
40
|
+
readonly name: Name;
|
|
41
|
+
readonly relationships: R;
|
|
42
|
+
};
|
|
43
|
+
/** A single hop's arguments, where `destSchema` is the destination *table def*. */
|
|
44
|
+
type ConnectArg<Dest extends TableDef = TableDef> = {
|
|
45
|
+
readonly sourceField: readonly string[];
|
|
46
|
+
readonly destField: readonly string[];
|
|
47
|
+
readonly destSchema: Dest;
|
|
48
|
+
};
|
|
49
|
+
type Connector<Card extends Cardinality> = {
|
|
50
|
+
<Dest extends TableDef>(arg: ConnectArg<Dest>): readonly [Connection & {
|
|
51
|
+
destSchema: Dest['name'];
|
|
52
|
+
cardinality: Card;
|
|
53
|
+
}];
|
|
54
|
+
<Junction extends TableDef, Dest extends TableDef>(first: ConnectArg<Junction>, second: ConnectArg<Dest>): readonly [
|
|
55
|
+
Connection & {
|
|
56
|
+
destSchema: Junction['name'];
|
|
57
|
+
cardinality: Card;
|
|
58
|
+
},
|
|
59
|
+
Connection & {
|
|
60
|
+
destSchema: Dest['name'];
|
|
61
|
+
cardinality: Card;
|
|
62
|
+
}
|
|
63
|
+
];
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Declare the relationships for `table` (mirrors Zero's `relationships`). Pass a
|
|
67
|
+
* callback that builds named relationships with `one(...)` / `many(...)`:
|
|
68
|
+
*
|
|
69
|
+
* ```ts
|
|
70
|
+
* relationships(issue, ({ one, many }) => ({
|
|
71
|
+
* author: one({ sourceField: ['authorId'], destField: ['id'], destSchema: user }),
|
|
72
|
+
* comments: many({ sourceField: ['id'], destField: ['issueId'], destSchema: comment }),
|
|
73
|
+
* labels: many(
|
|
74
|
+
* { sourceField: ['id'], destField: ['issueId'], destSchema: issueLabel },
|
|
75
|
+
* { sourceField: ['labelId'], destField: ['id'], destSchema: label },
|
|
76
|
+
* ),
|
|
77
|
+
* }));
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
declare function relationships<Name extends string, R extends Record<string, Relationship>>(table: TableDef<Name>, cb: (connectors: {
|
|
81
|
+
one: Connector<'one'>;
|
|
82
|
+
many: Connector<'many'>;
|
|
83
|
+
}) => R): RelationshipsDef<Name, R>;
|
|
84
|
+
/** Relationships keyed by source-table name (the shape stored on a schema). */
|
|
85
|
+
type RelationshipsMap = Record<string, Record<string, Relationship>>;
|
|
86
|
+
type SchemaDef<T extends Record<string, TableDef> = Record<string, TableDef>, R extends RelationshipsMap = RelationshipsMap> = {
|
|
87
|
+
readonly tables: T;
|
|
88
|
+
readonly relationships: R;
|
|
89
|
+
};
|
|
90
|
+
/** Combine table + relationship defs into a schema keyed by table name. */
|
|
91
|
+
declare function createSchema<const T extends readonly TableDef[], const R extends readonly RelationshipsDef[] = []>(def: {
|
|
92
|
+
tables: T;
|
|
93
|
+
relationships?: R;
|
|
94
|
+
}): SchemaDef<{
|
|
95
|
+
[K in T[number] as K['name']]: K;
|
|
96
|
+
}, {
|
|
97
|
+
[K in R[number] as K['name']]: K['relationships'];
|
|
98
|
+
}>;
|
|
99
|
+
/** The row type of a table def (column name -> TS value type). */
|
|
100
|
+
type RowOf<T extends TableDef> = {
|
|
101
|
+
[K in keyof T['columns']]: T['columns'][K] extends Column<infer V> ? V : never;
|
|
102
|
+
};
|
|
103
|
+
/** The primary-key column names of a table def. */
|
|
104
|
+
type PkOf<T extends TableDef> = T['primaryKey'][number];
|
|
105
|
+
/** A permissive schema, used when no schema is supplied (everything is loose). */
|
|
106
|
+
type AnySchema = SchemaDef<Record<string, TableDef>>;
|
|
107
|
+
|
|
108
|
+
export { type AnySchema as A, type Connection as C, type PkOf as P, type RowOf as R, type SchemaDef as S, type TableDef as T, type ValueType as V, type Relationship as a, type Cardinality as b, type Column as c, type Columns as d, type RelationshipsDef as e, type RelationshipsMap as f, boolean as g, createSchema as h, json as j, number as n, optional as o, relationships as r, string as s, table as t };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import pg from 'pg';
|
|
2
|
+
import { DBConnection } from '../server.js';
|
|
3
|
+
import '../query-BMK1cXAS.js';
|
|
4
|
+
import '../schema-BNM6bks7.js';
|
|
5
|
+
import '../custom-DzMQ-nY2.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Wrap a node-postgres `Pool`/`Client` (or a connection string / config) as a
|
|
9
|
+
* `DBConnection` for `PushProcessor`.
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { nodePg } from '@zeronsh/orbit/server/pg';
|
|
13
|
+
* const connection = nodePg(process.env.DATABASE_URL!);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
declare function nodePg(db: pg.Pool | pg.Client | pg.PoolConfig | string): DBConnection;
|
|
17
|
+
|
|
18
|
+
export { nodePg };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import pg from 'pg';
|
|
2
|
+
|
|
3
|
+
// server/src/pg.ts
|
|
4
|
+
function nodePg(db) {
|
|
5
|
+
const pool = typeof db === "string" ? new pg.Pool({ connectionString: db }) : db instanceof pg.Pool || db instanceof pg.Client ? db : new pg.Pool(db);
|
|
6
|
+
return {
|
|
7
|
+
async transaction(fn) {
|
|
8
|
+
const client = pool instanceof pg.Pool ? await pool.connect() : pool;
|
|
9
|
+
const tx = {
|
|
10
|
+
async query(sql, params) {
|
|
11
|
+
const res = await client.query(sql, params);
|
|
12
|
+
return res.rows;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
try {
|
|
16
|
+
await client.query("BEGIN");
|
|
17
|
+
const result = await fn(tx);
|
|
18
|
+
await client.query("COMMIT");
|
|
19
|
+
return result;
|
|
20
|
+
} catch (e) {
|
|
21
|
+
try {
|
|
22
|
+
await client.query("ROLLBACK");
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
25
|
+
throw e;
|
|
26
|
+
} finally {
|
|
27
|
+
if (pool instanceof pg.Pool) client.release();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { nodePg };
|
|
34
|
+
//# sourceMappingURL=pg.js.map
|
|
35
|
+
//# sourceMappingURL=pg.js.map
|