peta-orm 0.4.1 → 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.
@@ -0,0 +1,14 @@
1
+ import { o as ModelNotRegisteredError } from "./errors-i-gCZnlW.mjs";
2
+ //#region src/lib/model-helpers.ts
3
+ function getPrimaryKeyColumn(def) {
4
+ const cols = def.columns;
5
+ for (const [name, col] of Object.entries(cols)) if (col.isPrimaryKey) return name;
6
+ return "id";
7
+ }
8
+ function getDb(def) {
9
+ if (!def._orm) throw new ModelNotRegisteredError(def.name);
10
+ if (def._orm._trx) return def._orm._trx;
11
+ return def._orm.kysely;
12
+ }
13
+ //#endregion
14
+ export { getPrimaryKeyColumn as n, getDb as t };
package/package.json CHANGED
@@ -2,14 +2,14 @@
2
2
  "name": "peta-orm",
3
3
  "type": "module",
4
4
  "private": false,
5
- "version": "0.4.1",
5
+ "version": "0.6.0",
6
6
  "description": "ORM for Bun, built on Kysely",
7
7
  "license": "MIT",
8
8
  "repository": {
9
9
  "type": "git",
10
10
  "url": "git+https://github.com/zfadhli/peta-stack.git"
11
11
  },
12
- "module": "src/index.ts",
12
+ "module": "./dist/index.mjs",
13
13
  "main": "./dist/index.mjs",
14
14
  "types": "./dist/index.d.mts",
15
15
  "exports": {
@@ -25,8 +25,6 @@
25
25
  ],
26
26
  "dependencies": {
27
27
  "arktype": "^2.2.0",
28
- "cac": "^7.0.0",
29
- "ora": "^9.4.0",
30
28
  "ulid": "^3.0.2"
31
29
  },
32
30
  "peerDependencies": {
@@ -48,13 +46,11 @@
48
46
  },
49
47
  "scripts": {
50
48
  "test": "bun test",
51
- "test:all": "for f in test/*.ts; do echo === $f ===; bun test $f || exit 1; done",
52
49
  "test:integration": "bun test test/integration/",
53
- "test:all:integration": "for f in test/integration/*.ts; do echo === $f ===; bun test $f || exit 1; done",
54
50
  "typecheck": "bun x tsc --noEmit",
55
51
  "build": "tsdown",
56
52
  "lint": "bunx biome check src test examples",
57
53
  "lint:fix": "bunx biome check --write --unsafe src test examples",
58
- "prepublish": "bun run build"
54
+ "prepublishOnly": "bun run build"
59
55
  }
60
56
  }
@@ -1,331 +0,0 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { n as normalizeError, r as DatabaseError } from "./errors-sfFJolfu.mjs";
3
- import { t as getHooksFor } from "./hooks-BD0xy7uw.mjs";
4
- import { i as applyCastsToData, o as prepareForDb, t as createInstance } from "./factory-BBvIMQuc.mjs";
5
- import { d as setExists, f as syncOriginal, i as getExists, o as getState } from "./state-LtlHp6XV.mjs";
6
- //#region src/model/save.ts
7
- var save_exports = /* @__PURE__ */ __exportAll({
8
- getConfig: () => getConfig,
9
- insertManyModel: () => insertManyModel,
10
- insertModel: () => insertModel,
11
- reloadModel: () => reloadModel,
12
- saveModel: () => saveModel,
13
- setConfig: () => setConfig,
14
- updateModel: () => updateModel
15
- });
16
- function getPrimaryKeyColumn(def) {
17
- const cols = def.columns;
18
- for (const [name, col] of Object.entries(cols)) if (col.isPrimaryKey) return name;
19
- return "id";
20
- }
21
- function getTable(def) {
22
- return def.table;
23
- }
24
- function getDb(def) {
25
- if (!def._orm) throw new Error("Model not registered");
26
- return def._orm.kysely;
27
- }
28
- async function saveModel(def, model) {
29
- const hm = getHooksFor(def);
30
- const exists = getExists(model);
31
- const pk = getPrimaryKeyColumn(def);
32
- const db = getDb(def);
33
- const config = getConfig(def);
34
- if (exists) {
35
- const dirty = getState(model).attributes;
36
- const original = getState(model).original;
37
- const changed = {};
38
- for (const key of Object.keys(dirty)) if (dirty[key] !== original[key]) changed[key] = config?.casts?.[key] ? prepareForDb(dirty[key], config.casts[key]) : dirty[key];
39
- if (Object.keys(changed).length === 0) return model;
40
- await hm.trigger("beforeUpdate", model);
41
- await hm.trigger("beforeSave", model);
42
- const pkValue = model.get(pk);
43
- try {
44
- await db.updateTable(getTable(def)).set(changed).where(pk, "=", pkValue).execute();
45
- } catch (e) {
46
- throw normalizeError(e, getTable(def));
47
- }
48
- syncOriginal(model);
49
- await hm.trigger("afterUpdate", model);
50
- await hm.trigger("afterSave", model);
51
- } else {
52
- await hm.trigger("beforeCreate", model);
53
- await hm.trigger("beforeSave", model);
54
- const data = {};
55
- const attrs = getState(model).attributes;
56
- for (const [key, value] of Object.entries(attrs)) if (key !== pk || value !== void 0) data[key] = config?.casts?.[key] ? prepareForDb(value, config.casts[key]) : value;
57
- try {
58
- const result = await db.insertInto(getTable(def)).values(data).returningAll().executeTakeFirst();
59
- if (result) {
60
- const applied = config?.casts ? applyCastsToData(config, result, "get") : result;
61
- for (const [key, value] of Object.entries(applied)) getState(model).attributes[key] = value;
62
- }
63
- } catch (e) {
64
- throw normalizeError(e, getTable(def));
65
- }
66
- setExists(model, true);
67
- syncOriginal(model);
68
- await hm.trigger("afterCreate", model);
69
- await hm.trigger("afterSave", model);
70
- }
71
- return model;
72
- }
73
- async function insertModel(def, data) {
74
- const config = getConfig(def) ?? { columns: def.columns };
75
- if (!Object.keys(data).some((key) => key in def.relations)) {
76
- const model = createInstance(def, config, data, false);
77
- await saveModel(def, model);
78
- return model;
79
- }
80
- const { extractRelationData, processCreateRelations } = await import("./crud-BCWvg5MI.mjs");
81
- const { columnData, relationOps } = extractRelationData(def, data);
82
- for (const [relName, op] of Object.entries(relationOps)) {
83
- const relation = def.relations[relName];
84
- if (relation?.type === "belongsTo") {
85
- const bop = op;
86
- const relatedDef = relation.relatedModelClass;
87
- if (bop.create) {
88
- const related = await relatedDef.insert(bop.create);
89
- columnData[relation.foreignKey] = related.get(relation.localKey);
90
- } else if (bop.connect) {
91
- const cond = bop.connect;
92
- const condKey = Object.keys(cond)[0];
93
- const found = await relatedDef.query().where(condKey, "=", cond[condKey]).executeTakeFirst();
94
- if (found) columnData[relation.foreignKey] = found.get(relation.localKey);
95
- } else if (bop.connectOrCreate) {
96
- const { where, create } = bop.connectOrCreate;
97
- const whereKey = Object.keys(where)[0];
98
- const found = await relatedDef.query().where(whereKey, "=", where[whereKey]).executeTakeFirst();
99
- if (found) columnData[relation.foreignKey] = found.get(relation.localKey);
100
- else {
101
- const created = await relatedDef.insert(create);
102
- columnData[relation.foreignKey] = created.get(relation.localKey);
103
- }
104
- }
105
- }
106
- }
107
- const model = createInstance(def, config, columnData, false);
108
- await saveModel(def, model);
109
- const postOps = {};
110
- for (const [relName, op] of Object.entries(relationOps)) {
111
- const relation = def.relations[relName];
112
- if (relation && relation.type !== "belongsTo") postOps[relName] = op;
113
- }
114
- if (Object.keys(postOps).length > 0) await processCreateRelations(def, model, postOps);
115
- return model;
116
- }
117
- async function insertManyModel(def, dataArray) {
118
- const db = getDb(def);
119
- const pk = getPrimaryKeyColumn(def);
120
- const config = getConfig(def);
121
- const hm = getHooksFor(def);
122
- const instances = [];
123
- for (const data of dataArray) {
124
- const instance = createInstance(def, config ?? { columns: def.columns }, {}, false);
125
- const fillData = {};
126
- for (const [key, value] of Object.entries(data)) if (key !== pk) fillData[key] = value;
127
- instance.fill(fillData);
128
- await hm.trigger("beforeCreate", instance);
129
- instances.push(instance);
130
- }
131
- const prepared = instances.map((inst) => {
132
- const attrs = inst.attributes ?? {};
133
- const row = {};
134
- for (const [key, value] of Object.entries(attrs)) row[key] = config?.casts?.[key] ? prepareForDb(value, config.casts[key]) : value;
135
- return row;
136
- });
137
- let results;
138
- try {
139
- results = await db.insertInto(getTable(def)).values(prepared).returningAll().execute();
140
- } catch (e) {
141
- throw normalizeError(e, getTable(def));
142
- }
143
- const models = results.map((row) => {
144
- const applied = config?.casts ? applyCastsToData(config, row, "get") : row;
145
- return createInstance(def, config ?? { columns: def.columns }, applied, true);
146
- });
147
- for (const model of models) await hm.trigger("afterCreate", model);
148
- return models;
149
- }
150
- async function updateModel(def, id, data) {
151
- const model = await def.findOrFail(id);
152
- if (!Object.keys(data).some((key) => key in def.relations)) {
153
- model.fill(data);
154
- await saveModel(def, model);
155
- return model;
156
- }
157
- const { extractRelationData } = await import("./crud-BCWvg5MI.mjs");
158
- const { columnData, relationOps } = extractRelationData(def, data);
159
- model.fill(columnData);
160
- await saveModel(def, model);
161
- const pkValue = model.get("id");
162
- if (pkValue == null) return model;
163
- for (const [relName, op] of Object.entries(relationOps)) {
164
- const relation = def.relations[relName];
165
- if (!relation) continue;
166
- const relatedDef = relation.relatedModelClass;
167
- const db = relatedDef._orm?.kysely;
168
- if (!db) continue;
169
- if (relation.type === "belongsTo") {
170
- const bop = op;
171
- if (bop.update) {
172
- const fkValue = model.get(relation.foreignKey);
173
- if (fkValue != null) {
174
- const related = await relatedDef.find(fkValue);
175
- if (related) {
176
- related.fill(bop.update);
177
- const { saveModel: saveRel } = await Promise.resolve().then(() => save_exports);
178
- await saveRel(relatedDef, related);
179
- }
180
- }
181
- } else if (bop.upsert) {
182
- const { update, create } = bop.upsert;
183
- const fkValue = model.get(relation.foreignKey);
184
- if (fkValue != null) {
185
- const related = await relatedDef.find(fkValue);
186
- if (related) {
187
- related.fill(update);
188
- const { saveModel: saveRel } = await Promise.resolve().then(() => save_exports);
189
- await saveRel(relatedDef, related);
190
- }
191
- } else {
192
- const created = await relatedDef.insert(create);
193
- await db.updateTable(def.table).set({ [relation.foreignKey]: created.get(relation.localKey) }).where("id", "=", pkValue).execute();
194
- model.set(relation.foreignKey, created.get(relation.localKey));
195
- }
196
- } else if (bop.disconnect) {
197
- await db.updateTable(def.table).set({ [relation.foreignKey]: null }).where("id", "=", pkValue).execute();
198
- model.set(relation.foreignKey, null);
199
- } else if (bop.delete) {
200
- const fkValue = model.get(relation.foreignKey);
201
- if (fkValue != null) {
202
- const related = await relatedDef.find(fkValue);
203
- if (related) {
204
- const { deleteModel: delRel } = await import("./index.mjs").then((n) => n.r);
205
- await delRel(relatedDef, related);
206
- }
207
- }
208
- }
209
- } else if (relation.type === "hasMany" || relation.type === "hasOne") {
210
- const hop = op;
211
- if (hop.create) for (const childData of hop.create) await relatedDef.insert({
212
- ...childData,
213
- [relation.foreignKey]: pkValue
214
- });
215
- if (hop.update) {
216
- const queries = Array.isArray(hop.update?.where) ? hop.update.where : [hop.update?.where];
217
- for (const where of queries) {
218
- const whereKey = Object.keys(where)[0];
219
- await relatedDef.query().where(whereKey, "=", where[whereKey]).all().updateMany(hop.update.data);
220
- }
221
- }
222
- if (hop.delete) {
223
- const queries = Array.isArray(hop.delete) ? hop.delete : [hop.delete];
224
- for (const where of queries) {
225
- const whereKey = Object.keys(where)[0];
226
- await relatedDef.query().where(whereKey, "=", where[whereKey]).all().deleteMany();
227
- }
228
- }
229
- } else if (relation.type === "manyToMany") {
230
- const mop = op;
231
- if (mop.create) {
232
- const throughTable = relation.throughTable;
233
- const fpk = relation.foreignPivotKey;
234
- const rpk = relation.relatedPivotKey;
235
- for (const childData of mop.create) {
236
- const child = await relatedDef.insert(childData);
237
- try {
238
- await db.insertInto(throughTable).values({
239
- [fpk]: pkValue,
240
- [rpk]: child.get(relation.localKey ?? "id")
241
- }).execute();
242
- } catch {}
243
- }
244
- }
245
- if (mop.connect) {
246
- const throughTable = relation.throughTable;
247
- const fpk = relation.foreignPivotKey;
248
- const rpk = relation.relatedPivotKey;
249
- for (const target of mop.connect) {
250
- let targetId = target;
251
- if (typeof target !== "number" && typeof target !== "string") {
252
- const t = target;
253
- const key = Object.keys(t)[0];
254
- targetId = (await relatedDef.query().where(key, "=", t[key]).executeTakeFirst())?.get("id");
255
- }
256
- if (targetId != null) try {
257
- await db.insertInto(throughTable).values({
258
- [fpk]: pkValue,
259
- [rpk]: targetId
260
- }).execute();
261
- } catch {}
262
- }
263
- }
264
- if (mop.disconnect) {
265
- const throughTable = relation.throughTable;
266
- const fpk = relation.foreignPivotKey;
267
- const rpk = relation.relatedPivotKey;
268
- const queries = Array.isArray(mop.disconnect) ? mop.disconnect : [mop.disconnect];
269
- for (const where of queries) if (typeof where === "object" && Object.keys(where).length > 0) {
270
- const key = Object.keys(where)[0];
271
- const val = Object.values(where)[0];
272
- if (key === "id") await db.deleteFrom(throughTable).where(fpk, "=", pkValue).where(rpk, "=", val).execute();
273
- }
274
- }
275
- if (mop.set) {
276
- const throughTable = relation.throughTable;
277
- const fpk = relation.foreignPivotKey;
278
- const rpk = relation.relatedPivotKey;
279
- const current = await db.selectFrom(throughTable).select(rpk).where(fpk, "=", pkValue).execute();
280
- const currentIds = new Set(current.map((r) => r[rpk]));
281
- const desiredIds = /* @__PURE__ */ new Set();
282
- for (const target of mop.set) {
283
- let targetId = target;
284
- if (typeof target !== "number" && typeof target !== "string") {
285
- const t = target;
286
- const key = Object.keys(t)[0];
287
- targetId = (await relatedDef.query().where(key, "=", t[key]).executeTakeFirst())?.get("id");
288
- }
289
- if (targetId != null) {
290
- desiredIds.add(targetId);
291
- if (!currentIds.has(targetId)) try {
292
- await db.insertInto(throughTable).values({
293
- [fpk]: pkValue,
294
- [rpk]: targetId
295
- }).execute();
296
- } catch {}
297
- }
298
- }
299
- for (const id of currentIds) if (!desiredIds.has(id)) await db.deleteFrom(throughTable).where(fpk, "=", pkValue).where(rpk, "=", id).execute();
300
- }
301
- }
302
- }
303
- return model;
304
- }
305
- async function reloadModel(def, model) {
306
- const pk = getPrimaryKeyColumn(def);
307
- const pkValue = model.get(pk);
308
- if (pkValue == null) throw new DatabaseError("Cannot reload model without primary key", "MISSING_ID");
309
- const db = getDb(def);
310
- try {
311
- const row = await db.selectFrom(getTable(def)).selectAll().where(pk, "=", pkValue).executeTakeFirst();
312
- if (row) {
313
- const config = getConfig(def);
314
- const applied = config?.casts ? applyCastsToData(config, row, "get") : row;
315
- const state = getState(model);
316
- state.attributes = { ...applied };
317
- state.original = { ...applied };
318
- }
319
- } catch (e) {
320
- throw normalizeError(e, getTable(def));
321
- }
322
- }
323
- const configMap = /* @__PURE__ */ new WeakMap();
324
- function setConfig(def, config) {
325
- configMap.set(def, config);
326
- }
327
- function getConfig(def) {
328
- return configMap.get(def);
329
- }
330
- //#endregion
331
- export { setConfig as a, save_exports as i, reloadModel as n, saveModel as r, getConfig as t };