{"version":3,"file":"database-notification.mjs","names":[],"sources":["../../../../../../../notifications/src/in-app/database-notification.ts"],"sourcesContent":["/**\n * Shipped BASE in-app notification model. The scaffolded user model\n * `extends DatabaseNotification`, sets `static table`, and declares its\n * physical columns ONCE via `static columnMap`. Every accessor below derives\n * from that map, so the model, the repository, and the migration agree by\n * construction.\n *\n * The package ships NO concrete table or migration — those eject to userland\n * (thin eject). See `notificationColumns()` for the matching migration factory.\n *\n * @example\n *   @RegisterModel()\n *   export class Notification extends DatabaseNotification {\n *     public static table = \"notifications\";\n *     public static columnMap: NotificationColumnMap = {\n *       tenant: \"organization_id\",\n *       readAt: \"read_at\",\n *     };\n *   }\n */\nimport { Model } from \"@warlock.js/cascade\";\nimport type { NotificationContract } from \"../contracts\";\nimport type { Id } from \"../types\";\nimport {\n  type NotificationColumnMap,\n  type ResolvedNotificationColumnMap,\n  resolveColumnMap,\n} from \"./column-map\";\n\nexport abstract class DatabaseNotification extends Model implements NotificationContract {\n  /**\n   * Physical column bindings for THIS model's table. Override in the subclass;\n   * the empty default resolves to `{ recipient: \"user_id\", readAt: \"read_at\" }`.\n   */\n  public static columnMap: NotificationColumnMap = {};\n\n  /** The resolved column map for this row's model — defaults applied. */\n  protected get columns(): ResolvedNotificationColumnMap {\n    return resolveColumnMap((this.constructor as typeof DatabaseNotification).columnMap);\n  }\n\n  public get recipientId(): Id {\n    return this.get(this.columns.recipient);\n  }\n\n  /** Tenant scope value, or `undefined` for single-tenant models. */\n  public get tenantId(): Id | undefined {\n    const { tenant } = this.columns;\n    return tenant ? this.get(tenant) : undefined;\n  }\n\n  public get type(): string {\n    return this.get(\"type\");\n  }\n\n  public get isRead(): boolean {\n    const { isRead, readAt } = this.columns;\n\n    if (isRead) {\n      return Boolean(this.get(isRead));\n    }\n\n    return readAt ? this.get(readAt) != null : false;\n  }\n\n  public get readAt(): Date | null {\n    const { readAt } = this.columns;\n    return readAt ? (this.get(readAt) ?? null) : null;\n  }\n\n  /**\n   * Mark this row read. Sets whichever read-state column(s) the model\n   * declares — the boolean (fast unread filtering) and/or the timestamp\n   * (when it was read). Persists via `save()`.\n   */\n  public async markRead(): Promise<void> {\n    const { isRead, readAt } = this.columns;\n\n    if (isRead) {\n      this.set(isRead, true);\n    }\n\n    if (readAt) {\n      this.set(readAt, new Date());\n    }\n\n    await this.save();\n  }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA6BA,IAAsB,uBAAtB,cAAmD,MAAsC;;;;;CAKvF,OAAc,YAAmC,CAAC;;CAGlD,IAAc,UAAyC;EACrD,OAAO,iBAAkB,KAAK,YAA4C,SAAS;CACrF;CAEA,IAAW,cAAkB;EAC3B,OAAO,KAAK,IAAI,KAAK,QAAQ,SAAS;CACxC;;CAGA,IAAW,WAA2B;EACpC,MAAM,EAAE,WAAW,KAAK;EACxB,OAAO,SAAS,KAAK,IAAI,MAAM,IAAI;CACrC;CAEA,IAAW,OAAe;EACxB,OAAO,KAAK,IAAI,MAAM;CACxB;CAEA,IAAW,SAAkB;EAC3B,MAAM,EAAE,QAAQ,WAAW,KAAK;EAEhC,IAAI,QACF,OAAO,QAAQ,KAAK,IAAI,MAAM,CAAC;EAGjC,OAAO,SAAS,KAAK,IAAI,MAAM,KAAK,OAAO;CAC7C;CAEA,IAAW,SAAsB;EAC/B,MAAM,EAAE,WAAW,KAAK;EACxB,OAAO,SAAU,KAAK,IAAI,MAAM,KAAK,OAAQ;CAC/C;;;;;;CAOA,MAAa,WAA0B;EACrC,MAAM,EAAE,QAAQ,WAAW,KAAK;EAEhC,IAAI,QACF,KAAK,IAAI,QAAQ,IAAI;EAGvB,IAAI,QACF,KAAK,IAAI,wBAAQ,IAAI,KAAK,CAAC;EAG7B,MAAM,KAAK,KAAK;CAClB;AACF"}