@vertz/db 0.2.0 → 0.2.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.
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Database driver interface.
3
+ *
4
+ * Provides a unified interface for different database backends
5
+ * (PostgreSQL, SQLite/D1, etc.) with query and execute methods.
6
+ */
7
+ interface DbDriver {
8
+ /**
9
+ * Execute a read query and return results.
10
+ */
11
+ query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;
12
+ /**
13
+ * Execute a write query and return affected row count.
14
+ */
15
+ execute(sql: string, params?: unknown[]): Promise<{
16
+ rowsAffected: number;
17
+ }>;
18
+ /**
19
+ * Close the database connection.
20
+ */
21
+ close(): Promise<void>;
22
+ }
23
+ interface JsonbValidator<T> {
24
+ parse(value: unknown): T;
25
+ }
26
+ interface ColumnMetadata {
27
+ readonly sqlType: string;
28
+ readonly primary: boolean;
29
+ readonly unique: boolean;
30
+ readonly nullable: boolean;
31
+ readonly hasDefault: boolean;
32
+ readonly _annotations: Record<string, true>;
33
+ readonly isReadOnly: boolean;
34
+ readonly isAutoUpdate: boolean;
35
+ readonly isTenant: boolean;
36
+ readonly references: {
37
+ readonly table: string;
38
+ readonly column: string;
39
+ } | null;
40
+ readonly check: string | null;
41
+ readonly defaultValue?: unknown;
42
+ readonly format?: string;
43
+ readonly length?: number;
44
+ readonly precision?: number;
45
+ readonly scale?: number;
46
+ readonly enumName?: string;
47
+ readonly enumValues?: readonly string[];
48
+ readonly validator?: JsonbValidator<unknown>;
49
+ readonly generate?: "cuid" | "uuid" | "nanoid";
50
+ }
51
+ /** Phantom symbol to carry the TypeScript type without a runtime value. */
52
+ declare const PhantomType: unique symbol;
53
+ interface ColumnBuilder<
54
+ TType,
55
+ TMeta extends ColumnMetadata = ColumnMetadata
56
+ > {
57
+ /** Phantom field -- only exists at the type level for inference. Do not access at runtime. */
58
+ readonly [PhantomType]: TType;
59
+ readonly _meta: TMeta;
60
+ primary(options?: {
61
+ generate?: "cuid" | "uuid" | "nanoid";
62
+ }): ColumnBuilder<TType, Omit<TMeta, "primary" | "hasDefault" | "generate"> & {
63
+ readonly primary: true;
64
+ readonly hasDefault: true;
65
+ readonly generate?: "cuid" | "uuid" | "nanoid";
66
+ }>;
67
+ unique(): ColumnBuilder<TType, Omit<TMeta, "unique"> & {
68
+ readonly unique: true;
69
+ }>;
70
+ nullable(): ColumnBuilder<TType | null, Omit<TMeta, "nullable"> & {
71
+ readonly nullable: true;
72
+ }>;
73
+ default(value: TType | "now"): ColumnBuilder<TType, Omit<TMeta, "hasDefault"> & {
74
+ readonly hasDefault: true;
75
+ readonly defaultValue: TType | "now";
76
+ }>;
77
+ is<TFlag extends string>(flag: TFlag): ColumnBuilder<TType, Omit<TMeta, "_annotations"> & {
78
+ readonly _annotations: TMeta["_annotations"] & { readonly [K in TFlag] : true };
79
+ }>;
80
+ readOnly(): ColumnBuilder<TType, Omit<TMeta, "isReadOnly"> & {
81
+ readonly isReadOnly: true;
82
+ }>;
83
+ autoUpdate(): ColumnBuilder<TType, Omit<TMeta, "isAutoUpdate" | "isReadOnly"> & {
84
+ readonly isAutoUpdate: true;
85
+ readonly isReadOnly: true;
86
+ }>;
87
+ check(sql: string): ColumnBuilder<TType, Omit<TMeta, "check"> & {
88
+ readonly check: string;
89
+ }>;
90
+ references(table: string, column?: string): ColumnBuilder<TType, Omit<TMeta, "references"> & {
91
+ readonly references: {
92
+ readonly table: string;
93
+ readonly column: string;
94
+ };
95
+ }>;
96
+ }
97
+ type InferColumnType<C> = C extends ColumnBuilder<infer T, ColumnMetadata> ? T : never;
98
+ interface IndexDef {
99
+ readonly columns: readonly string[];
100
+ readonly name?: string;
101
+ readonly unique?: boolean;
102
+ }
103
+ /** A record of column builders -- the shape passed to d.table(). */
104
+ type ColumnRecord = Record<string, ColumnBuilder<unknown, ColumnMetadata>>;
105
+ /** Extract the TypeScript type from every column in a record. */
106
+ type InferColumns<T extends ColumnRecord> = { [K in keyof T] : InferColumnType<T[K]> };
107
+ /** Keys of columns where a given metadata property is `true`. */
108
+ type ColumnKeysWhere<
109
+ T extends ColumnRecord,
110
+ Flag extends keyof ColumnMetadata
111
+ > = { [K in keyof T] : T[K] extends ColumnBuilder<unknown, infer M> ? M extends Record<Flag, true> ? K : never : never }[keyof T];
112
+ /** Keys of columns where a given metadata property is NOT `true` (i.e., false). */
113
+ type ColumnKeysWhereNot<
114
+ T extends ColumnRecord,
115
+ Flag extends keyof ColumnMetadata
116
+ > = { [K in keyof T] : T[K] extends ColumnBuilder<unknown, infer M> ? M extends Record<Flag, true> ? never : K : never }[keyof T];
117
+ /** Keys of columns that do NOT have ANY of the specified annotations in `_annotations`. */
118
+ type ColumnKeysWithoutAnyAnnotation<
119
+ T extends ColumnRecord,
120
+ Annotations extends string
121
+ > = { [K in keyof T] : T[K] extends ColumnBuilder<unknown, infer M> ? M["_annotations"] extends Record<Annotations, true> ? never : K : never }[keyof T];
122
+ /**
123
+ * $infer -- default SELECT type.
124
+ * Excludes columns annotated 'hidden'. Includes everything else.
125
+ */
126
+ type Infer<T extends ColumnRecord> = { [K in ColumnKeysWithoutAnyAnnotation<T, "hidden">] : InferColumnType<T[K]> };
127
+ /**
128
+ * $infer_all -- all columns including hidden.
129
+ */
130
+ type InferAll<T extends ColumnRecord> = InferColumns<T>;
131
+ /**
132
+ * $insert -- write type. ALL columns included (visibility is read-side only).
133
+ * Columns with hasDefault: true become optional.
134
+ */
135
+ type Insert<T extends ColumnRecord> = { [K in ColumnKeysWhereNot<T, "hasDefault">] : InferColumnType<T[K]> } & { [K in ColumnKeysWhere<T, "hasDefault">]? : InferColumnType<T[K]> };
136
+ /**
137
+ * $update -- write type. ALL non-primary-key columns, all optional.
138
+ * Primary key excluded (you don't update a PK).
139
+ */
140
+ type Update<T extends ColumnRecord> = { [K in ColumnKeysWhereNot<T, "primary">]? : InferColumnType<T[K]> };
141
+ /**
142
+ * $response -- API response shape. Excludes columns annotated 'hidden'.
143
+ */
144
+ type Response<T extends ColumnRecord> = { [K in ColumnKeysWithoutAnyAnnotation<T, "hidden">] : InferColumnType<T[K]> };
145
+ /**
146
+ * $create_input -- API create input shape.
147
+ * Excludes readOnly and primary key columns.
148
+ * Columns with defaults are optional.
149
+ */
150
+ type ApiCreateInput<T extends ColumnRecord> = { [K in ColumnKeysWhereNot<T, "isReadOnly"> & ColumnKeysWhereNot<T, "primary"> & ColumnKeysWhereNot<T, "hasDefault"> & string] : InferColumnType<T[K]> } & { [K in ColumnKeysWhereNot<T, "isReadOnly"> & ColumnKeysWhereNot<T, "primary"> & ColumnKeysWhere<T, "hasDefault"> & string]? : InferColumnType<T[K]> };
151
+ /**
152
+ * $update_input -- API update input shape.
153
+ * Excludes readOnly and primary key columns. All fields optional (partial update).
154
+ */
155
+ type ApiUpdateInput<T extends ColumnRecord> = { [K in ColumnKeysWhereNot<T, "isReadOnly"> & ColumnKeysWhereNot<T, "primary"> & string]? : InferColumnType<T[K]> };
156
+ interface TableDef<TColumns extends ColumnRecord = ColumnRecord> {
157
+ readonly _name: string;
158
+ readonly _columns: TColumns;
159
+ readonly _indexes: readonly IndexDef[];
160
+ readonly _shared: boolean;
161
+ /** Default SELECT type -- excludes columns annotated 'hidden'. */
162
+ readonly $infer: Infer<TColumns>;
163
+ /** All columns including hidden. */
164
+ readonly $infer_all: InferAll<TColumns>;
165
+ /** Insert type -- defaulted columns optional. ALL columns included. */
166
+ readonly $insert: Insert<TColumns>;
167
+ /** Update type -- all non-PK columns optional. ALL columns included. */
168
+ readonly $update: Update<TColumns>;
169
+ /** API response shape — excludes columns annotated 'hidden'. */
170
+ readonly $response: Response<TColumns>;
171
+ /** API create input — excludes readOnly + PK; defaulted columns optional. */
172
+ readonly $create_input: ApiCreateInput<TColumns>;
173
+ /** API update input — excludes readOnly + PK; all fields optional. */
174
+ readonly $update_input: ApiUpdateInput<TColumns>;
175
+ /** Mark this table as shared / cross-tenant. */
176
+ shared(): TableDef<TColumns>;
177
+ }
178
+ /**
179
+ * Database Adapter Types for @vertz/db
180
+ *
181
+ * Generic adapter interface that abstracts database operations.
182
+ * Implemented by SQLite, D1, and other database adapters.
183
+ */
184
+ interface ListOptions {
185
+ where?: Record<string, unknown>;
186
+ orderBy?: Record<string, "asc" | "desc">;
187
+ limit?: number;
188
+ /** Cursor-based pagination: fetch records after this ID. */
189
+ after?: string;
190
+ }
191
+ interface EntityDbAdapter {
192
+ get(id: string): Promise<Record<string, unknown> | null>;
193
+ list(options?: ListOptions): Promise<{
194
+ data: Record<string, unknown>[];
195
+ total: number;
196
+ }>;
197
+ create(data: Record<string, unknown>): Promise<Record<string, unknown>>;
198
+ update(id: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
199
+ delete(id: string): Promise<Record<string, unknown> | null>;
200
+ }
201
+ interface D1DatabaseBinding {
202
+ prepare(sql: string): D1PreparedStatement;
203
+ }
204
+ interface D1PreparedStatement {
205
+ bind(...values: unknown[]): D1PreparedStatement;
206
+ all(): Promise<{
207
+ results: unknown[];
208
+ }>;
209
+ run(): Promise<{
210
+ meta: {
211
+ changes: number;
212
+ };
213
+ }>;
214
+ }
215
+ interface D1AdapterOptions<T extends ColumnRecord> {
216
+ /** The table schema definition */
217
+ schema: TableDef<T>;
218
+ /** D1 database binding from Cloudflare env */
219
+ d1: D1DatabaseBinding;
220
+ /**
221
+ * Whether migrations should be applied at runtime.
222
+ * NOTE: For D1, migrations should typically be run via `wrangler d1 migrations apply`
223
+ * during deployment, not at runtime. Set to false for production use.
224
+ */
225
+ migrations?: {
226
+ autoApply?: boolean;
227
+ };
228
+ }
229
+ /**
230
+ * Create a DbDriver from a D1 database binding.
231
+ */
232
+ declare function createD1Driver(d1: D1DatabaseBinding): DbDriver;
233
+ /**
234
+ * Create a D1 EntityDbAdapter from a schema and D1 binding.
235
+ *
236
+ * NOTE: For production D1 deployments, migrations should be run via
237
+ * `wrangler d1 migrations apply` during deployment, NOT at runtime.
238
+ * Set `migrations.autoApply = false` or omit the migrations option for production.
239
+ */
240
+ declare function createD1Adapter<T extends ColumnRecord>(options: D1AdapterOptions<T>): EntityDbAdapter;
241
+ export { createD1Driver, createD1Adapter, D1PreparedStatement, D1DatabaseBinding, D1AdapterOptions };
@@ -0,0 +1,8 @@
1
+ import {
2
+ createD1Adapter,
3
+ createD1Driver
4
+ } from "../shared/chunk-ktbebkz5.js";
5
+ export {
6
+ createD1Driver,
7
+ createD1Adapter
8
+ };
@@ -2,7 +2,7 @@ import {
2
2
  diagnoseError,
3
3
  explainError,
4
4
  formatDiagnostic
5
- } from "../shared/chunk-wj026daz.js";
5
+ } from "../shared/chunk-k04v1jjx.js";
6
6
  export {
7
7
  formatDiagnostic,
8
8
  explainError,