peta-orm 0.4.0 → 0.5.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/dist/index.mjs CHANGED
@@ -7,6 +7,7 @@ import { a as getRawRelations, d as setExists, o as getState } from "./state-Ltl
7
7
  import { a as setConfig$1, n as reloadModel, r as saveModel, t as getConfig$1 } from "./save-D5UKXvqC.mjs";
8
8
  import { type } from "arktype";
9
9
  import { Kysely, sql } from "kysely";
10
+ import { pathToFileURL } from "url";
10
11
  import { ulid as ulid$1 } from "ulid";
11
12
  //#region src/columns/arktype.ts
12
13
  function createArkTypeSchemaConfig() {
@@ -189,7 +190,27 @@ function createColumn(schema, dataType, args = [], constraints = []) {
189
190
  }
190
191
  //#endregion
191
192
  //#region src/columns/types.ts
192
- function t(config) {
193
+ /**
194
+ * Pre-configured column type factory backed by ArkType validation.
195
+ *
196
+ * The most common usage — just import and use:
197
+ * ```ts
198
+ * import { t } from "peta-orm"
199
+ * const id = t.integer().primaryKey()
200
+ * ```
201
+ *
202
+ * For a custom validation backend, use `createColumnTypes({ schema })` instead.
203
+ */
204
+ const t = createColumnTypes({ schema: createArkTypeSchemaConfig() });
205
+ /**
206
+ * Create a column type factory with a custom validation schema backend.
207
+ *
208
+ * @example
209
+ * ```ts
210
+ * const t = createColumnTypes({ schema: myCustomSchemaConfig })
211
+ * ```
212
+ */
213
+ function createColumnTypes(config) {
193
214
  const schema = config.schema;
194
215
  function col(dataType, args) {
195
216
  return createColumn(schema, dataType, args);
@@ -217,6 +238,43 @@ function t(config) {
217
238
  };
218
239
  }
219
240
  //#endregion
241
+ //#region src/init.ts
242
+ /**
243
+ * Create a lazy-initialized singleton factory.
244
+ *
245
+ * The factory function is called only once — on the first call to the returned
246
+ * function. Subsequent calls return the same resolved promise. This avoids
247
+ * module-level side effects: importing a model file won't trigger database
248
+ * connection or schema initialization until the first explicit `await db()`.
249
+ *
250
+ * @example
251
+ * ```ts
252
+ * import { createClient } from "@libsql/client"
253
+ * import { LibsqlDialect } from "@libsql/kysely-libsql"
254
+ * import { createDb, createORM, defineModel, t } from "peta-orm"
255
+ *
256
+ * const User = defineModel("users", { columns: { ... } })
257
+ *
258
+ * async function setup() {
259
+ * const client = createClient({ url: "file:my-app.db" })
260
+ * await client.execute("CREATE TABLE IF NOT EXISTS users (...)") // schema init
261
+ * const orm = createORM({ dialect: new LibsqlDialect({ client }) })
262
+ * orm.registerAll(User)
263
+ * return orm
264
+ * }
265
+ *
266
+ * export const db = createDb(setup)
267
+ * // Usage: const orm = await db()
268
+ * ```
269
+ */
270
+ function createDb(factory) {
271
+ let promise = null;
272
+ return () => {
273
+ if (!promise) promise = factory();
274
+ return promise;
275
+ };
276
+ }
277
+ //#endregion
220
278
  //#region src/hooks/static.ts
221
279
  var static_exports = /* @__PURE__ */ __exportAll({
222
280
  addStaticHook: () => addStaticHook,
@@ -1483,9 +1541,6 @@ function defineModel(table, config) {
1483
1541
  def.registerSoftDeletes = (deletedAtCol) => {
1484
1542
  registerSoftDeletesFor(def, deletedAtCol);
1485
1543
  };
1486
- def.discover = async () => {
1487
- throw new Error("discover() not yet implemented in v2");
1488
- };
1489
1544
  return def;
1490
1545
  }
1491
1546
  //#endregion
@@ -1895,9 +1950,14 @@ initRuntime({
1895
1950
  /**
1896
1951
  * Create an ORM instance — the central registry that wires Kysely to model definitions.
1897
1952
  * Replaces createPeta() from v0.x.
1953
+ *
1954
+ * Pass either `dialect` (to auto-create a Kysely instance) or `kysely` (to reuse one).
1955
+ * Passing a pre-existing Kysely instance avoids creating a second connection for
1956
+ * migration runners or other tools that already have their own Kysely.
1898
1957
  */
1899
1958
  function createORM(config) {
1900
- const kysely = new Kysely({ dialect: config.dialect });
1959
+ if (!config.dialect && !config.kysely) throw new Error("createORM: provide either `dialect` (to create a Kysely instance) or `kysely` (to reuse one)");
1960
+ const kysely = config.kysely ?? new Kysely({ dialect: config.dialect });
1901
1961
  const modelMap = /* @__PURE__ */ new Map();
1902
1962
  const orm = {
1903
1963
  kysely,
@@ -1923,6 +1983,26 @@ function createORM(config) {
1923
1983
  },
1924
1984
  getModel(name) {
1925
1985
  return modelMap.get(name);
1986
+ },
1987
+ async discover(pattern) {
1988
+ const entries = await (await import("fast-glob")).glob(pattern, {
1989
+ absolute: true,
1990
+ onlyFiles: true
1991
+ });
1992
+ if (entries.length === 0) throw new Error(`discover: no files matched pattern "${pattern}"`);
1993
+ const models = [];
1994
+ const seen = /* @__PURE__ */ new Set();
1995
+ for (const fp of entries) {
1996
+ const mod = await import(pathToFileURL(fp).href);
1997
+ for (const val of Object.values(mod)) if (val && typeof val === "object" && "columns" in val && "table" in val && typeof val.table === "string" && val.table.length > 0) {
1998
+ const def = val;
1999
+ if (!seen.has(def.table)) {
2000
+ seen.add(def.table);
2001
+ models.push(def);
2002
+ }
2003
+ }
2004
+ }
2005
+ return models;
1926
2006
  }
1927
2007
  };
1928
2008
  if (config.models) for (const [_name, model] of Object.entries(config.models)) orm.register(model);
@@ -2601,4 +2681,65 @@ function defName(instance) {
2601
2681
  return instance.constructor?.name ?? "model";
2602
2682
  }
2603
2683
  //#endregion
2604
- export { Attribute, DatabaseError, ModelNotFoundError, ModelNotRegisteredError, RelationNotAllowedError, RelationNotFoundError, ValidationError, belongsTo, createArkTypeSchemaConfig, createCollection, createColumn, createHookManager, createORM, createORM as createPeta, createPaginator, createQueryBuilder, defineModel, defineMorphMany, defineMorphOne, defineMorphTo, hasMany, hasManyThrough, hasOne, eager_exports as i, manyToMany, relation_exports as n, normalizeError, delete_exports as r, resolveMorphRelation, softDeletes, t, timestamps, ulid };
2684
+ //#region src/repo/index.ts
2685
+ /**
2686
+ * Create a repository — a composable set of chainable query methods.
2687
+ *
2688
+ * ```ts
2689
+ * const userRepo = createRepo(User, {
2690
+ * queryMethods: {
2691
+ * search(q, query: string) {
2692
+ * return q.where('name', 'like', `%${query}%`)
2693
+ * },
2694
+ * },
2695
+ * })
2696
+ * const users = await userRepo.search('john').paginate(1, 20)
2697
+ * ```
2698
+ */
2699
+ function createRepo(model, methods) {
2700
+ const customMethods = /* @__PURE__ */ new Map();
2701
+ if (methods.queryMethods) for (const [name, fn] of Object.entries(methods.queryMethods)) customMethods.set(name, fn);
2702
+ /**
2703
+ * Wrap a QueryBuilder so custom methods are available for chaining.
2704
+ * Custom methods operate on the CURRENT QB (not a fresh one), so
2705
+ * chaining carries forward previous conditions.
2706
+ */
2707
+ function wrapQB(qb) {
2708
+ return new Proxy(qb, { get(target, prop) {
2709
+ if (typeof prop === "string") {
2710
+ if (customMethods.has(prop)) {
2711
+ const fn = customMethods.get(prop);
2712
+ return (...args) => {
2713
+ return wrapQB(fn(target, ...args));
2714
+ };
2715
+ }
2716
+ if (methods.methods?.[prop]) return (...args) => methods.methods[prop](...args);
2717
+ }
2718
+ const val = target[prop];
2719
+ if (typeof val === "function") return function(...args) {
2720
+ const result = val.apply(target, args);
2721
+ return result === target ? wrapQB(result) : result;
2722
+ };
2723
+ return val;
2724
+ } });
2725
+ }
2726
+ return new Proxy({}, { get(_target, prop) {
2727
+ if (typeof prop === "string") {
2728
+ if (customMethods.has(prop)) {
2729
+ const fn = customMethods.get(prop);
2730
+ return (...args) => {
2731
+ return wrapQB(fn(model.query(), ...args));
2732
+ };
2733
+ }
2734
+ if (methods.methods?.[prop]) return (...args) => methods.methods[prop](...args);
2735
+ }
2736
+ const qb = model.query();
2737
+ const val = qb[prop];
2738
+ if (typeof val === "function") return (...args) => {
2739
+ return wrapQB(val.apply(qb, args));
2740
+ };
2741
+ return val;
2742
+ } });
2743
+ }
2744
+ //#endregion
2745
+ export { Attribute, DatabaseError, ModelNotFoundError, ModelNotRegisteredError, RelationNotAllowedError, RelationNotFoundError, ValidationError, belongsTo, createArkTypeSchemaConfig, createCollection, createColumn, createColumnTypes, createDb, createHookManager, createORM, createORM as createPeta, createPaginator, createQueryBuilder, createRepo, defineModel, defineMorphMany, defineMorphOne, defineMorphTo, hasMany, hasManyThrough, hasOne, eager_exports as i, manyToMany, relation_exports as n, normalizeError, delete_exports as r, resolveMorphRelation, softDeletes, t, timestamps, ulid };
package/package.json CHANGED
@@ -2,31 +2,23 @@
2
2
  "name": "peta-orm",
3
3
  "type": "module",
4
4
  "private": false,
5
- "version": "0.4.0",
5
+ "version": "0.5.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": {
16
16
  ".": {
17
17
  "import": "./dist/index.mjs",
18
18
  "types": "./dist/index.d.mts"
19
- },
20
- "./migrator": {
21
- "import": "./dist/migrations/index.mjs",
22
- "types": "./dist/migrations/index.d.mts"
23
19
  }
24
20
  },
25
- "bin": {
26
- "peta": "./bin/peta"
27
- },
28
21
  "files": [
29
- "bin/",
30
22
  "dist/",
31
23
  "README.md",
32
24
  "LICENSE"
@@ -34,6 +26,7 @@
34
26
  "dependencies": {
35
27
  "arktype": "^2.2.0",
36
28
  "cac": "^7.0.0",
29
+ "fast-glob": "^3.3.3",
37
30
  "ora": "^9.4.0",
38
31
  "ulid": "^3.0.2"
39
32
  },
@@ -63,6 +56,6 @@
63
56
  "build": "tsdown",
64
57
  "lint": "bunx biome check src test examples",
65
58
  "lint:fix": "bunx biome check --write --unsafe src test examples",
66
- "prepublish": "bun run build"
59
+ "prepublishOnly": "bun run build"
67
60
  }
68
61
  }
package/bin/peta DELETED
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env bun
2
- import { run } from "../dist/migrations/cli.mjs"
3
- await run()