peta-orm 0.5.0 → 0.6.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 +12 -18
- package/dist/{collection-PFmrQHyM.mjs → collection-D9YZn2mL.mjs} +4 -9
- package/dist/{crud-BCWvg5MI.mjs → crud-Di2nvpjB.mjs} +6 -23
- package/dist/{errors-sfFJolfu.mjs → errors-i-gCZnlW.mjs} +14 -1
- package/dist/{factory-BBvIMQuc.mjs → factory-_JPR5fVl.mjs} +5 -4
- package/dist/helpers-CcxHFhtz.mjs +40 -0
- package/dist/{hooks-BD0xy7uw.mjs → hooks-D508wLQg.mjs} +2 -16
- package/dist/index.d.mts +104 -86
- package/dist/index.mjs +646 -402
- package/dist/model-helpers-BBpD3qdv.mjs +14 -0
- package/package.json +1 -6
- package/dist/save-D5UKXvqC.mjs +0 -331
package/README.md
CHANGED
|
@@ -310,25 +310,10 @@ const posts = await Post.query()
|
|
|
310
310
|
|
|
311
311
|
## Migrations
|
|
312
312
|
|
|
313
|
-
|
|
313
|
+
See the [peta-migrate](../migrate/README.md) package for migration generation and running.
|
|
314
314
|
|
|
315
315
|
```ts
|
|
316
|
-
import { createMigrationRunner, createMigrationGenerator } from "peta-
|
|
317
|
-
|
|
318
|
-
const runner = createMigrationRunner(kysely)
|
|
319
|
-
const gen = createMigrationGenerator()
|
|
320
|
-
|
|
321
|
-
const code = gen.generateInitialMigration(models)
|
|
322
|
-
await runner.up(migrationFiles)
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
Or via the CLI:
|
|
326
|
-
|
|
327
|
-
```bash
|
|
328
|
-
bun run bin/peta migrate:init
|
|
329
|
-
bun run bin/peta migrate:generate
|
|
330
|
-
bun run bin/peta migrate:up
|
|
331
|
-
bun run bin/peta migrate:status
|
|
316
|
+
import { createMigrationRunner, createMigrationGenerator } from "peta-migrate"
|
|
332
317
|
```
|
|
333
318
|
|
|
334
319
|
---
|
|
@@ -394,7 +379,16 @@ cd packages/orm
|
|
|
394
379
|
bun test test/integration/
|
|
395
380
|
```
|
|
396
381
|
|
|
397
|
-
|
|
382
|
+
### Environment Variables
|
|
383
|
+
|
|
384
|
+
| Variable | Default | Description |
|
|
385
|
+
|----------|---------|-------------|
|
|
386
|
+
| `INTEGRATION_PG_URL` | `postgres://postgres:postgres@localhost:5432/peta_orm_test` | PostgreSQL connection string |
|
|
387
|
+
| `INTEGRATION_MYSQL_URL` | `mysql://root:mysqlroot@localhost:3306/peta_orm_test` | MySQL connection string |
|
|
388
|
+
| `INTEGRATION_SKIP_PG` | — | Set to `1` to skip PostgreSQL integration tests |
|
|
389
|
+
| `INTEGRATION_SKIP_MYSQL` | — | Set to `1` to skip MySQL integration tests |
|
|
390
|
+
|
|
391
|
+
See [`.env.example`](./.env.example) for a copyable template.
|
|
398
392
|
|
|
399
393
|
---
|
|
400
394
|
|
|
@@ -44,7 +44,7 @@ function createCollection(items) {
|
|
|
44
44
|
return data.map((d) => d.get(key));
|
|
45
45
|
},
|
|
46
46
|
pluck(key) {
|
|
47
|
-
return
|
|
47
|
+
return this.get(key);
|
|
48
48
|
},
|
|
49
49
|
groupBy(key) {
|
|
50
50
|
const result = {};
|
|
@@ -72,10 +72,6 @@ function createCollection(items) {
|
|
|
72
72
|
forEach(fn) {
|
|
73
73
|
data.forEach(fn);
|
|
74
74
|
},
|
|
75
|
-
each(fn) {
|
|
76
|
-
data.forEach(fn);
|
|
77
|
-
return collection;
|
|
78
|
-
},
|
|
79
75
|
unique(key) {
|
|
80
76
|
if (!key) {
|
|
81
77
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -152,11 +148,10 @@ function createCollection(items) {
|
|
|
152
148
|
},
|
|
153
149
|
async load(...relations) {
|
|
154
150
|
if (data.length === 0) return collection;
|
|
155
|
-
const { EagerLoader } = await import("./index.mjs").then((n) => n.
|
|
156
|
-
const { getModelDefFromInstance } = await import("./factory-
|
|
157
|
-
const { getModelDef } = await import("./index.mjs").then((n) => n.n);
|
|
151
|
+
const { EagerLoader } = await import("./index.mjs").then((n) => n.n);
|
|
152
|
+
const { getModelDefFromInstance } = await import("./factory-_JPR5fVl.mjs").then((n) => n.n);
|
|
158
153
|
const first = data[0];
|
|
159
|
-
const def = getModelDefFromInstance(first)
|
|
154
|
+
const def = getModelDefFromInstance(first);
|
|
160
155
|
if (def) {
|
|
161
156
|
const loader = new EagerLoader();
|
|
162
157
|
for (const rel of relations) await loader.loadRelated(data, { name: rel }, def);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as RelationNotFoundError, i as DatabaseError, n as isUniqueConstraintError, r as normalizeError } from "./errors-i-gCZnlW.mjs";
|
|
2
|
+
import { t as getDb } from "./model-helpers-BBpD3qdv.mjs";
|
|
3
|
+
import { i as resolveTargetId, n as getPivotInfo, t as findRelated } from "./helpers-CcxHFhtz.mjs";
|
|
2
4
|
//#region src/relations/crud.ts
|
|
3
5
|
function extractRelationData(def, data) {
|
|
4
6
|
const columnData = {};
|
|
@@ -12,10 +14,6 @@ function extractRelationData(def, data) {
|
|
|
12
14
|
relationOps
|
|
13
15
|
};
|
|
14
16
|
}
|
|
15
|
-
function getDb(def) {
|
|
16
|
-
if (!def._orm) throw new Error("Model not registered");
|
|
17
|
-
return def._orm.kysely;
|
|
18
|
-
}
|
|
19
17
|
/**
|
|
20
18
|
* Process relation operations after the parent model has been created.
|
|
21
19
|
* For belongsTo, the related model must be created FIRST, then its ID
|
|
@@ -77,25 +75,10 @@ async function processManyToManyCreate(_instance, relation, op, pkValue) {
|
|
|
77
75
|
[foreignPivotKey]: pkValue,
|
|
78
76
|
[relatedPivotKey]: relatedId
|
|
79
77
|
}).execute();
|
|
80
|
-
} catch {
|
|
78
|
+
} catch (e) {
|
|
79
|
+
if (!isUniqueConstraintError(e)) throw normalizeError(e, throughTable);
|
|
80
|
+
}
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
-
function getPivotInfo(relation) {
|
|
84
|
-
if (relation.type !== "manyToMany" || !relation.throughTable) throw new Error("Not a many-to-many relation");
|
|
85
|
-
return {
|
|
86
|
-
throughTable: relation.throughTable,
|
|
87
|
-
foreignPivotKey: relation.foreignPivotKey ?? "",
|
|
88
|
-
relatedPivotKey: relation.relatedPivotKey ?? ""
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
async function findRelated(def, conditions) {
|
|
92
|
-
const key = Object.keys(conditions)[0];
|
|
93
|
-
return def.query().where(key, "=", conditions[key]).executeTakeFirst();
|
|
94
|
-
}
|
|
95
|
-
async function resolveTargetId(def, target) {
|
|
96
|
-
if (typeof target === "number" || typeof target === "string") return target;
|
|
97
|
-
const found = await findRelated(def, target);
|
|
98
|
-
if (found) return found.get("id");
|
|
99
|
-
}
|
|
100
83
|
//#endregion
|
|
101
84
|
export { extractRelationData, processCreateRelations };
|
|
@@ -62,8 +62,21 @@ function normalizeError(e, table) {
|
|
|
62
62
|
if (raw.code === "ER_BAD_NULL_ERROR" || raw.errno === 1048) return new DatabaseError(`Not null constraint violation on ${table}: ${msg}`, "NOT_NULL_CONSTRAINT", table, msg);
|
|
63
63
|
return new DatabaseError(msg || "Unknown database error", "UNKNOWN", table, msg);
|
|
64
64
|
}
|
|
65
|
+
function isUniqueConstraintError(error) {
|
|
66
|
+
if (error instanceof Error) {
|
|
67
|
+
const msg = error.message.toLowerCase();
|
|
68
|
+
if (msg.includes("unique") || msg.includes("sqlite_constraint")) return true;
|
|
69
|
+
if (msg.includes("23505")) return true;
|
|
70
|
+
if (msg.includes("1062") || msg.includes("duplicate entry")) return true;
|
|
71
|
+
}
|
|
72
|
+
if (error && typeof error === "object" && "code" in error) {
|
|
73
|
+
const code = error.code;
|
|
74
|
+
if (code === "23505" || code === "ER_DUP_ENTRY" || code === "SQLITE_CONSTRAINT_UNIQUE") return true;
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
65
78
|
//#endregion
|
|
66
79
|
//#region src/errors.ts
|
|
67
80
|
var errors_exports = /* @__PURE__ */ __exportAll({ normalizeError: () => normalizeError });
|
|
68
81
|
//#endregion
|
|
69
|
-
export {
|
|
82
|
+
export { ModelNotFoundError as a, RelationNotFoundError as c, DatabaseError as i, ValidationError as l, isUniqueConstraintError as n, ModelNotRegisteredError as o, normalizeError as r, RelationNotAllowedError as s, errors_exports as t };
|
|
@@ -39,10 +39,10 @@ function castForSet(value, type) {
|
|
|
39
39
|
default: return value;
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
-
function applyCastsToData(config, data
|
|
42
|
+
function applyCastsToData(config, data) {
|
|
43
43
|
if (!config.casts) return { ...data };
|
|
44
44
|
const result = { ...data };
|
|
45
|
-
for (const [key, type] of Object.entries(config.casts)) if (key in result) result[key] =
|
|
45
|
+
for (const [key, type] of Object.entries(config.casts)) if (key in result) result[key] = castValue(result[key], type);
|
|
46
46
|
return result;
|
|
47
47
|
}
|
|
48
48
|
//#endregion
|
|
@@ -77,6 +77,7 @@ function getModelDefFromInstance(instance) {
|
|
|
77
77
|
return instanceDefs.get(instance);
|
|
78
78
|
}
|
|
79
79
|
function createInstance(def, config, data, exists) {
|
|
80
|
+
const validColumns = new Set(Object.keys(def.columns));
|
|
80
81
|
const instance = {
|
|
81
82
|
get exists() {
|
|
82
83
|
return getExists(instance);
|
|
@@ -106,7 +107,7 @@ function createInstance(def, config, data, exists) {
|
|
|
106
107
|
},
|
|
107
108
|
fill(data) {
|
|
108
109
|
const safe = {};
|
|
109
|
-
for (const [key, value] of Object.entries(data)) if (!FORBIDDEN_KEYS.has(key)) {
|
|
110
|
+
for (const [key, value] of Object.entries(data)) if (!FORBIDDEN_KEYS.has(key) && validColumns.has(key)) {
|
|
110
111
|
let v = value;
|
|
111
112
|
const attrDef = config.attributes?.[key];
|
|
112
113
|
if (attrDef?.set) v = attrDef.set(v, instance);
|
|
@@ -160,7 +161,7 @@ function createInstance(def, config, data, exists) {
|
|
|
160
161
|
return getRuntime().modelToJSON(def, instance);
|
|
161
162
|
}
|
|
162
163
|
};
|
|
163
|
-
if (exists) initState(instance, applyCastsToData(config, data || {}
|
|
164
|
+
if (exists) initState(instance, applyCastsToData(config, data || {}), true);
|
|
164
165
|
else {
|
|
165
166
|
initState(instance, {}, false);
|
|
166
167
|
if (data && Object.keys(data).length > 0) instance.fill(data);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//#region src/relations/helpers.ts
|
|
2
|
+
const THUNK_CACHE = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
function resolveThunk(thunk) {
|
|
4
|
+
let cls = THUNK_CACHE.get(thunk);
|
|
5
|
+
if (!cls) {
|
|
6
|
+
cls = thunk();
|
|
7
|
+
THUNK_CACHE.set(thunk, cls);
|
|
8
|
+
}
|
|
9
|
+
return cls;
|
|
10
|
+
}
|
|
11
|
+
function groupByArray(items, key) {
|
|
12
|
+
const result = {};
|
|
13
|
+
for (const item of items) {
|
|
14
|
+
const v = item.get(key);
|
|
15
|
+
if (v == null) continue;
|
|
16
|
+
const k = String(v);
|
|
17
|
+
if (!result[k]) result[k] = [];
|
|
18
|
+
result[k].push(item);
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
function getPivotInfo(relation) {
|
|
23
|
+
if (relation.type !== "manyToMany" || !relation.throughTable) throw new Error("Not a many-to-many relation");
|
|
24
|
+
return {
|
|
25
|
+
throughTable: relation.throughTable,
|
|
26
|
+
foreignPivotKey: relation.foreignPivotKey ?? "",
|
|
27
|
+
relatedPivotKey: relation.relatedPivotKey ?? ""
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async function findRelated(def, conditions) {
|
|
31
|
+
const key = Object.keys(conditions)[0];
|
|
32
|
+
return def.query().where(key, "=", conditions[key]).executeTakeFirst();
|
|
33
|
+
}
|
|
34
|
+
async function resolveTargetId(def, target) {
|
|
35
|
+
if (typeof target === "number" || typeof target === "string") return target;
|
|
36
|
+
const found = await findRelated(def, target);
|
|
37
|
+
if (found) return found.get("id");
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { resolveThunk as a, resolveTargetId as i, getPivotInfo as n, groupByArray as r, findRelated as t };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
1
|
//#region src/hooks/index.ts
|
|
3
2
|
function createHookManager() {
|
|
4
3
|
const listeners = /* @__PURE__ */ new Map();
|
|
@@ -22,27 +21,14 @@ function createHookManager() {
|
|
|
22
21
|
const cbs = listeners.get(event);
|
|
23
22
|
if (cbs) for (const cb of cbs) await cb(model);
|
|
24
23
|
}
|
|
25
|
-
function clone() {
|
|
26
|
-
const cloned = createHookManager();
|
|
27
|
-
for (const [event, cbs] of listeners) for (const cb of cbs) cloned.on(event, cb);
|
|
28
|
-
return cloned;
|
|
29
|
-
}
|
|
30
24
|
return {
|
|
31
25
|
on,
|
|
32
26
|
off,
|
|
33
|
-
trigger
|
|
34
|
-
clone
|
|
27
|
+
trigger
|
|
35
28
|
};
|
|
36
29
|
}
|
|
37
30
|
//#endregion
|
|
38
31
|
//#region src/model/hooks.ts
|
|
39
|
-
var hooks_exports = /* @__PURE__ */ __exportAll({
|
|
40
|
-
getHooksFor: () => getHooksFor,
|
|
41
|
-
getSoftDeleteConfig: () => getSoftDeleteConfig,
|
|
42
|
-
hasSoftDelete: () => hasSoftDelete,
|
|
43
|
-
registerSoftDeletesFor: () => registerSoftDeletesFor,
|
|
44
|
-
registerTimestampsFor: () => registerTimestampsFor
|
|
45
|
-
});
|
|
46
32
|
const hookManagers = /* @__PURE__ */ new WeakMap();
|
|
47
33
|
function getHooksFor(def) {
|
|
48
34
|
let hm = hookManagers.get(def);
|
|
@@ -74,4 +60,4 @@ function registerTimestampsFor(def, createdAtCol = "createdAt", updatedAtCol = "
|
|
|
74
60
|
});
|
|
75
61
|
}
|
|
76
62
|
//#endregion
|
|
77
|
-
export {
|
|
63
|
+
export { registerTimestampsFor as a, registerSoftDeletesFor as i, getSoftDeleteConfig as n, createHookManager as o, hasSoftDelete as r, getHooksFor as t };
|
package/dist/index.d.mts
CHANGED
|
@@ -40,8 +40,33 @@ declare function createColumn<T>(schema: SchemaConfig, dataType: string, args?:
|
|
|
40
40
|
type ColumnShape = Record<string, Column>;
|
|
41
41
|
type ColumnValue<C> = C extends Column<infer T> ? T : never;
|
|
42
42
|
//#endregion
|
|
43
|
-
//#region src/
|
|
43
|
+
//#region src/types.d.ts
|
|
44
44
|
type Database = Kysely<Record<string, never>>;
|
|
45
|
+
interface ModelLike<TColumns extends ColumnShape = ColumnShape> {
|
|
46
|
+
get<K extends keyof TColumns>(key: K): ColumnValue<TColumns[K]>;
|
|
47
|
+
get(key: string): unknown;
|
|
48
|
+
set(key: string, value: unknown): void;
|
|
49
|
+
}
|
|
50
|
+
interface ORMLike {
|
|
51
|
+
readonly kysely: Database;
|
|
52
|
+
register(model: ModelDefinition<any>): void;
|
|
53
|
+
registerAll(...models: (ModelDefinition<any> | ModelDefinition<any>[])[]): void;
|
|
54
|
+
destroy(): Promise<void>;
|
|
55
|
+
transaction<T>(fn: (orm: ORMLike) => Promise<T>): Promise<T>;
|
|
56
|
+
readonly models: ReadonlyMap<string, ModelDefinition<any>>;
|
|
57
|
+
getModel<T extends ColumnShape = ColumnShape>(name: string): ModelDefinition<T> | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Discover model definitions by scanning files matching a glob pattern.
|
|
60
|
+
*
|
|
61
|
+
* Uses `fast-glob` to resolve the pattern relative to `cwd`, then dynamically
|
|
62
|
+
* imports each matching file and collects exported `ModelDefinition` values.
|
|
63
|
+
* Does **not** auto-register — use `registerAll(...result)` to register them.
|
|
64
|
+
*
|
|
65
|
+
* @param pattern Glob pattern (e.g. `"./src/models/**\/*.ts"`)
|
|
66
|
+
* @returns Array of discovered model definitions
|
|
67
|
+
*/
|
|
68
|
+
discover(pattern: string): Promise<ModelDefinition<any>[]>;
|
|
69
|
+
}
|
|
45
70
|
//#endregion
|
|
46
71
|
//#region src/pagination/index.d.ts
|
|
47
72
|
interface Paginator<TColumns extends ColumnShape = ColumnShape> {
|
|
@@ -56,8 +81,6 @@ interface Paginator<TColumns extends ColumnShape = ColumnShape> {
|
|
|
56
81
|
readonly lastItem: number;
|
|
57
82
|
readonly onFirstPage: boolean;
|
|
58
83
|
readonly onLastPage: boolean;
|
|
59
|
-
readonly count: number;
|
|
60
|
-
map<T>(fn: (item: ModelInstance<TColumns>) => T): T[];
|
|
61
84
|
toJSON(): PaginatorJson<TColumns>;
|
|
62
85
|
}
|
|
63
86
|
interface PaginatorJson<TColumns extends ColumnShape = ColumnShape> {
|
|
@@ -73,9 +96,14 @@ interface PaginatorJson<TColumns extends ColumnShape = ColumnShape> {
|
|
|
73
96
|
onFirstPage: boolean;
|
|
74
97
|
onLastPage: boolean;
|
|
75
98
|
}
|
|
76
|
-
type PaginatedResult = PaginatorJson;
|
|
77
99
|
declare function createPaginator<TColumns extends ColumnShape = ColumnShape>(items: ModelInstance<TColumns>[], total: number, perPage: number, currentPage: number): Paginator<TColumns>;
|
|
78
100
|
//#endregion
|
|
101
|
+
//#region src/relations/graph/delete.d.ts
|
|
102
|
+
interface DeleteGraphOptions {
|
|
103
|
+
allowedRelations?: string[];
|
|
104
|
+
}
|
|
105
|
+
declare function deleteGraph(def: ModelDefinition, model: ModelInstance, options?: DeleteGraphOptions): Promise<void>;
|
|
106
|
+
//#endregion
|
|
79
107
|
//#region src/relations/base.d.ts
|
|
80
108
|
type RelationType = "hasMany" | "belongsTo" | "hasOne" | "manyToMany" | "hasManyThrough";
|
|
81
109
|
interface RelationOptions {
|
|
@@ -156,14 +184,11 @@ interface QueryBuilder<TColumns extends ColumnShape = ColumnShape> extends Promi
|
|
|
156
184
|
max(column: string): Promise<number>;
|
|
157
185
|
withCount(relation: string): QueryBuilder<TColumns>;
|
|
158
186
|
withSum(relation: string, column: string): QueryBuilder<TColumns>;
|
|
159
|
-
withAvg(relation: string, column: string): QueryBuilder<TColumns>;
|
|
160
|
-
withMin(relation: string, column: string): QueryBuilder<TColumns>;
|
|
161
|
-
withMax(relation: string, column: string): QueryBuilder<TColumns>;
|
|
162
|
-
withExists(relation: string): QueryBuilder<TColumns>;
|
|
163
187
|
chunk(size: number, callback: (chunk: ModelInstance<TColumns>[]) => Promise<void>): Promise<void>;
|
|
164
188
|
paginate(page: number, perPage?: number): Promise<Paginator<TColumns>>;
|
|
165
189
|
insertGraph(data: Record<string, unknown> | Record<string, unknown>[], options?: InsertGraphOptions): Promise<any>;
|
|
166
190
|
upsertGraph(data: Record<string, unknown> | Record<string, unknown>[], options?: UpsertGraphOptions): Promise<any>;
|
|
191
|
+
upsert(data: Record<string, unknown>): Promise<ModelInstance<TColumns>>;
|
|
167
192
|
with(...relations: (string | Record<string, (qb: QueryBuilder<TColumns>) => void>)[]): QueryBuilder<TColumns>;
|
|
168
193
|
/**
|
|
169
194
|
* Whitelist allowed relations (and nested paths) for eager loading.
|
|
@@ -182,10 +207,18 @@ interface QueryBuilder<TColumns extends ColumnShape = ColumnShape> extends Promi
|
|
|
182
207
|
withTrashed(): QueryBuilder<TColumns>;
|
|
183
208
|
onlyTrashed(): QueryBuilder<TColumns>;
|
|
184
209
|
whereIn(column: string, values: unknown[]): QueryBuilder<TColumns>;
|
|
185
|
-
whereInPivot(column: string, values: unknown[]): QueryBuilder<TColumns>;
|
|
186
210
|
has(relationName: string): QueryBuilder<TColumns>;
|
|
187
|
-
|
|
188
|
-
|
|
211
|
+
/**
|
|
212
|
+
* Filter rows by related model existence with optional subquery filtering.
|
|
213
|
+
* The callback receives a raw Kysely subquery builder for the related table,
|
|
214
|
+
* not a peta-orm QueryBuilder. Chain `.where(...)` etc. directly on it.
|
|
215
|
+
*/
|
|
216
|
+
whereHas(relationName: string, callback?: (subQb: any) => any): QueryBuilder<TColumns>;
|
|
217
|
+
/**
|
|
218
|
+
* Filter rows by absence of related model, with optional subquery filtering.
|
|
219
|
+
* Same callback semantics as `whereHas`.
|
|
220
|
+
*/
|
|
221
|
+
whereDoesntHave(relationName: string, callback?: (subQb: any) => any): QueryBuilder<TColumns>;
|
|
189
222
|
where(column: string, operator: unknown, value?: unknown): QueryBuilder<TColumns>;
|
|
190
223
|
whereRef(col1: string, operator: string, col2: string): QueryBuilder<TColumns>;
|
|
191
224
|
orWhere(column: string, operator: unknown, value?: unknown): QueryBuilder<TColumns>;
|
|
@@ -242,59 +275,6 @@ interface RelationQuery extends QueryBuilder {
|
|
|
242
275
|
*/
|
|
243
276
|
type Plugin = (def: ModelDefinition) => undefined | ModelDefinition;
|
|
244
277
|
//#endregion
|
|
245
|
-
//#region src/types.d.ts
|
|
246
|
-
type ModelId = number & {
|
|
247
|
-
readonly __brand: "ModelId";
|
|
248
|
-
};
|
|
249
|
-
interface ModelLike<TColumns extends ColumnShape = ColumnShape> {
|
|
250
|
-
get<K extends keyof TColumns>(key: K): ColumnValue<TColumns[K]>;
|
|
251
|
-
get(key: string): unknown;
|
|
252
|
-
set(key: string, value: unknown): void;
|
|
253
|
-
}
|
|
254
|
-
interface ORMLike {
|
|
255
|
-
readonly kysely: Database;
|
|
256
|
-
register(model: ModelDefinition$1<any>): void;
|
|
257
|
-
registerAll(...models: (ModelDefinition$1<any> | ModelDefinition$1<any>[])[]): void;
|
|
258
|
-
destroy(): Promise<void>;
|
|
259
|
-
transaction<T>(fn: (trx: import("kysely").Kysely<Record<string, never>>) => Promise<T>): Promise<T>;
|
|
260
|
-
readonly models: ReadonlyMap<string, ModelDefinition$1<any>>;
|
|
261
|
-
getModel<T extends ColumnShape = ColumnShape>(name: string): ModelDefinition$1<T> | undefined;
|
|
262
|
-
/**
|
|
263
|
-
* Discover model definitions by scanning files matching a glob pattern.
|
|
264
|
-
*
|
|
265
|
-
* Uses `fast-glob` to resolve the pattern relative to `cwd`, then dynamically
|
|
266
|
-
* imports each matching file and collects exported `ModelDefinition` values.
|
|
267
|
-
* Does **not** auto-register — use `registerAll(...result)` to register them.
|
|
268
|
-
*
|
|
269
|
-
* @param pattern Glob pattern (e.g. `"./src/models/**\/*.ts"`)
|
|
270
|
-
* @returns Array of discovered model definitions
|
|
271
|
-
*/
|
|
272
|
-
discover(pattern: string): Promise<ModelDefinition$1<any>[]>;
|
|
273
|
-
}
|
|
274
|
-
interface ModelDefinition$1<TColumns extends ColumnShape = ColumnShape> {
|
|
275
|
-
readonly table: string;
|
|
276
|
-
readonly columns: TColumns;
|
|
277
|
-
readonly relations: Record<string, Relation>;
|
|
278
|
-
readonly name: string;
|
|
279
|
-
_orm: ORMLike | null;
|
|
280
|
-
query(): QueryBuilder<TColumns>;
|
|
281
|
-
find(id: number | string): Promise<ModelInstance<TColumns> | undefined>;
|
|
282
|
-
findOrFail(id: number | string): Promise<ModelInstance<TColumns>>;
|
|
283
|
-
first(): Promise<ModelInstance<TColumns> | undefined>;
|
|
284
|
-
create(data: Record<string, unknown>): Promise<ModelInstance<TColumns>>;
|
|
285
|
-
insert(data: Record<string, unknown>): Promise<ModelInstance<TColumns>>;
|
|
286
|
-
insertMany(dataArray: Record<string, unknown>[]): Promise<ModelInstance<TColumns>[]>;
|
|
287
|
-
update(id: number | string, data: Record<string, unknown>): Promise<ModelInstance<TColumns>>;
|
|
288
|
-
delete(id: number | string): Promise<void>;
|
|
289
|
-
hydrate(row: Record<string, unknown>): ModelInstance<TColumns>;
|
|
290
|
-
on(event: string, callback: (model: ModelInstance<TColumns>) => void | Promise<void>): () => void;
|
|
291
|
-
getHooks(): HookManager;
|
|
292
|
-
addGlobalScope(name: string, callback: (qb: QueryBuilder) => void): void;
|
|
293
|
-
removeGlobalScope(name: string): void;
|
|
294
|
-
getGlobalScopes(): Map<string, (qb: QueryBuilder) => void> | undefined;
|
|
295
|
-
_init(orm: ORMLike): void;
|
|
296
|
-
}
|
|
297
|
-
//#endregion
|
|
298
278
|
//#region src/hooks/index.d.ts
|
|
299
279
|
type LifecycleEvent = "beforeCreate" | "afterCreate" | "beforeUpdate" | "afterUpdate" | "beforeSave" | "afterSave" | "beforeDelete" | "afterDelete" | "beforeRestore" | "afterRestore" | "beforeForceDelete" | "afterForceDelete";
|
|
300
280
|
type HookCallback = (model: ModelLike) => void | Promise<void>;
|
|
@@ -302,7 +282,6 @@ interface HookManager {
|
|
|
302
282
|
on(event: LifecycleEvent, callback: HookCallback): () => void;
|
|
303
283
|
off(event: LifecycleEvent, callback: HookCallback): void;
|
|
304
284
|
trigger(event: LifecycleEvent, model: ModelLike): Promise<void>;
|
|
305
|
-
clone(): HookManager;
|
|
306
285
|
}
|
|
307
286
|
declare function createHookManager(): HookManager;
|
|
308
287
|
//#endregion
|
|
@@ -319,14 +298,12 @@ type StaticHookCallback = (args: StaticHookArgs) => void | Promise<void>;
|
|
|
319
298
|
//#endregion
|
|
320
299
|
//#region src/model/computed.d.ts
|
|
321
300
|
interface ComputedColumn<T = unknown> {
|
|
322
|
-
readonly type: "
|
|
301
|
+
readonly type: "runtime" | "batch";
|
|
323
302
|
readonly dependencies: string[];
|
|
324
303
|
/** Compute a value for a single record (runtime) */
|
|
325
304
|
compute?: (record: ModelInstance) => T;
|
|
326
305
|
/** Compute values for a batch of records (batch async) */
|
|
327
306
|
batchCompute?: (records: ModelInstance[]) => Promise<T[]>;
|
|
328
|
-
/** Raw SQL expression to inline in SELECT */
|
|
329
|
-
sql?: string;
|
|
330
307
|
}
|
|
331
308
|
//#endregion
|
|
332
309
|
//#region src/model/attribute.d.ts
|
|
@@ -410,10 +387,14 @@ interface ModelDefinition<TColumns extends ColumnShape = ColumnShape> {
|
|
|
410
387
|
create(data: Record<string, unknown>): Promise<ModelInstance<TColumns>>;
|
|
411
388
|
insert(data: Record<string, unknown>): Promise<ModelInstance<TColumns>>;
|
|
412
389
|
insertMany(dataArray: Record<string, unknown>[]): Promise<ModelInstance<TColumns>[]>;
|
|
390
|
+
updateMany(data: Record<string, unknown>, where: Record<string, unknown>[]): Promise<number>;
|
|
391
|
+
deleteMany(where: Record<string, unknown>[]): Promise<number>;
|
|
413
392
|
update(id: number | string, data: Record<string, unknown>): Promise<ModelInstance<TColumns>>;
|
|
414
393
|
delete(id: number | string): Promise<void>;
|
|
394
|
+
deleteGraph(idOrInstance: any, options?: DeleteGraphOptions): Promise<void>;
|
|
415
395
|
insertGraph(data: Record<string, unknown> | Record<string, unknown>[], options?: InsertGraphOptions): Promise<any>;
|
|
416
396
|
upsertGraph(data: Record<string, unknown> | Record<string, unknown>[], options?: UpsertGraphOptions): Promise<any>;
|
|
397
|
+
upsert(data: Record<string, unknown>): Promise<ModelInstance<TColumns>>;
|
|
417
398
|
hydrate(row: Record<string, unknown>): ModelInstance<TColumns>;
|
|
418
399
|
use(plugin: Plugin): ModelDefinition<TColumns>;
|
|
419
400
|
makeHelper<A extends any[], R>(fn: (qb: QueryBuilder, ...args: A) => R): (...args: A) => R;
|
|
@@ -422,11 +403,6 @@ interface ModelDefinition<TColumns extends ColumnShape = ColumnShape> {
|
|
|
422
403
|
beforeDelete(callback: StaticHookCallback): () => void;
|
|
423
404
|
afterDelete(callback: StaticHookCallback): () => void;
|
|
424
405
|
beforeUpdate(callback: StaticHookCallback): () => void;
|
|
425
|
-
afterUpdate(callback: StaticHookCallback): () => void;
|
|
426
|
-
beforeCreate(callback: StaticHookCallback): () => void;
|
|
427
|
-
afterCreate(callback: StaticHookCallback): () => void;
|
|
428
|
-
beforeFind(callback: StaticHookCallback): () => void;
|
|
429
|
-
afterFind(callback: StaticHookCallback): () => void;
|
|
430
406
|
addGlobalScope(name: string, callback: (qb: QueryBuilder) => void): void;
|
|
431
407
|
removeGlobalScope(name: string): void;
|
|
432
408
|
getGlobalScopes(): Map<string, (qb: QueryBuilder) => void> | undefined;
|
|
@@ -468,7 +444,6 @@ interface Collection<TColumns extends ColumnShape = ColumnShape> {
|
|
|
468
444
|
filter(fn: (item: ModelInstance<TColumns>, index: number) => boolean): Collection<TColumns>;
|
|
469
445
|
reduce<T>(fn: (acc: T, item: ModelInstance<TColumns>, index: number) => T, initial: T): T;
|
|
470
446
|
forEach(fn: (item: ModelInstance<TColumns>, index: number) => void): void;
|
|
471
|
-
each(fn: (item: ModelInstance<TColumns>, index: number) => void): Collection<TColumns>;
|
|
472
447
|
unique(key?: string): Collection<TColumns>;
|
|
473
448
|
sortBy(key: string, direction?: "asc" | "desc"): Collection<TColumns>;
|
|
474
449
|
shuffle(): Collection<TColumns>;
|
|
@@ -601,6 +576,24 @@ declare function normalizeError(e: unknown, table?: string): DatabaseError;
|
|
|
601
576
|
*/
|
|
602
577
|
declare function createDb<T>(factory: () => Promise<T>): () => Promise<T>;
|
|
603
578
|
//#endregion
|
|
579
|
+
//#region src/integrations/elysia.d.ts
|
|
580
|
+
interface PetaElysiaPluginOptions {
|
|
581
|
+
peta: ORMLike;
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Elysia.js plugin that attaches the ORM instance to the app context.
|
|
585
|
+
*/
|
|
586
|
+
declare function petaPlugin(options: PetaElysiaPluginOptions): (app: any) => any;
|
|
587
|
+
//#endregion
|
|
588
|
+
//#region src/integrations/hono.d.ts
|
|
589
|
+
interface PetaHonoMiddlewareOptions {
|
|
590
|
+
peta: ORMLike;
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Hono middleware that sets the ORM instance on the context.
|
|
594
|
+
*/
|
|
595
|
+
declare function petaMiddleware(options: PetaHonoMiddlewareOptions): (c: any, next: any) => Promise<void>;
|
|
596
|
+
//#endregion
|
|
604
597
|
//#region src/model/define.d.ts
|
|
605
598
|
declare function defineModel<TColumns extends ColumnShape>(table: string, config: ModelConfig<TColumns>): ModelDefinition<TColumns>;
|
|
606
599
|
//#endregion
|
|
@@ -669,6 +662,42 @@ declare function timestamps(opts?: {
|
|
|
669
662
|
*/
|
|
670
663
|
declare function ulid(): Plugin;
|
|
671
664
|
//#endregion
|
|
665
|
+
//#region src/relations/crud.d.ts
|
|
666
|
+
interface BelongsToOp {
|
|
667
|
+
create?: Record<string, unknown>;
|
|
668
|
+
connect?: Record<string, unknown>;
|
|
669
|
+
connectOrCreate?: {
|
|
670
|
+
where: Record<string, unknown>;
|
|
671
|
+
create: Record<string, unknown>;
|
|
672
|
+
};
|
|
673
|
+
update?: Record<string, unknown>;
|
|
674
|
+
upsert?: {
|
|
675
|
+
update: Record<string, unknown>;
|
|
676
|
+
create: Record<string, unknown>;
|
|
677
|
+
};
|
|
678
|
+
delete?: boolean;
|
|
679
|
+
disconnect?: boolean;
|
|
680
|
+
set?: Record<string, unknown>;
|
|
681
|
+
}
|
|
682
|
+
interface HasManyOp {
|
|
683
|
+
create?: Record<string, unknown>[];
|
|
684
|
+
connect?: (number | string | Record<string, unknown>)[];
|
|
685
|
+
set?: (number | string | Record<string, unknown>)[];
|
|
686
|
+
delete?: Record<string, unknown> | Record<string, unknown>[];
|
|
687
|
+
update?: {
|
|
688
|
+
where: Record<string, unknown> | Record<string, unknown>[];
|
|
689
|
+
data: Record<string, unknown>;
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
interface ManyToManyOp {
|
|
693
|
+
create?: Record<string, unknown>[];
|
|
694
|
+
connect?: (number | string | Record<string, unknown>)[];
|
|
695
|
+
disconnect?: Record<string, unknown> | Record<string, unknown>[];
|
|
696
|
+
set?: (number | string | Record<string, unknown>)[];
|
|
697
|
+
add?: (number | string | Record<string, unknown>)[];
|
|
698
|
+
}
|
|
699
|
+
type RelationData = BelongsToOp | HasManyOp | ManyToManyOp;
|
|
700
|
+
//#endregion
|
|
672
701
|
//#region src/relations/has-many.d.ts
|
|
673
702
|
declare function hasMany(relatedThunk: () => ModelDefinition, options?: RelationOptions): Relation;
|
|
674
703
|
declare function hasOne(relatedThunk: () => ModelDefinition, options?: RelationOptions): Relation;
|
|
@@ -709,13 +738,6 @@ interface MorphManyOptions {
|
|
|
709
738
|
*/
|
|
710
739
|
typeValue?: string;
|
|
711
740
|
}
|
|
712
|
-
interface MorphOneOptions {
|
|
713
|
-
name: string;
|
|
714
|
-
related: () => ModelDefinition;
|
|
715
|
-
type?: string;
|
|
716
|
-
id?: string;
|
|
717
|
-
typeValue?: string;
|
|
718
|
-
}
|
|
719
741
|
/**
|
|
720
742
|
* Resolve the related model for a MorphTo relation given a parent instance.
|
|
721
743
|
* Looks up the parent's `{name}Type` column value in the relation's morphMap
|
|
@@ -756,10 +778,6 @@ declare function defineMorphTo(options: MorphToOptions): Relation;
|
|
|
756
778
|
* The related table stores the parent's type and id.
|
|
757
779
|
*/
|
|
758
780
|
declare function defineMorphMany(options: MorphManyOptions): Relation;
|
|
759
|
-
/**
|
|
760
|
-
* Define a polymorphic hasOne relationship.
|
|
761
|
-
*/
|
|
762
|
-
declare function defineMorphOne(options: MorphOneOptions): Relation;
|
|
763
781
|
//#endregion
|
|
764
782
|
//#region src/repo/index.d.ts
|
|
765
783
|
type QueryMethod = (qb: QueryBuilder, ...args: any[]) => QueryBuilder;
|
|
@@ -783,4 +801,4 @@ interface RepoMethods {
|
|
|
783
801
|
*/
|
|
784
802
|
declare function createRepo<TMethods extends RepoMethods>(model: ModelDefinition, methods: TMethods): Record<string, never>;
|
|
785
803
|
//#endregion
|
|
786
|
-
export { Attribute, type Collection, type Column, type ColumnShape, type ColumnTypes, type ColumnValue, type Constraint, DatabaseError, type DatabaseErrorCode, type HookCallback, type HookManager, type InsertGraphOptions, type LifecycleEvent, type
|
|
804
|
+
export { Attribute, type BelongsToOp, type Collection, type Column, type ColumnShape, type ColumnTypes, type ColumnValue, type Constraint, DatabaseError, type DatabaseErrorCode, type DeleteGraphOptions, type HasManyOp, type HookCallback, type HookManager, type InsertGraphOptions, type LifecycleEvent, type ManyToManyOp, type ModelConfig, type ModelDefinition, type ModelInstance, ModelNotFoundError, ModelNotRegisteredError, type MorphManyOptions, type MorphToOptions, type ORMConfig, type ORMLike, type Paginator, type PaginatorJson, type Plugin, type QueryBuilder, type QueryMethod, type Relation, type RelationData, RelationNotAllowedError, RelationNotFoundError, type RelationOptions, type RelationType, type RepoMethods, type SchemaConfig, type SerializedShape, type UpsertGraphOptions, ValidationError, belongsTo, createArkTypeSchemaConfig, createCollection, createColumn, createColumnTypes, createDb, createHookManager, createORM, createORM as createPeta, createPaginator, createQueryBuilder, createRepo, defineModel, defineMorphMany, defineMorphTo, deleteGraph, hasMany, hasManyThrough, hasOne, manyToMany, normalizeError, petaMiddleware, petaPlugin, resolveMorphRelation, softDeletes, t, timestamps, ulid };
|