@vsrepo/drizzle-adapter 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.
@@ -0,0 +1,184 @@
1
+ import { KeysOfType, Primitive, RelationKeys, VSRepoAdapter, VSRepoTransactionOptions, AdapterQueryOptions, VSRepoWhere, AdapterMethodOptions, DeepPartial, CountResult, NumericKeys } from 'vsrepo';
2
+ import { SQLWrapper, Table } from 'drizzle-orm';
3
+
4
+ /**
5
+ * @publicApi
6
+ */
7
+ type DrizzleTransactionLike = DrizzleDbLike & {
8
+ rollback(): never;
9
+ };
10
+
11
+ type Fn = (...args: any[]) => any;
12
+ /**
13
+ * @publicApi
14
+ */
15
+ type DrizzleDbLike = {
16
+ select: Fn;
17
+ insert: Fn;
18
+ update: Fn;
19
+ delete: Fn;
20
+ query: Record<string, {
21
+ findFirst: Fn;
22
+ findMany: Fn;
23
+ }>;
24
+ selectDistinct: (fields: object) => {
25
+ from: (table: any) => any;
26
+ };
27
+ execute: (query: SQLWrapper) => Promise<any>;
28
+ transaction: <R>(fn: (tx: DrizzleTransactionLike) => Promise<R>, config?: any) => Promise<R>;
29
+ };
30
+
31
+ /**
32
+ * @publicApi
33
+ */
34
+ type SupportedDialects = "postgresql" | "sqlite" | "cockroach";
35
+
36
+ /**
37
+ * @publicApi
38
+ */
39
+ type AdapterRelation<T, K> = {
40
+ restriction: "set" | "add";
41
+ table: Table;
42
+ fkHere?: KeysOfType<T, Primitive>;
43
+ fkThere?: KeysOfType<K, Primitive>;
44
+ } & ({
45
+ mode: "otm";
46
+ fkThere: KeysOfType<K, Primitive>;
47
+ fkHere?: never;
48
+ } | {
49
+ mode: "mto";
50
+ nullable?: boolean;
51
+ fkHere: KeysOfType<T, Primitive>;
52
+ } | ({
53
+ mode: "oto";
54
+ } & ({
55
+ fkHere: KeysOfType<T, Primitive>;
56
+ fkThere?: never;
57
+ } | {
58
+ fkThere: KeysOfType<K, Primitive>;
59
+ fkHere?: never;
60
+ })));
61
+
62
+ /**
63
+ * @publicApi
64
+ */
65
+ type AdapterRelations<T> = Partial<{
66
+ [P in RelationKeys<T>]: AdapterRelation<T, NonNullable<T[P]> extends Array<infer U> ? U : NonNullable<T[P]>>;
67
+ }>;
68
+
69
+ /**
70
+ * @publicApi
71
+ */
72
+ type DrizzleAdapterConfig<T, K extends DrizzleDbLike = DrizzleDbLike> = {
73
+ table: Table;
74
+ dialect?: SupportedDialects;
75
+ queryKey: keyof K["query"];
76
+ relations?: AdapterRelations<T>;
77
+ };
78
+
79
+ /**
80
+ * @publicApi
81
+ */
82
+ declare class DrizzleAdapter<T, K extends DrizzleDbLike = DrizzleDbLike> extends VSRepoAdapter<T> {
83
+ private readonly table;
84
+ private readonly db;
85
+ private readonly dialect;
86
+ private readonly pk;
87
+ private readonly queryKey;
88
+ private readonly relations?;
89
+ constructor(db: K, config: DrizzleAdapterConfig<T, K>);
90
+ /**
91
+ * Returns `db.query[queryKey]` (the relational query builder entry for
92
+ * this adapter's table), reading from `db` when a transaction/executor
93
+ * override is passed via `options.db`, otherwise from the root client.
94
+ */
95
+ private getQueryBuilder;
96
+ /**
97
+ * Resolves the "read" part of a query arg: `columns`/`with`/`where`/
98
+ * `orderBy`/pagination.
99
+ *
100
+ * Per the adapter contract: when both `select` and `relations` are
101
+ * given, `select` wins and `relations` is ignored entirely.
102
+ */
103
+ private resolveReadArgs;
104
+ /** Builds the context `parseSqlWhere` needs to resolve `_with`/`_without`/`_some`/`_every`/`_none` relation filters. */
105
+ private getSqlWhereContext;
106
+ /**
107
+ * Resolves a user-supplied `VSRepoWhere<T>` into the `where` shape the
108
+ * relational query API (`db.query[queryKey].findFirst/findMany`) accepts.
109
+ *
110
+ * The relational API's own object-shaped `where` (`where.parser.ts`) has
111
+ * no native `_every`/`_none` semantics for to-many relations — so when
112
+ * `where` contains one (`hasQuantifierFilter`), this instead:
113
+ * 1. Resolves `where` into a `SQL` condition via `sql-where.parser.ts`
114
+ * (which DOES support `_every`/`_none`, via `NOT EXISTS`);
115
+ * 2. Runs `db.select({pk}).from(table).where(condition)`, applying the
116
+ * SAME `order`/`limit`/`offset` the final query would've used
117
+ * (`sql-order-by.parser.ts`), so the prefetch only ever pulls the
118
+ * rows the caller actually needs, instead of every matching row;
119
+ * 3. Returns `parseDrizzleWhere({ [pk]: { in: pks } })` instead — the
120
+ * relational API then only has to filter by pk (trivial for it),
121
+ * while still handling `columns`/`with` on the correct result set.
122
+ *
123
+ * Since SQL `IN (...)` doesn't preserve the given list's order, `resolveReadArgs`
124
+ * re-applies `orderBy` (but NOT `limit`/`offset`, already baked into the pk set)
125
+ * on the final relational query when `paginationApplied` comes back `true`.
126
+ *
127
+ * This keeps `_every`/`_none` support consistent between this adapter's
128
+ * two `where` parsers — from the outside, `findOne`/`findMany`/etc. never
129
+ * throw `NOT_SUPPORTED` for them, at the cost of an extra round-trip only
130
+ * when they're actually used.
131
+ */
132
+ private resolveFindWhere;
133
+ /**
134
+ * Strips relation fields from a payload — used by `createMany`/`updateMany`/
135
+ * `updateManyReturning`, since batch statements only accept flat column
136
+ * data (no nested writes). Throws `VSRepoAdapterError` (code
137
+ * `NOT_SUPPORTED`) instead of silently dropping the field, when a
138
+ * configured relation field is present in the payload.
139
+ */
140
+ private stripRelationFields;
141
+ private isRootClient;
142
+ private runTransactional;
143
+ runInTransaction<R>(fn: (tx: DrizzleTransactionLike) => Promise<R>, options?: VSRepoTransactionOptions): Promise<R>;
144
+ getDbClient(): DrizzleDbLike;
145
+ query<R = any>(rawQuery: string, options?: AdapterQueryOptions): Promise<R>;
146
+ findOne(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T | null>;
147
+ findOneOrThrow(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T>;
148
+ findMany(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T> & {
149
+ distinct?: (keyof T)[];
150
+ }): Promise<T[]>;
151
+ save(obj: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<T>;
152
+ saveMany(objs: DeepPartial<T>[], options?: AdapterMethodOptions<T>): Promise<T[]>;
153
+ create(obj: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<T>;
154
+ createMany(objs: DeepPartial<T>[], options?: AdapterMethodOptions<T> & {
155
+ ignoreConflicts?: boolean;
156
+ }): Promise<CountResult>;
157
+ createManyReturning(objs: DeepPartial<T>[], options?: AdapterMethodOptions<T> & {
158
+ ignoreConflicts?: boolean;
159
+ }): Promise<T[]>;
160
+ delete(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T>;
161
+ deleteMany(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<CountResult>;
162
+ deleteManyReturning(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T[]>;
163
+ update(where: VSRepoWhere<T>, obj: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<T>;
164
+ updateMany(where: VSRepoWhere<T>, obj: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<CountResult>;
165
+ updateManyReturning(where: VSRepoWhere<T>, obj: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<T[]>;
166
+ count(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<number>;
167
+ exists(where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<boolean>;
168
+ merge<K>(where: VSRepoWhere<T>, obj: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<K & T>;
169
+ upsert(where: VSRepoWhere<T>, create: DeepPartial<T>, update: DeepPartial<T>, options?: AdapterMethodOptions<T>): Promise<T>;
170
+ /** Shared implementation behind `incrementOne`/`decrementOne`/`multiplyOne`/`divideOne`. */
171
+ private atomicUpdate;
172
+ incrementOne<K extends NumericKeys<T>>(field: K, value: NonNullable<T[K]>, where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T>;
173
+ decrementOne<K extends NumericKeys<T>>(field: K, value: NonNullable<T[K]>, where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T>;
174
+ multiplyOne<K extends NumericKeys<T>>(field: K, value: NonNullable<T[K]>, where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T>;
175
+ divideOne<K extends NumericKeys<T>>(field: K, value: NonNullable<T[K]>, where: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<T>;
176
+ /** Shared implementation behind `sum`/`average`/`min`/`max`. */
177
+ private aggregate;
178
+ sum(field: NumericKeys<T>, where?: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<number | null>;
179
+ average(field: NumericKeys<T>, where?: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<number | null>;
180
+ min(field: NumericKeys<T>, where?: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<number | null>;
181
+ max(field: NumericKeys<T>, where?: VSRepoWhere<T>, options?: AdapterMethodOptions<T>): Promise<number | null>;
182
+ }
183
+
184
+ export { DrizzleAdapter, type DrizzleAdapterConfig, type DrizzleDbLike, type DrizzleTransactionLike, type SupportedDialects };