Skip to content

fix: getMetadata shares inherited metadata by reference, so subclass decorators write into the parent and sibling tables #43

Closed

Description

@Upd4ting

getMetadata stores the parent's metadata object itself on a subclass (src/common.ts, the inherited branch of getMetadata), not a copy. A decorator on a subclass therefore writes into the parent's metadata and into every sibling's, which breaks the inheritance pattern documented in docs/2.table-definitions.md ("Inheritance").

Reproduction (CommonJS, against the built package; identical on main and on #42):

const { Table, Field, RegisterTable, getMetadata, DatumStaticMetadata } = require("@antelopejs/interface-database-decorators");
const str = { name: "string", is: (u) => typeof u === "string", decode: (u) => ({ _tag: "Right", right: u }), encode: (a) => a };

class Base extends Table {}
Field(str)(Base.prototype, "createdBy");

class Users extends Base {}
Field(str)(Users.prototype, "email");
RegisterTable("users", "app")(Users);

class Posts extends Base {}
Field(str)(Posts.prototype, "title");
RegisterTable("posts", "app")(Posts);

for (const c of [Base, Users, Posts]) {
  const m = getMetadata(c, DatumStaticMetadata);
  console.log(`${c.name}: tableName=${m.tableName} fields=${Object.keys(m.fields)}`);
}
console.log("Users.table(instance) ->", Users.table({ table: (name) => `table(${name})` }));

Output:

Base: tableName=posts fields=createdBy,email,title
Users: tableName=posts fields=createdBy,email,title
Posts: tableName=posts fields=createdBy,email,title
Users.table(instance) -> table(posts)

Expected: Users keeps tableName=users and fields createdBy,email; Posts keeps posts and createdBy,title; Base keeps only createdBy.

The same sharing affects ModifiersStaticMetadata (@Hashed on a child's field adds it to the parent's modified fields) and @Fixture (a sibling's generator becomes every sibling's generator, so insertAllFixtureData calls Posts' generator with Users).

Activity

  1. Upd4ting commented on Nov 4, 2026

    @Upd4ting
    MemberAuthor

    Fixed by #54 (copy the metadata a subclass inherits instead of sharing it), landed on main (921bf9d, the landed campaign/integration PR #87). Checked on main: a Base with two subclasses now gives [createdBy], [createdBy,email], [createdBy,title]; the 243 module tests pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions