@apisr/drizzle-model 0.0.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.
Files changed (47) hide show
  1. package/.turbo/turbo-check-types.log +2 -0
  2. package/ROADMAP.md +1 -0
  3. package/TODO.md +64 -0
  4. package/drizzle.config.ts +11 -0
  5. package/package.json +35 -0
  6. package/src/index.ts +1 -0
  7. package/src/model/builder.ts +46 -0
  8. package/src/model/config.ts +35 -0
  9. package/src/model/core/joins.ts +279 -0
  10. package/src/model/core/projection.ts +47 -0
  11. package/src/model/core/runtime.ts +249 -0
  12. package/src/model/core/thenable.ts +85 -0
  13. package/src/model/core/transform.ts +45 -0
  14. package/src/model/core/where.ts +183 -0
  15. package/src/model/core/with.ts +28 -0
  16. package/src/model/dialect.ts +11 -0
  17. package/src/model/foreigns.ts +31 -0
  18. package/src/model/format.ts +19 -0
  19. package/src/model/index.ts +1 -0
  20. package/src/model/methods/exclude.ts +32 -0
  21. package/src/model/methods/include.ts +3 -0
  22. package/src/model/methods/insert.ts +16 -0
  23. package/src/model/methods/levels.ts +2 -0
  24. package/src/model/methods/query/where.ts +48 -0
  25. package/src/model/methods/return.ts +39 -0
  26. package/src/model/methods/select.ts +38 -0
  27. package/src/model/methods/update.ts +4 -0
  28. package/src/model/methods/upsert.ts +54 -0
  29. package/src/model/methods/with.ts +40 -0
  30. package/src/model/model.ts +148 -0
  31. package/src/model/options.ts +64 -0
  32. package/src/model/query/operations.ts +170 -0
  33. package/src/model/relation.ts +121 -0
  34. package/src/model/result.ts +91 -0
  35. package/src/model/shape.ts +8 -0
  36. package/src/model/table.ts +127 -0
  37. package/src/types.ts +16 -0
  38. package/tests/builder-v2-mysql.type-test.ts +40 -0
  39. package/tests/builder-v2.type-test.ts +343 -0
  40. package/tests/builder.test.ts +63 -0
  41. package/tests/db.ts +25 -0
  42. package/tests/find.test.ts +155 -0
  43. package/tests/insert.test.ts +233 -0
  44. package/tests/relations.ts +38 -0
  45. package/tests/schema.ts +49 -0
  46. package/tsconfig.json +36 -0
  47. package/tsdown.config.ts +12 -0
@@ -0,0 +1,249 @@
1
+ import type { ModelDialect } from "../dialect.ts";
2
+ import type { ModelOptions } from "../options.ts";
3
+ import type { MethodUpsertValue } from "../methods/upsert.ts";
4
+ import type { MethodWhereValue } from "../methods/query/where.ts";
5
+ import type { MethodWithValue } from "../methods/with.ts";
6
+
7
+ import { and } from "drizzle-orm";
8
+ import { MutateResult, QueryResult } from "./thenable.ts";
9
+ import type { MutateState, QueryState } from "./thenable.ts";
10
+ import { applyExclude, applyFormat, applySelect } from "./transform.ts";
11
+ import { buildSelectProjection } from "./projection.ts";
12
+ import { compileWhere } from "./where.ts";
13
+ import { runWithJoins } from "./with.ts";
14
+ import type { ReturningIdDialects } from "../dialect.ts";
15
+
16
+ type AnyObj = Record<string, any>;
17
+
18
+ type MutateKind = "insert" | "update" | "delete" | "upsert";
19
+
20
+ type BaseState = {
21
+ db: any;
22
+ where: unknown;
23
+ };
24
+
25
+ // TODO: can be broken...
26
+ function compileEffectiveWhere(table: AnyObj, optionsWhere: unknown, stateWhere: unknown) {
27
+ const base = compileWhere(table, optionsWhere);
28
+ const extra = compileWhere(table, stateWhere);
29
+ if (base && extra) return and(base as any, extra as any);
30
+ return (base ?? extra) as any;
31
+ }
32
+
33
+ function isReturningIdDialect(dialect: string): dialect is ReturningIdDialects {
34
+ return dialect === "MySQL" || dialect === "SingleStore" || dialect === "CockroachDB";
35
+ }
36
+
37
+ async function execReturn(q: any, mState: MutateState, dialect: string): Promise<any> {
38
+ if (typeof q?.returning === "function") {
39
+ return await (mState.returnSelect ? q.returning(mState.returnSelect) : q.returning());
40
+ }
41
+ if (isReturningIdDialect(dialect) && typeof q?.$returningId === "function") {
42
+ return await q.$returningId();
43
+ }
44
+ return await q;
45
+ }
46
+
47
+ function normalizeUpsertTarget(table: AnyObj, target: any): any {
48
+ if (!target) return target;
49
+ if (typeof target === "string") return (table as any)[target] ?? target;
50
+ if (Array.isArray(target)) {
51
+ return target.map((t) => (typeof t === "string" ? ((table as any)[t] ?? t) : t));
52
+ }
53
+ return target;
54
+ }
55
+
56
+ export function makeModelRuntime(config: {
57
+ db: any;
58
+ schema: Record<string, any>;
59
+ relations: Record<string, any>;
60
+ tableName: string;
61
+ dialect: ModelDialect;
62
+ options: ModelOptions<any, any, any, any>;
63
+ }): any {
64
+ const baseState: BaseState = {
65
+ db: config.db,
66
+ where: undefined as unknown,
67
+ };
68
+
69
+ const build = (state: BaseState): any => {
70
+ const modelObj: AnyObj = {
71
+ $model: "model",
72
+ $modelName: config.tableName,
73
+ $format: config.options.format,
74
+ $formatValue: undefined,
75
+ where(value: MethodWhereValue<any, any>) {
76
+ return build({ ...state, where: value });
77
+ },
78
+ include(value: MethodWithValue<any, any>) {
79
+ return value;
80
+ },
81
+ extend(nextOptions: any) {
82
+ return makeModelRuntime({
83
+ ...config,
84
+ options: {
85
+ ...config.options,
86
+ ...nextOptions,
87
+ methods: {
88
+ ...(nextOptions?.methods ?? {}),
89
+ ...(config.options?.methods ?? {}),
90
+ },
91
+ format: nextOptions?.format ?? config.options?.format,
92
+ },
93
+ });
94
+ },
95
+ db(db: any) {
96
+ return makeModelRuntime({ ...config, db });
97
+ },
98
+ };
99
+
100
+ const attachMethods = (methods: AnyObj | undefined) => {
101
+ if (!methods) return;
102
+ for (const [key, fn] of Object.entries(methods)) {
103
+ if (typeof fn === "function") {
104
+ (modelObj as any)[key] = fn.bind(modelObj);
105
+ }
106
+ }
107
+ };
108
+
109
+ attachMethods(config.options.methods);
110
+
111
+ modelObj.findMany = () => {
112
+ const runner = async (qState: QueryState) => {
113
+ const table = (config.schema as any)[config.tableName];
114
+ const whereSql = compileEffectiveWhere(table as AnyObj, config.options.where, state.where);
115
+
116
+ let result: any;
117
+ if (qState.with) {
118
+ result = await runWithJoins({
119
+ db: config.db,
120
+ schema: config.schema,
121
+ relations: config.relations,
122
+ tableName: config.tableName,
123
+ table,
124
+ dialect: config.dialect,
125
+ whereSql,
126
+ qState,
127
+ kind: "many",
128
+ });
129
+ } else {
130
+ const { selectMap } = buildSelectProjection(table as AnyObj, qState.select as any, qState.exclude as any);
131
+ let q = (config.db as any).select(selectMap).from(table);
132
+ if (whereSql) q = q.where(whereSql);
133
+ result = await q;
134
+ }
135
+
136
+ let out: any = result;
137
+ if (qState.select) out = applySelect(out, qState.select);
138
+ if (qState.exclude) out = applyExclude(out, qState.exclude);
139
+ if (!qState.raw) out = applyFormat(out, config.options.format);
140
+ return out;
141
+ };
142
+
143
+ return new QueryResult({} as QueryState, runner) as any;
144
+ };
145
+
146
+ modelObj.findFirst = () => {
147
+ const runner = async (qState: QueryState) => {
148
+ const table = (config.schema as any)[config.tableName];
149
+ const whereSql = compileEffectiveWhere(table as AnyObj, config.options.where, state.where);
150
+
151
+ let result: any;
152
+ if (qState.with) {
153
+ result = await runWithJoins({
154
+ db: config.db,
155
+ schema: config.schema,
156
+ relations: config.relations,
157
+ tableName: config.tableName,
158
+ table,
159
+ dialect: config.dialect,
160
+ whereSql,
161
+ qState,
162
+ kind: "one",
163
+ });
164
+ } else {
165
+ const { selectMap } = buildSelectProjection(table as AnyObj, qState.select as any, qState.exclude as any);
166
+ let q = (config.db as any).select(selectMap).from(table);
167
+ if (whereSql) q = q.where(whereSql);
168
+ q = q.limit(1);
169
+ const rows = await q;
170
+ result = rows[0];
171
+ }
172
+
173
+ let out: any = result;
174
+ if (qState.select) out = applySelect(out, qState.select);
175
+ if (qState.exclude) out = applyExclude(out, qState.exclude);
176
+ if (!qState.raw) out = applyFormat(out, config.options.format);
177
+ return out;
178
+ };
179
+
180
+ return new QueryResult({} as QueryState, runner) as any;
181
+ };
182
+
183
+ modelObj.insert = (value: any) => {
184
+ const runner = async (mState: MutateState) => {
185
+ const table = (config.schema as any)[config.tableName];
186
+ const q = (config.db as any).insert(table).values(mState.value);
187
+ return await execReturn(q, mState, config.dialect);
188
+ };
189
+
190
+ return new MutateResult({ kind: "insert" as MutateKind, value } as MutateState, runner) as any;
191
+ };
192
+
193
+ modelObj.update = (value: any) => {
194
+ const runner = async (mState: MutateState) => {
195
+ const table = (config.schema as any)[config.tableName];
196
+ const whereSql = compileEffectiveWhere(table as AnyObj, config.options.where, state.where);
197
+ let q = (config.db as any).update(table).set(mState.value);
198
+ if (whereSql) q = q.where(whereSql);
199
+ return await execReturn(q, mState, config.dialect);
200
+ };
201
+
202
+ return new MutateResult({ kind: "update" as MutateKind, value } as MutateState, runner) as any;
203
+ };
204
+
205
+ modelObj.delete = () => {
206
+ const runner = async (mState: MutateState) => {
207
+ const table = (config.schema as any)[config.tableName];
208
+ const whereSql = compileEffectiveWhere(table as AnyObj, config.options.where, state.where);
209
+ let q = (config.db as any).delete(table);
210
+ if (whereSql) q = q.where(whereSql);
211
+ return await execReturn(q, mState, config.dialect);
212
+ };
213
+
214
+ return new MutateResult({ kind: "delete" as MutateKind } as MutateState, runner) as any;
215
+ };
216
+
217
+ modelObj.upsert = (value: MethodUpsertValue<any>) => {
218
+ const runner = async (mState: MutateState) => {
219
+ const table = (config.schema as any)[config.tableName];
220
+ const insertValues = (mState.value as any).insert;
221
+ const updateCfg = (mState.value as any).update;
222
+ const target = normalizeUpsertTarget(table as AnyObj, (mState.value as any).target);
223
+ let updateSet = updateCfg;
224
+ if (typeof updateCfg === "function") {
225
+ updateSet = updateCfg({
226
+ excluded: (field: string) => (table as any)[field],
227
+ inserted: (field: string) => (table as any)[field],
228
+ });
229
+ }
230
+
231
+ let q = (config.db as any).insert(table).values(insertValues);
232
+ if (q.onConflictDoUpdate) {
233
+ q = q.onConflictDoUpdate({
234
+ target,
235
+ set: updateSet,
236
+ });
237
+ }
238
+
239
+ return await execReturn(q, mState, config.dialect);
240
+ };
241
+
242
+ return new MutateResult({ kind: "upsert" as MutateKind, value } as MutateState, runner) as any;
243
+ };
244
+
245
+ return modelObj;
246
+ };
247
+
248
+ return build(baseState);
249
+ }
@@ -0,0 +1,85 @@
1
+ import type { MethodExcludeValue } from "../methods/exclude.ts";
2
+ import type { MethodSelectValue } from "../methods/select.ts";
3
+ import type { MethodWithValue } from "../methods/with.ts";
4
+
5
+ type AnyObj = Record<string, any>;
6
+
7
+ type QueryState = {
8
+ where?: unknown;
9
+ with?: unknown;
10
+ raw?: boolean;
11
+ select?: AnyObj;
12
+ exclude?: AnyObj;
13
+ };
14
+
15
+ type MutateKind = "insert" | "update" | "delete" | "upsert";
16
+
17
+ type MutateState = {
18
+ kind: MutateKind;
19
+ where?: unknown;
20
+ value?: unknown;
21
+ returnSelect?: AnyObj;
22
+ };
23
+
24
+ export class ThenableResult<T> implements PromiseLike<T> {
25
+ protected _execute: () => Promise<T>;
26
+
27
+ constructor(execute: () => Promise<T>) {
28
+ this._execute = execute;
29
+ }
30
+
31
+ then<TResult1 = T, TResult2 = never>(
32
+ onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
33
+ onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null,
34
+ ): Promise<TResult1 | TResult2> {
35
+ return this._execute().then(onfulfilled as any, onrejected as any);
36
+ }
37
+ }
38
+
39
+ export class QueryResult<T> extends ThenableResult<T> {
40
+ private state: QueryState;
41
+ private runner: (state: QueryState) => Promise<T>;
42
+
43
+ constructor(state: QueryState, runner: (state: QueryState) => Promise<T>) {
44
+ super(() => runner(state));
45
+ this.state = state;
46
+ this.runner = runner;
47
+ }
48
+
49
+ with(value: MethodWithValue<any, any>): any {
50
+ return new QueryResult({ ...this.state, with: value }, this.runner) as any;
51
+ }
52
+
53
+ select(value: MethodSelectValue<any>): any {
54
+ return new QueryResult({ ...this.state, select: value as any }, this.runner) as any;
55
+ }
56
+
57
+ exclude(value: MethodExcludeValue<any>): any {
58
+ return new QueryResult({ ...this.state, exclude: value as any }, this.runner) as any;
59
+ }
60
+
61
+ raw(): any {
62
+ return new QueryResult({ ...this.state, raw: true }, this.runner) as any;
63
+ }
64
+
65
+ debug(): any {
66
+ return this.state;
67
+ }
68
+ }
69
+
70
+ export class MutateResult<T> extends ThenableResult<T> {
71
+ private state: MutateState;
72
+ private runner: (state: MutateState) => Promise<T>;
73
+
74
+ constructor(state: MutateState, runner: (state: MutateState) => Promise<T>) {
75
+ super(() => runner(state));
76
+ this.state = state;
77
+ this.runner = runner;
78
+ }
79
+
80
+ return(value?: AnyObj): any {
81
+ return new MutateResult({ ...this.state, returnSelect: value }, this.runner) as any;
82
+ }
83
+ }
84
+
85
+ export type { QueryState, MutateState, MutateKind };
@@ -0,0 +1,45 @@
1
+ type AnyObj = Record<string, any>;
2
+
3
+ export function applySelect(value: any, select: AnyObj): any {
4
+ if (value == null) return value;
5
+ if (Array.isArray(value)) return value.map((v) => applySelect(v, select));
6
+ if (typeof value !== "object") return value;
7
+
8
+ const out: AnyObj = {};
9
+ for (const [key, sel] of Object.entries(select)) {
10
+ if (sel === true) {
11
+ out[key] = (value as any)[key];
12
+ continue;
13
+ }
14
+ if (sel && typeof sel === "object") {
15
+ out[key] = applySelect((value as any)[key], sel as AnyObj);
16
+ }
17
+ }
18
+ return out;
19
+ }
20
+
21
+ export function applyExclude(value: any, exclude: AnyObj): any {
22
+ if (value == null) return value;
23
+ if (Array.isArray(value)) return value.map((v) => applyExclude(v, exclude));
24
+ if (typeof value !== "object") return value;
25
+
26
+ const out: AnyObj = { ...(value as AnyObj) };
27
+ for (const [key, ex] of Object.entries(exclude)) {
28
+ if (ex === true) {
29
+ delete out[key];
30
+ continue;
31
+ }
32
+ if (ex && typeof ex === "object" && key in out) {
33
+ out[key] = applyExclude(out[key], ex as AnyObj);
34
+ }
35
+ }
36
+ return out;
37
+ }
38
+
39
+ export function applyFormat(value: any, format: any): any {
40
+ if (!format) return value;
41
+ if (value == null) return value;
42
+ if (Array.isArray(value)) return value.map((v) => applyFormat(v, format));
43
+ if (typeof value !== "object") return value;
44
+ return format(value);
45
+ }
@@ -0,0 +1,183 @@
1
+ import {
2
+ and,
3
+ between,
4
+ eq,
5
+ gt,
6
+ gte,
7
+ ilike,
8
+ inArray,
9
+ isNull,
10
+ like,
11
+ lt,
12
+ lte,
13
+ ne,
14
+ notBetween,
15
+ notInArray,
16
+ or,
17
+ } from "drizzle-orm";
18
+ import type { SQL } from "drizzle-orm";
19
+ import type { EscapedValue } from "../query/operations.ts";
20
+
21
+ type AnyObj = Record<string, any>;
22
+
23
+ function isPromiseLike(value: any): value is PromiseLike<any> {
24
+ return value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
25
+ }
26
+
27
+ function isEscapedValue(value: any): value is EscapedValue<any> {
28
+ return value && typeof value === "object" && ("equal" in value || value.__kind === "esc-op");
29
+ }
30
+
31
+ function unwrapEscapedValue(column: any, value: any): { sql?: SQL; value?: any } {
32
+ if (!isEscapedValue(value)) return { value };
33
+
34
+ if ((value as any).__kind === "esc-op") {
35
+ return {
36
+ sql: (value as any).op(column, (value as any).value),
37
+ };
38
+ }
39
+
40
+ return {
41
+ value: (value as any).equal,
42
+ };
43
+ }
44
+
45
+ function compileColumnValue(column: any, value: any): SQL | undefined {
46
+ if (isEscapedValue(value)) {
47
+ if ((value as any).__kind === "esc-op") {
48
+ return (value as any).op(column, (value as any).value);
49
+ }
50
+ return eq(column, (value as any).equal);
51
+ }
52
+
53
+ if (value && typeof value === "object" && !Array.isArray(value)) {
54
+ const parts: SQL[] = [];
55
+
56
+ const pushIf = (sql: SQL | undefined) => {
57
+ if (sql) parts.push(sql);
58
+ };
59
+
60
+ const v: AnyObj = value;
61
+ if ("eq" in v) {
62
+ const u = unwrapEscapedValue(column, v.eq);
63
+ pushIf(u.sql ?? eq(column, u.value));
64
+ }
65
+ if ("equal" in v) {
66
+ const u = unwrapEscapedValue(column, v.equal);
67
+ pushIf(u.sql ?? eq(column, u.value));
68
+ }
69
+ if ("not" in v) {
70
+ const u = unwrapEscapedValue(column, v.not);
71
+ pushIf(u.sql ?? ne(column, u.value));
72
+ }
73
+ if ("in" in v) {
74
+ const arr = (v.in ?? []).map((item: any) => unwrapEscapedValue(column, item));
75
+ const sqls = arr.map((x: { sql?: SQL; value?: any }) => x.sql).filter(Boolean) as SQL[];
76
+ const values = arr.map((x: { sql?: SQL; value?: any }) => x.value).filter((x: any) => x !== undefined);
77
+ if (sqls.length) pushIf(or(...sqls));
78
+ if (values.length) pushIf(inArray(column, values));
79
+ }
80
+ if ("nin" in v) {
81
+ const arr = (v.nin ?? []).map((item: any) => unwrapEscapedValue(column, item));
82
+ const sqls = arr.map((x: { sql?: SQL; value?: any }) => x.sql).filter(Boolean) as SQL[];
83
+ const values = arr.map((x: { sql?: SQL; value?: any }) => x.value).filter((x: any) => x !== undefined);
84
+ if (sqls.length) pushIf(or(...sqls));
85
+ if (values.length) pushIf(notInArray(column, values));
86
+ }
87
+ if ("isNull" in v) pushIf(v.isNull ? isNull(column) : undefined);
88
+
89
+ if ("gt" in v) {
90
+ const u = unwrapEscapedValue(column, v.gt);
91
+ pushIf(u.sql ?? gt(column, u.value));
92
+ }
93
+ if ("gte" in v) {
94
+ const u = unwrapEscapedValue(column, v.gte);
95
+ pushIf(u.sql ?? gte(column, u.value));
96
+ }
97
+ if ("lt" in v) {
98
+ const u = unwrapEscapedValue(column, v.lt);
99
+ pushIf(u.sql ?? lt(column, u.value));
100
+ }
101
+ if ("lte" in v) {
102
+ const u = unwrapEscapedValue(column, v.lte);
103
+ pushIf(u.sql ?? lte(column, u.value));
104
+ }
105
+ if ("between" in v) {
106
+ const a = unwrapEscapedValue(column, v.between?.[0]);
107
+ const b = unwrapEscapedValue(column, v.between?.[1]);
108
+ if (a.sql) pushIf(a.sql);
109
+ if (b.sql) pushIf(b.sql);
110
+ pushIf(between(column, a.value, b.value));
111
+ }
112
+ if ("notBetween" in v) {
113
+ const a = unwrapEscapedValue(column, v.notBetween?.[0]);
114
+ const b = unwrapEscapedValue(column, v.notBetween?.[1]);
115
+ if (a.sql) pushIf(a.sql);
116
+ if (b.sql) pushIf(b.sql);
117
+ pushIf(notBetween(column, a.value, b.value));
118
+ }
119
+
120
+ if ("like" in v) {
121
+ const u = unwrapEscapedValue(column, v.like);
122
+ pushIf(u.sql ?? like(column, u.value));
123
+ }
124
+ if ("ilike" in v) {
125
+ const u = unwrapEscapedValue(column, v.ilike);
126
+ pushIf(u.sql ?? ilike(column, u.value));
127
+ }
128
+
129
+ if (Array.isArray(v.or)) {
130
+ const sub = v.or
131
+ .map((item: any) => compileColumnValue(column, item))
132
+ .filter(Boolean) as SQL[];
133
+ if (sub.length) pushIf(or(...sub));
134
+ }
135
+
136
+ if (Array.isArray(v.and)) {
137
+ const sub = v.and
138
+ .map((item: any) => compileColumnValue(column, item))
139
+ .filter(Boolean) as SQL[];
140
+ if (sub.length) pushIf(and(...sub));
141
+ }
142
+
143
+ if (!parts.length) return undefined;
144
+ return parts.length === 1 ? parts[0] : and(...parts);
145
+ }
146
+
147
+ return eq(column, value);
148
+ }
149
+
150
+ export function compileWhereObject(fields: AnyObj, where: AnyObj): SQL | undefined {
151
+ const parts: SQL[] = [];
152
+ for (const [key, value] of Object.entries(where)) {
153
+ if (value === undefined) continue;
154
+
155
+ const col = (fields as any)[key];
156
+ if (col) {
157
+ const sql = compileColumnValue(col, value);
158
+ if (sql) parts.push(sql);
159
+ continue;
160
+ }
161
+
162
+ if (value && typeof value === "object") {
163
+ throw new Error(`Relation where is not implemented yet for key '${key}'.`);
164
+ }
165
+ }
166
+
167
+ if (!parts.length) return undefined;
168
+ return parts.length === 1 ? parts[0] : and(...parts);
169
+ }
170
+
171
+ export function compileWhere(fields: AnyObj, where: unknown): SQL | undefined {
172
+ if (!where) return undefined;
173
+
174
+ if (typeof where === "object" && where && !isPromiseLike(where)) {
175
+ if ((where as any).$model === "model") {
176
+ throw new Error("Model-as-where is not implemented yet.");
177
+ }
178
+ if ((where as any).getSQL) return where as any;
179
+ return compileWhereObject(fields, where as AnyObj);
180
+ }
181
+
182
+ return where as any;
183
+ }
@@ -0,0 +1,28 @@
1
+ import type { QueryState } from "./thenable.ts";
2
+ import { executeWithJoins } from "./joins.ts";
3
+
4
+ type AnyObj = Record<string, any>;
5
+
6
+ export async function runWithJoins(args: {
7
+ db: any;
8
+ schema: Record<string, any>;
9
+ relations: Record<string, any>;
10
+ tableName: string;
11
+ table: AnyObj;
12
+ dialect: string;
13
+ whereSql?: any;
14
+ qState: QueryState;
15
+ kind: "many" | "one";
16
+ }): Promise<any> {
17
+ return await executeWithJoins({
18
+ db: args.db,
19
+ schema: args.schema,
20
+ relations: args.relations,
21
+ baseTableName: args.tableName,
22
+ baseTable: args.table,
23
+ dialect: args.dialect,
24
+ whereSql: args.whereSql,
25
+ withValue: args.qState.with as any,
26
+ limitOne: args.kind === "one",
27
+ });
28
+ }
@@ -0,0 +1,11 @@
1
+ export type ModelDialect = SqlLiteDialect | MySqlDialect | SingleStoreDialect | PgDialect | MssqlDialect | CockroachDbDialect | UnknownDialect;
2
+
3
+ export type UnknownDialect = "Unknown[DO_NOT_USE]";
4
+ export type SqlLiteDialect = "SQLite";
5
+ export type MySqlDialect = "MySQL";
6
+ export type SingleStoreDialect = "SingleStore";
7
+ export type PgDialect = "PostgreSQL";
8
+ export type MssqlDialect = "MSSQL";
9
+ export type CockroachDbDialect = "CockroachDB";
10
+
11
+ export type ReturningIdDialects = MySqlDialect | SingleStoreDialect | CockroachDbDialect;
@@ -0,0 +1,31 @@
1
+ import type {
2
+ TableRelationalConfig,
3
+ TablesRelationalConfig,
4
+ } from "drizzle-orm/relations";
5
+ import type { ModelDialect } from "./dialect.ts";
6
+ import type { Model, ModelIdentifier } from "./model.ts";
7
+ import type { ModelLevelMethods } from "./methods/levels.ts";
8
+
9
+ // export type ModelForeignContext<TSchema extends TablesRelationalConfig, TTableName extends string, TDialect extends ModelDialect, ExcludedKeys extends string = string> = Omit<Model<TSchema, TSchema[TTableName], TDialect>, ModelLevelMethods | ExcludedKeys>;
10
+ // export type ModelForeignField<TSchema extends TablesRelationalConfig, TTableName extends string, TDialect extends ModelDialect, ExcludedKeys extends string = string> = <TContext extends ModelForeignContext<TSchema, TTableName, TDialect, ExcludedKeys>>(c: TContext) => TContext | any;
11
+
12
+ // export type ModelForegins<
13
+ // TSchema extends TablesRelationalConfig,
14
+ // TTable extends TableRelationalConfig,
15
+ // TDialect extends ModelDialect,
16
+ // > = {
17
+ // [K in keyof TTable["relations"]]: <TName extends string = TTable["relations"][K & string]["targetTableName"], TValue = (ModelForeignField<TSchema, TName, TDialect, K & string>) | ModelIdentifier<TName>>(
18
+ // fn: TValue extends Function
19
+ // ? TValue
20
+ // : (TValue extends ModelIdentifier<TName> ? TValue
21
+ // : never)
22
+ // ) => Omit<Model<TSchema, TTable, TDialect>, K>;
23
+ // };
24
+
25
+ export type ModelForegins<
26
+ TSchema extends TablesRelationalConfig,
27
+ TTable extends TableRelationalConfig,
28
+ TDialect extends ModelDialect,
29
+ > = {
30
+
31
+ };
@@ -0,0 +1,19 @@
1
+ export type ModelFormatValue<
2
+ TValue extends Record<string, any>,
3
+ TFormat extends Record<string, any> | undefined
4
+ > = TFormat extends undefined
5
+ ? TValue
6
+ : TValue extends (infer TItem)[]
7
+ ? (TItem extends Record<string, any>
8
+ ? ModelFormatValue<TItem, TFormat>[]
9
+ : TValue)
10
+ : Omit<TValue, keyof TFormat> & TFormat;
11
+
12
+ // export type ModelFormatResult<
13
+ // TResult extends Promise<any>,
14
+ // TFormat extends Record<string, any> | undefined
15
+ // > = TFormat extends undefined ? TResult : (TResult extends Promise<infer T>
16
+ // ? (T extends Record<string, any>
17
+ // ? ModelFormatValue<T, Exclude<TFormat, undefined>>
18
+ // : never)
19
+ // : never);
@@ -0,0 +1 @@
1
+ export * from "./builder.ts";
@@ -0,0 +1,32 @@
1
+ import type { MethodSelectValue } from "./select.ts";
2
+
3
+ export type ResolveMethodExcludeValue<
4
+ TValue extends Record<string, any>,
5
+ TResult extends Record<string, any>,
6
+ > = {
7
+ [Key in keyof TResult as TValue[Key & string] extends true
8
+ ? never
9
+ : Key]: TValue[Key & string] extends object
10
+ ? TResult[Key & string] extends (infer RItem)[]
11
+ ? RItem extends Record<string, any>
12
+ ? ResolveMethodExcludeValue<TValue[Key & string], RItem>[]
13
+ : never
14
+ : TResult[Key & string] extends Record<string, any>
15
+ ? ResolveMethodExcludeValue<TValue[Key & string], TResult[Key & string]>
16
+ : never
17
+ : TResult[Key & string];
18
+ };
19
+
20
+ export type MethodExcludeResult<
21
+ TValue extends Record<string, any>,
22
+ TResult extends Record<string, any>,
23
+ > = TResult extends any[]
24
+ ? TResult extends (infer RItem)[]
25
+ ? RItem extends Record<string, any>
26
+ ? ResolveMethodExcludeValue<TValue, RItem>[]
27
+ : ResolveMethodExcludeValue<TValue, TResult>[]
28
+ : ResolveMethodExcludeValue<TValue, TResult>
29
+ : ResolveMethodExcludeValue<TValue, TResult>;
30
+
31
+ export type MethodExcludeValue<TResult extends Record<string, any>> =
32
+ MethodSelectValue<TResult>;
@@ -0,0 +1,3 @@
1
+ export type MethodIncludeIdentifier<T> = {
2
+ $include: T;
3
+ };