uql-orm 0.58.0 → 0.59.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.
@@ -186,17 +186,10 @@ export function defineEntity(entity, opts = {}) {
186
186
  meta.derivedName = true;
187
187
  }
188
188
  meta.schema = opts.schema ?? meta.schema;
189
- let proto = Object.getPrototypeOf(entity.prototype);
190
- while (proto.constructor !== Object) {
191
- const parent = proto.constructor;
192
- // An `abstract class BaseEntity` carrying `@Field`s but no `@Entity()` has nobody to drain its
193
- // registrations, so do it here. Walking the *class* prototype chain rather than reading through the
194
- // metadata object's is what makes this work on every transformer: tsc and esbuild chain metadata
195
- // across `extends`, SWC does not.
196
- applyMembers(parent, ownRegistrations(parent));
197
- extendMeta(meta, ensureMeta(parent));
198
- proto = Object.getPrototypeOf(proto);
199
- }
189
+ // The class's real chain first: where a class both extends a base and names one, the one it extends
190
+ // is the nearer, and nearer wins every merge.
191
+ inheritFrom(meta, parentOf(entity));
192
+ inheritFrom(meta, opts.extends);
200
193
  // Derive soft-delete from the (inheritance-merged) fields, so own and inherited markers are handled
201
194
  // uniformly. Exactly one field may be marked; it auto-registers the built-in `softDelete` read
202
195
  // filter (a reserved name - see defineFilter - so it never clobbers a user filter).
@@ -471,6 +464,24 @@ function junctionColumn(meta, idKey) {
471
464
  function getIdKeys(meta) {
472
465
  return getKeys(meta.fields).filter((key) => meta.fields[key]?.isId);
473
466
  }
467
+ /**
468
+ * Merges `ancestor` and its own ancestors into `meta`, nearest first, so a further one never overwrites
469
+ * a nearer. An `abstract class BaseEntity` carrying `@Field`s but no `@Entity()` has nobody to drain
470
+ * its registrations, so do it here. Walking the *class* prototype chain rather than the metadata
471
+ * object's is what makes this work on every transformer: tsc and esbuild chain metadata across
472
+ * `extends`, SWC does not.
473
+ */
474
+ function inheritFrom(meta, ancestor) {
475
+ for (let parent = ancestor; parent && parent !== Object; parent = parentOf(parent)) {
476
+ const base = parent;
477
+ applyMembers(base, ownRegistrations(base));
478
+ extendMeta(meta, ensureMeta(base));
479
+ }
480
+ }
481
+ /** The class `entity` extends, `Object` where it extends nothing. */
482
+ function parentOf(entity) {
483
+ return Object.getPrototypeOf(entity.prototype)?.constructor;
484
+ }
474
485
  function extendMeta(target, source) {
475
486
  const sourceFields = { ...source.fields };
476
487
  // A subclass declaring its own primary key drops the parent's - every column of it, or a composite
@@ -878,6 +878,13 @@ type EntityRelationOptions<E> = {
878
878
  */
879
879
  export type EntityOptions<E = unknown> = {
880
880
  readonly name?: string;
881
+ /**
882
+ * The base to inherit fields, relations, hooks and filters from, for a class that cannot extend one
883
+ * (minted at runtime, or its base chosen from data): the merge `class Child extends Base` does, with
884
+ * the class's real base nearer, so it wins. Checked against whatever properties the entity declares,
885
+ * which a class behind an index signature has none of. See the Inheritance guide.
886
+ */
887
+ readonly extends?: string extends keyof E ? Type<object> : Type<Partial<E>>;
881
888
  /**
882
889
  * The schema (in MySQL terms, database) this table lives in, pinning it whichever pool reads it;
883
890
  * unset follows the pool's own. Not in `name`: a dotted `name` is rejected.
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "homepage": "https://uql-orm.dev",
4
4
  "description": "The JSON-native TypeScript ORM for Bun, Browsers, Edge, Deno, Node, Workers. Supports PostgreSQL, PGlite, MySQL, MariaDB, SQLite, CockroachDB, SQL Server, Turso, Neon, Cloudflare D1 and MongoDB. Queries are plain JSON, typed to the leaf.",
5
5
  "license": "MIT",
6
- "version": "0.58.0",
6
+ "version": "0.59.0",
7
7
  "type": "module",
8
8
  "engines": {
9
9
  "node": ">=24"