@getstrata/core 0.5.10 → 0.5.12

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.
@@ -1,5 +1,5 @@
1
1
  import { type CursorPaginatedResult, type PaginatedResult } from "../pagination/index.ts";
2
- import { type BelongsToRelation, type HasManyRelation } from "./relationships.ts";
2
+ import { type BelongsToRelation, type HasManyRelation, type MorphManyRelation, type MorphOneRelation, type MorphToRelation } from "./relationships.ts";
3
3
  import { RepositoryQuery } from "./repositoryQuery.ts";
4
4
  import type { TableDefinition } from "./table.ts";
5
5
  import type { MutationValues, QueryOptions, QueryWhere, UpdateValues } from "./types.ts";
@@ -54,6 +54,9 @@ declare class BaseRepository<TEntity extends object, PrimaryKey extends keyof TE
54
54
  findByHasManyRelation<TParent extends object, LocalKey extends keyof TParent & string, ForeignKey extends keyof TEntity & string>(relation: HasManyRelation<TParent, TEntity, LocalKey, ForeignKey>, parentId: TParent[LocalKey], options?: Omit<QueryOptions<TEntity>, "where">): Promise<TEntity[]>;
55
55
  loadHasManyForParents<TParent extends object, LocalKey extends keyof TParent & string, ForeignKey extends keyof TEntity & string>(parents: readonly TParent[], relation: HasManyRelation<TParent, TEntity, LocalKey, ForeignKey>, options?: Omit<QueryOptions<TEntity>, "where">): Promise<Map<TParent[LocalKey], TEntity[]>>;
56
56
  loadBelongsToForParents<TChild extends object, TParent extends object, ForeignKey extends keyof TChild & string, OwnerKey extends keyof TParent & string>(children: readonly TChild[], relation: BelongsToRelation<TChild, TParent, ForeignKey, OwnerKey>, parentRepository: BaseRepository<TParent, OwnerKey>, options?: Omit<QueryOptions<TParent>, "where">): Promise<Map<TChild[ForeignKey], TParent>>;
57
+ loadMorphManyForParents<TParent extends object, LocalKey extends keyof TParent & string, MorphTypeKey extends keyof TEntity & string, MorphIdKey extends keyof TEntity & string>(parents: readonly TParent[], relation: MorphManyRelation<TParent, TEntity, LocalKey, MorphTypeKey, MorphIdKey>, options?: Omit<QueryOptions<TEntity>, "where">): Promise<Map<TParent[LocalKey], TEntity[]>>;
58
+ loadMorphOneForParents<TParent extends object, LocalKey extends keyof TParent & string, MorphTypeKey extends keyof TEntity & string, MorphIdKey extends keyof TEntity & string>(parents: readonly TParent[], relation: MorphOneRelation<TParent, TEntity, LocalKey, MorphTypeKey, MorphIdKey>, options?: Omit<QueryOptions<TEntity>, "where">): Promise<Map<TParent[LocalKey], TEntity | undefined>>;
59
+ loadMorphToForChildren<TChild extends object, TParent extends object, MorphTypeKey extends keyof TChild & string, MorphIdKey extends keyof TChild & string, OwnerKey extends keyof TParent & string>(children: readonly TChild[], relation: MorphToRelation<TChild, MorphTypeKey, MorphIdKey>, repositoriesByType: ReadonlyMap<string, BaseRepository<TParent, OwnerKey>>, options?: Omit<QueryOptions<TParent>, "where">): Promise<Map<TChild[MorphIdKey], TParent>>;
57
60
  }
58
61
  export default BaseRepository;
59
62
  export type { DatabaseConnection };
@@ -5,8 +5,8 @@ export { mapDatabaseError, withDatabaseErrorHandling } from "./errors.ts";
5
5
  export type { CastType, GlobalScopeFn, ModelConstructor } from "./model.ts";
6
6
  export { applyCasts, dehydrateValue, filterMassAssignable, hydrateValue, Model, registerModelRepository, } from "./model.ts";
7
7
  export { buildAdvancedWhereClause, buildCountQuery, buildDeleteByIdQuery, buildGroupedCountQuery, buildInsertQuery, buildJoinClause, buildOrderByClause, buildProjectionQuery, buildQueryWhereClause, buildRestoreByIdQuery, buildSelectQuery, buildSoftDeleteByIdQuery, buildUpdateQuery, buildWhereClause, parseQualifiedColumn, qualifyColumn, quoteIdentifier, resolveQualifiedColumn, resolveSoftDeleteColumn, } from "./query.ts";
8
- export type { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasOneRelation, } from "./relationships.ts";
9
- export { belongsTo, belongsToMany, hasMany, hasOne, indexBelongsToManyRelation, indexBelongsToRelation, indexHasManyRelation, indexHasOneRelation, } from "./relationships.ts";
8
+ export type { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasOneRelation, MorphManyRelation, MorphOneRelation, MorphToRelation, } from "./relationships.ts";
9
+ export { belongsTo, belongsToMany, hasMany, hasOne, indexBelongsToManyRelation, indexBelongsToRelation, indexHasManyRelation, indexHasOneRelation, indexMorphManyRelation, indexMorphOneRelation, indexMorphToRelation, morphMany, morphOne, morphTo, } from "./relationships.ts";
10
10
  export { RepositoryQuery } from "./repositoryQuery.ts";
11
11
  export type { BlueprintAction, BlueprintCallback, ColumnKind, DatabaseDriver, ForeignKeyOptions, Grammar, IndexDefinition, IndexKind, ResolveDatabaseDriverOptions, SchemaBuilder, } from "./schema/index.ts";
12
12
  export { Blueprint, ColumnDefinition, compileBlueprint, createSchemaBuilder, ForeignIdColumnDefinition, grammarForDriver, inferReferencedTable, MySqlGrammar, PostgresGrammar, resolveDatabaseDriver, Schema, SqliteGrammar, UnsupportedSchemaFeatureError, } from "./schema/index.ts";
@@ -52,5 +52,49 @@ declare function indexHasManyRelation<TParent, TChild, LocalKey extends keyof TP
52
52
  declare function indexHasOneRelation<TParent, TChild, LocalKey extends keyof TParent & string, ForeignKey extends keyof TChild & string>(parents: readonly TParent[], children: readonly TChild[], relation: HasOneRelation<TParent, TChild, LocalKey, ForeignKey>): Map<TParent[LocalKey], TChild | undefined>;
53
53
  declare function indexBelongsToRelation<TChild, TParent, ForeignKey extends keyof TChild & string, OwnerKey extends keyof TParent & string>(children: readonly TChild[], parents: readonly TParent[], relation: BelongsToRelation<TChild, TParent, ForeignKey, OwnerKey>): Map<TChild[ForeignKey], TParent>;
54
54
  declare function indexBelongsToManyRelation<TParent, TRelated, Pivot extends object, ParentKey extends keyof TParent & string, RelatedKey extends keyof TRelated & string, ForeignPivotKey extends keyof Pivot & string, RelatedPivotKey extends keyof Pivot & string>(parents: readonly TParent[], pivotRows: readonly Pivot[], relatedRows: readonly TRelated[], relation: BelongsToManyRelation<TParent, TRelated, Pivot, ParentKey, RelatedKey, ForeignPivotKey, RelatedPivotKey>): Map<TParent[ParentKey], TRelated[]>;
55
- export type { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasOneRelation };
56
- export { belongsTo, belongsToMany, hasMany, hasOne, indexBelongsToManyRelation, indexBelongsToRelation, indexHasManyRelation, indexHasOneRelation, };
55
+ interface MorphManyRelation<TParent, TChild, LocalKey extends keyof TParent & string = keyof TParent & string, MorphTypeKey extends keyof TChild & string = keyof TChild & string, MorphIdKey extends keyof TChild & string = keyof TChild & string> {
56
+ type: "morphMany";
57
+ name: string;
58
+ localKey: LocalKey;
59
+ morphTypeKey: MorphTypeKey;
60
+ morphIdKey: MorphIdKey;
61
+ morphType: string;
62
+ }
63
+ interface MorphOneRelation<TParent, TChild, LocalKey extends keyof TParent & string = keyof TParent & string, MorphTypeKey extends keyof TChild & string = keyof TChild & string, MorphIdKey extends keyof TChild & string = keyof TChild & string> {
64
+ type: "morphOne";
65
+ name: string;
66
+ localKey: LocalKey;
67
+ morphTypeKey: MorphTypeKey;
68
+ morphIdKey: MorphIdKey;
69
+ morphType: string;
70
+ }
71
+ interface MorphToRelation<TChild, MorphTypeKey extends keyof TChild & string = keyof TChild & string, MorphIdKey extends keyof TChild & string = keyof TChild & string> {
72
+ type: "morphTo";
73
+ name: string;
74
+ morphTypeKey: MorphTypeKey;
75
+ morphIdKey: MorphIdKey;
76
+ }
77
+ declare function morphMany<TParent, TChild, LocalKey extends keyof TParent & string = keyof TParent & string, MorphTypeKey extends keyof TChild & string = keyof TChild & string, MorphIdKey extends keyof TChild & string = keyof TChild & string>(definition: {
78
+ name: string;
79
+ localKey: LocalKey;
80
+ morphTypeKey: MorphTypeKey;
81
+ morphIdKey: MorphIdKey;
82
+ morphType: string;
83
+ }): MorphManyRelation<TParent, TChild, LocalKey, MorphTypeKey, MorphIdKey>;
84
+ declare function morphOne<TParent, TChild, LocalKey extends keyof TParent & string = keyof TParent & string, MorphTypeKey extends keyof TChild & string = keyof TChild & string, MorphIdKey extends keyof TChild & string = keyof TChild & string>(definition: {
85
+ name: string;
86
+ localKey: LocalKey;
87
+ morphTypeKey: MorphTypeKey;
88
+ morphIdKey: MorphIdKey;
89
+ morphType: string;
90
+ }): MorphOneRelation<TParent, TChild, LocalKey, MorphTypeKey, MorphIdKey>;
91
+ declare function morphTo<TChild, MorphTypeKey extends keyof TChild & string = keyof TChild & string, MorphIdKey extends keyof TChild & string = keyof TChild & string>(definition: {
92
+ name: string;
93
+ morphTypeKey: MorphTypeKey;
94
+ morphIdKey: MorphIdKey;
95
+ }): MorphToRelation<TChild, MorphTypeKey, MorphIdKey>;
96
+ declare function indexMorphManyRelation<TParent, TChild, LocalKey extends keyof TParent & string, MorphTypeKey extends keyof TChild & string, MorphIdKey extends keyof TChild & string>(parents: readonly TParent[], children: readonly TChild[], relation: MorphManyRelation<TParent, TChild, LocalKey, MorphTypeKey, MorphIdKey>): Map<TParent[LocalKey], TChild[]>;
97
+ declare function indexMorphOneRelation<TParent, TChild, LocalKey extends keyof TParent & string, MorphTypeKey extends keyof TChild & string, MorphIdKey extends keyof TChild & string>(parents: readonly TParent[], children: readonly TChild[], relation: MorphOneRelation<TParent, TChild, LocalKey, MorphTypeKey, MorphIdKey>): Map<TParent[LocalKey], TChild | undefined>;
98
+ declare function indexMorphToRelation<TChild, TParent extends object, MorphTypeKey extends keyof TChild & string, MorphIdKey extends keyof TChild & string, OwnerKey extends keyof TParent & string>(children: readonly TChild[], parentsByType: ReadonlyMap<string, ReadonlyMap<TParent[OwnerKey], TParent>>, relation: MorphToRelation<TChild, MorphTypeKey, MorphIdKey>): Map<TChild[MorphIdKey], TParent>;
99
+ export type { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasOneRelation, MorphManyRelation, MorphOneRelation, MorphToRelation, };
100
+ export { belongsTo, belongsToMany, hasMany, hasOne, indexBelongsToManyRelation, indexBelongsToRelation, indexHasManyRelation, indexHasOneRelation, indexMorphManyRelation, indexMorphOneRelation, indexMorphToRelation, morphMany, morphOne, morphTo, };
@@ -1,6 +1,6 @@
1
1
  import type { PaginatedResult } from "../pagination/index.ts";
2
2
  import type BaseRepository from "./baseRepository.ts";
3
- import type { BelongsToRelation, HasManyRelation } from "./relationships.ts";
3
+ import type { BelongsToRelation, HasManyRelation, MorphManyRelation, MorphOneRelation, MorphToRelation } from "./relationships.ts";
4
4
  import type { QueryOptions, QueryWhere } from "./types.ts";
5
5
  import { WhereBuilder } from "./whereBuilder.ts";
6
6
  type LoadedRow = Record<string, unknown>;
@@ -22,6 +22,9 @@ declare class RepositoryQuery<TEntity extends object, PrimaryKey extends keyof T
22
22
  having(having: QueryWhere<TEntity>): this;
23
23
  withHasMany<TChild extends object, LocalKey extends keyof TEntity & string, ForeignKey extends keyof TChild & string, Alias extends string>(as: Alias, relation: HasManyRelation<TEntity, TChild, LocalKey, ForeignKey>, childRepository: BaseRepository<TChild, keyof TChild & string>, options?: Omit<QueryOptions<TChild>, "where">): this;
24
24
  withBelongsTo<TParent extends object, ForeignKey extends keyof TEntity & string, OwnerKey extends keyof TParent & string, Alias extends string>(as: Alias, relation: BelongsToRelation<TEntity, TParent, ForeignKey, OwnerKey>, parentRepository: BaseRepository<TParent, OwnerKey>, options?: Omit<QueryOptions<TParent>, "where">): this;
25
+ withMorphMany<TChild extends object, LocalKey extends keyof TEntity & string, MorphTypeKey extends keyof TChild & string, MorphIdKey extends keyof TChild & string, Alias extends string>(as: Alias, relation: MorphManyRelation<TEntity, TChild, LocalKey, MorphTypeKey, MorphIdKey>, childRepository: BaseRepository<TChild, keyof TChild & string>, options?: Omit<QueryOptions<TChild>, "where">): this;
26
+ withMorphOne<TChild extends object, LocalKey extends keyof TEntity & string, MorphTypeKey extends keyof TChild & string, MorphIdKey extends keyof TChild & string, Alias extends string>(as: Alias, relation: MorphOneRelation<TEntity, TChild, LocalKey, MorphTypeKey, MorphIdKey>, childRepository: BaseRepository<TChild, keyof TChild & string>, options?: Omit<QueryOptions<TChild>, "where">): this;
27
+ withMorphTo<TParent extends object, MorphTypeKey extends keyof TEntity & string, MorphIdKey extends keyof TEntity & string, Alias extends string>(as: Alias, relation: MorphToRelation<TEntity, MorphTypeKey, MorphIdKey>, repositoriesByType: ReadonlyMap<string, BaseRepository<TParent, keyof TParent & string>>, options?: Omit<QueryOptions<TParent>, "where">): this;
25
28
  get(): Promise<Array<TEntity & LoadedRow>>;
26
29
  first(): Promise<(TEntity & LoadedRow) | null>;
27
30
  paginate(options: {
@@ -2,6 +2,7 @@ interface MailMessage {
2
2
  to: string;
3
3
  subject: string;
4
4
  body: string;
5
+ html?: string;
5
6
  }
6
7
  interface MailDriver {
7
8
  send(message: MailMessage): Promise<void>;
@@ -16,6 +17,7 @@ interface SmtpConfig {
16
17
  }
17
18
  type SmtpTransport = (config: SmtpConfig, message: MailMessage) => Promise<void>;
18
19
  declare function resolveSmtpConfig(): SmtpConfig;
20
+ declare function buildSmtpPayload(from: string, message: MailMessage): string;
19
21
  declare class LogMailDriver implements MailDriver {
20
22
  send(message: MailMessage): Promise<void>;
21
23
  }
@@ -33,4 +35,4 @@ declare class Mailer {
33
35
  declare function createMailDriver(): MailDriver;
34
36
  declare function mailer(): Mailer;
35
37
  export type { MailDriver, MailMessage, SmtpConfig, SmtpTransport };
36
- export { createMailDriver, LogMailDriver, Mailer, mailer, resolveSmtpConfig, SmtpMailDriver };
38
+ export { buildSmtpPayload, createMailDriver, LogMailDriver, Mailer, mailer, resolveSmtpConfig, SmtpMailDriver, };
@@ -0,0 +1,15 @@
1
+ interface MarkdownMailLayoutOptions {
2
+ title?: string;
3
+ preview?: string;
4
+ footer?: string;
5
+ }
6
+ interface RenderedMarkdownMail {
7
+ html: string;
8
+ text: string;
9
+ }
10
+ declare function stripMarkdown(markdown: string): string;
11
+ declare function markdownToHtml(markdown: string): string;
12
+ declare function wrapMarkdownMailLayout(bodyHtml: string, options?: MarkdownMailLayoutOptions): string;
13
+ declare function renderMarkdownMail(markdown: string, options?: MarkdownMailLayoutOptions): RenderedMarkdownMail;
14
+ export type { MarkdownMailLayoutOptions, RenderedMarkdownMail };
15
+ export { markdownToHtml, renderMarkdownMail, stripMarkdown, wrapMarkdownMailLayout };
@@ -0,0 +1,13 @@
1
+ import type { MailMessage } from "./mailer.ts";
2
+ import type { Mailer } from "./mailer.ts";
3
+ import { type MarkdownMailLayoutOptions } from "./markdownMail.ts";
4
+ interface MarkdownMailableInput {
5
+ to: string;
6
+ subject: string;
7
+ markdown: string;
8
+ layout?: MarkdownMailLayoutOptions;
9
+ }
10
+ declare function buildMarkdownMailMessage(input: MarkdownMailableInput): MailMessage;
11
+ declare function sendMarkdownMail(mailer: Mailer, input: MarkdownMailableInput): Promise<void>;
12
+ export type { MarkdownMailableInput };
13
+ export { buildMarkdownMailMessage, sendMarkdownMail };
@@ -0,0 +1,13 @@
1
+ import type { Mailer } from "../mail/mailer.ts";
2
+ import type { Notification } from "./notification.ts";
3
+ import type { DatabaseNotificationStore, Notifiable } from "./types.ts";
4
+ declare class NotificationDispatcher {
5
+ private readonly mailer;
6
+ private readonly databaseStore;
7
+ constructor(mailer: Mailer, databaseStore?: DatabaseNotificationStore | null);
8
+ send(notifiable: Notifiable, notification: Notification): Promise<void>;
9
+ private sendMail;
10
+ private sendDatabase;
11
+ }
12
+ declare function createNotificationDispatcher(mailer: Mailer, databaseStore?: DatabaseNotificationStore): NotificationDispatcher;
13
+ export { createNotificationDispatcher, NotificationDispatcher };
@@ -0,0 +1,3 @@
1
+ export { createNotificationDispatcher, NotificationDispatcher } from "./dispatcher.ts";
2
+ export { Notification } from "./notification.ts";
3
+ export type { DatabaseNotificationPayload, DatabaseNotificationStore, MailNotificationMessage, Notifiable, NotificationChannelName, } from "./types.ts";
@@ -0,0 +1,7 @@
1
+ import type { DatabaseNotificationPayload, MailNotificationMessage, NotificationChannelName } from "./types.ts";
2
+ declare abstract class Notification<TNotifiable = unknown> {
3
+ abstract via(notifiable: TNotifiable): NotificationChannelName[];
4
+ toMail(_notifiable: TNotifiable): MailNotificationMessage | null;
5
+ toDatabase(_notifiable: TNotifiable): DatabaseNotificationPayload | null;
6
+ }
7
+ export { Notification };
@@ -0,0 +1,25 @@
1
+ type NotificationChannelName = "mail" | "database";
2
+ interface MailNotificationMessage {
3
+ subject: string;
4
+ markdown?: string;
5
+ body?: string;
6
+ html?: string;
7
+ }
8
+ interface DatabaseNotificationPayload {
9
+ type: string;
10
+ title: string;
11
+ body: string;
12
+ data?: Record<string, unknown>;
13
+ notifiableType?: string | null;
14
+ notifiableId?: number | null;
15
+ }
16
+ interface DatabaseNotificationStore {
17
+ create(input: DatabaseNotificationPayload & {
18
+ userId: number;
19
+ }): Promise<Record<string, unknown>>;
20
+ }
21
+ interface Notifiable {
22
+ getNotificationKey(): string | number;
23
+ routeNotificationFor(channel: NotificationChannelName): string | number | null;
24
+ }
25
+ export type { DatabaseNotificationPayload, DatabaseNotificationStore, MailNotificationMessage, Notifiable, NotificationChannelName, };
@@ -866,6 +866,66 @@ function indexBelongsToManyRelation(parents, pivotRows, relatedRows, relation) {
866
866
  }
867
867
  return groups;
868
868
  }
869
+ function morphMany(definition) {
870
+ return {
871
+ type: "morphMany",
872
+ ...definition
873
+ };
874
+ }
875
+ function morphOne(definition) {
876
+ return {
877
+ type: "morphOne",
878
+ ...definition
879
+ };
880
+ }
881
+ function morphTo(definition) {
882
+ return {
883
+ type: "morphTo",
884
+ ...definition
885
+ };
886
+ }
887
+ function indexMorphManyRelation(parents, children, relation) {
888
+ const groups = new Map;
889
+ for (const parent of parents) {
890
+ groups.set(parent[relation.localKey], []);
891
+ }
892
+ for (const child of children) {
893
+ if (child[relation.morphTypeKey] !== relation.morphType) {
894
+ continue;
895
+ }
896
+ const key = child[relation.morphIdKey];
897
+ const group = groups.get(key);
898
+ if (!group) {
899
+ continue;
900
+ }
901
+ group.push(child);
902
+ }
903
+ return groups;
904
+ }
905
+ function indexMorphOneRelation(parents, children, relation) {
906
+ const grouped = indexMorphManyRelation(parents, children, relation);
907
+ const result = new Map;
908
+ for (const parent of parents) {
909
+ const matches = grouped.get(parent[relation.localKey]) ?? [];
910
+ result.set(parent[relation.localKey], matches[0]);
911
+ }
912
+ return result;
913
+ }
914
+ function indexMorphToRelation(children, parentsByType, relation) {
915
+ const result = new Map;
916
+ for (const child of children) {
917
+ const morphType = String(child[relation.morphTypeKey]);
918
+ const parents = parentsByType.get(morphType);
919
+ if (!parents) {
920
+ continue;
921
+ }
922
+ const parent = parents.get(child[relation.morphIdKey]);
923
+ if (parent) {
924
+ result.set(child[relation.morphIdKey], parent);
925
+ }
926
+ }
927
+ return result;
928
+ }
869
929
 
870
930
  // ../../src/config/database.ts
871
931
  function readInteger(name, fallback) {
@@ -1069,6 +1129,37 @@ class RepositoryQuery {
1069
1129
  });
1070
1130
  return this;
1071
1131
  }
1132
+ withMorphMany(as, relation, childRepository, options = {}) {
1133
+ this.eagerLoads.push({
1134
+ kind: "morphMany",
1135
+ as,
1136
+ relation,
1137
+ repository: childRepository,
1138
+ options
1139
+ });
1140
+ return this;
1141
+ }
1142
+ withMorphOne(as, relation, childRepository, options = {}) {
1143
+ this.eagerLoads.push({
1144
+ kind: "morphOne",
1145
+ as,
1146
+ relation,
1147
+ repository: childRepository,
1148
+ options
1149
+ });
1150
+ return this;
1151
+ }
1152
+ withMorphTo(as, relation, repositoriesByType, options = {}) {
1153
+ this.eagerLoads.push({
1154
+ kind: "morphTo",
1155
+ as,
1156
+ relation,
1157
+ repository: this.repository,
1158
+ morphRepositories: repositoriesByType,
1159
+ options
1160
+ });
1161
+ return this;
1162
+ }
1072
1163
  async get() {
1073
1164
  const rows = await this.repository.findAll(this.buildOptions());
1074
1165
  return await this.attach(rows);
@@ -1129,6 +1220,33 @@ class RepositoryQuery {
1129
1220
  }));
1130
1221
  continue;
1131
1222
  }
1223
+ if (load.kind === "morphMany") {
1224
+ const relation2 = load.relation;
1225
+ const grouped2 = await load.repository.withConnection(this.repository.getConnection()).loadMorphManyForParents(rows, relation2, load.options);
1226
+ result = result.map((row) => ({
1227
+ ...row,
1228
+ [load.as]: grouped2.get(row[relation2.localKey]) ?? []
1229
+ }));
1230
+ continue;
1231
+ }
1232
+ if (load.kind === "morphOne") {
1233
+ const relation2 = load.relation;
1234
+ const grouped2 = await load.repository.withConnection(this.repository.getConnection()).loadMorphOneForParents(rows, relation2, load.options);
1235
+ result = result.map((row) => ({
1236
+ ...row,
1237
+ [load.as]: grouped2.get(row[relation2.localKey])
1238
+ }));
1239
+ continue;
1240
+ }
1241
+ if (load.kind === "morphTo") {
1242
+ const relation2 = load.relation;
1243
+ const grouped2 = await this.repository.loadMorphToForChildren(rows, relation2, load.morphRepositories ?? new Map, load.options);
1244
+ result = result.map((row) => ({
1245
+ ...row,
1246
+ [load.as]: grouped2.get(row[relation2.morphIdKey])
1247
+ }));
1248
+ continue;
1249
+ }
1132
1250
  const relation = load.relation;
1133
1251
  const grouped = await this.repository.loadBelongsToForParents(rows, relation, load.repository, load.options);
1134
1252
  result = result.map((row) => ({
@@ -1405,6 +1523,56 @@ class BaseRepository {
1405
1523
  }, options);
1406
1524
  return indexBelongsToRelation(children, parents, relation);
1407
1525
  }
1526
+ async loadMorphManyForParents(parents, relation, options = {}) {
1527
+ if (parents.length === 0) {
1528
+ return indexMorphManyRelation(parents, [], relation);
1529
+ }
1530
+ const parentIds = [...new Set(parents.map((parent) => parent[relation.localKey]))];
1531
+ const children = await this.findWhere({
1532
+ [relation.morphTypeKey]: relation.morphType,
1533
+ [relation.morphIdKey]: parentIds
1534
+ }, options);
1535
+ return indexMorphManyRelation(parents, children, relation);
1536
+ }
1537
+ async loadMorphOneForParents(parents, relation, options = {}) {
1538
+ const grouped = await this.loadMorphManyForParents(parents, relation, options);
1539
+ const result = new Map;
1540
+ for (const parent of parents) {
1541
+ const matches = grouped.get(parent[relation.localKey]) ?? [];
1542
+ result.set(parent[relation.localKey], matches[0]);
1543
+ }
1544
+ return result;
1545
+ }
1546
+ async loadMorphToForChildren(children, relation, repositoriesByType, options = {}) {
1547
+ if (children.length === 0) {
1548
+ return new Map;
1549
+ }
1550
+ const idsByType = new Map;
1551
+ for (const child of children) {
1552
+ const morphType = String(child[relation.morphTypeKey]);
1553
+ const morphId = child[relation.morphIdKey];
1554
+ const ids = idsByType.get(morphType) ?? new Set;
1555
+ ids.add(morphId);
1556
+ idsByType.set(morphType, ids);
1557
+ }
1558
+ const parentsByType = new Map;
1559
+ for (const [morphType, ids] of idsByType) {
1560
+ const repository = repositoriesByType.get(morphType);
1561
+ if (!repository) {
1562
+ continue;
1563
+ }
1564
+ const ownerKey = repository.getTable().primaryKey;
1565
+ const parents = await repository.withConnection(this.connection).findWhere({
1566
+ [ownerKey]: [...ids]
1567
+ }, options);
1568
+ const indexed = new Map;
1569
+ for (const parent of parents) {
1570
+ indexed.set(parent[ownerKey], parent);
1571
+ }
1572
+ parentsByType.set(morphType, indexed);
1573
+ }
1574
+ return indexMorphToRelation(children, parentsByType, relation);
1575
+ }
1408
1576
  }
1409
1577
  var baseRepository_default = BaseRepository;
1410
1578
  // ../../src/core/database/connection.ts
@@ -664,6 +664,66 @@ function indexBelongsToManyRelation(parents, pivotRows, relatedRows, relation) {
664
664
  }
665
665
  return groups;
666
666
  }
667
+ function morphMany(definition) {
668
+ return {
669
+ type: "morphMany",
670
+ ...definition
671
+ };
672
+ }
673
+ function morphOne(definition) {
674
+ return {
675
+ type: "morphOne",
676
+ ...definition
677
+ };
678
+ }
679
+ function morphTo(definition) {
680
+ return {
681
+ type: "morphTo",
682
+ ...definition
683
+ };
684
+ }
685
+ function indexMorphManyRelation(parents, children, relation) {
686
+ const groups = new Map;
687
+ for (const parent of parents) {
688
+ groups.set(parent[relation.localKey], []);
689
+ }
690
+ for (const child of children) {
691
+ if (child[relation.morphTypeKey] !== relation.morphType) {
692
+ continue;
693
+ }
694
+ const key = child[relation.morphIdKey];
695
+ const group = groups.get(key);
696
+ if (!group) {
697
+ continue;
698
+ }
699
+ group.push(child);
700
+ }
701
+ return groups;
702
+ }
703
+ function indexMorphOneRelation(parents, children, relation) {
704
+ const grouped = indexMorphManyRelation(parents, children, relation);
705
+ const result = new Map;
706
+ for (const parent of parents) {
707
+ const matches = grouped.get(parent[relation.localKey]) ?? [];
708
+ result.set(parent[relation.localKey], matches[0]);
709
+ }
710
+ return result;
711
+ }
712
+ function indexMorphToRelation(children, parentsByType, relation) {
713
+ const result = new Map;
714
+ for (const child of children) {
715
+ const morphType = String(child[relation.morphTypeKey]);
716
+ const parents = parentsByType.get(morphType);
717
+ if (!parents) {
718
+ continue;
719
+ }
720
+ const parent = parents.get(child[relation.morphIdKey]);
721
+ if (parent) {
722
+ result.set(child[relation.morphIdKey], parent);
723
+ }
724
+ }
725
+ return result;
726
+ }
667
727
 
668
728
  // ../../src/config/database.ts
669
729
  function readInteger(name, fallback) {
@@ -867,6 +927,37 @@ class RepositoryQuery {
867
927
  });
868
928
  return this;
869
929
  }
930
+ withMorphMany(as, relation, childRepository, options = {}) {
931
+ this.eagerLoads.push({
932
+ kind: "morphMany",
933
+ as,
934
+ relation,
935
+ repository: childRepository,
936
+ options
937
+ });
938
+ return this;
939
+ }
940
+ withMorphOne(as, relation, childRepository, options = {}) {
941
+ this.eagerLoads.push({
942
+ kind: "morphOne",
943
+ as,
944
+ relation,
945
+ repository: childRepository,
946
+ options
947
+ });
948
+ return this;
949
+ }
950
+ withMorphTo(as, relation, repositoriesByType, options = {}) {
951
+ this.eagerLoads.push({
952
+ kind: "morphTo",
953
+ as,
954
+ relation,
955
+ repository: this.repository,
956
+ morphRepositories: repositoriesByType,
957
+ options
958
+ });
959
+ return this;
960
+ }
870
961
  async get() {
871
962
  const rows = await this.repository.findAll(this.buildOptions());
872
963
  return await this.attach(rows);
@@ -927,6 +1018,33 @@ class RepositoryQuery {
927
1018
  }));
928
1019
  continue;
929
1020
  }
1021
+ if (load.kind === "morphMany") {
1022
+ const relation2 = load.relation;
1023
+ const grouped2 = await load.repository.withConnection(this.repository.getConnection()).loadMorphManyForParents(rows, relation2, load.options);
1024
+ result = result.map((row) => ({
1025
+ ...row,
1026
+ [load.as]: grouped2.get(row[relation2.localKey]) ?? []
1027
+ }));
1028
+ continue;
1029
+ }
1030
+ if (load.kind === "morphOne") {
1031
+ const relation2 = load.relation;
1032
+ const grouped2 = await load.repository.withConnection(this.repository.getConnection()).loadMorphOneForParents(rows, relation2, load.options);
1033
+ result = result.map((row) => ({
1034
+ ...row,
1035
+ [load.as]: grouped2.get(row[relation2.localKey])
1036
+ }));
1037
+ continue;
1038
+ }
1039
+ if (load.kind === "morphTo") {
1040
+ const relation2 = load.relation;
1041
+ const grouped2 = await this.repository.loadMorphToForChildren(rows, relation2, load.morphRepositories ?? new Map, load.options);
1042
+ result = result.map((row) => ({
1043
+ ...row,
1044
+ [load.as]: grouped2.get(row[relation2.morphIdKey])
1045
+ }));
1046
+ continue;
1047
+ }
930
1048
  const relation = load.relation;
931
1049
  const grouped = await this.repository.loadBelongsToForParents(rows, relation, load.repository, load.options);
932
1050
  result = result.map((row) => ({
@@ -1203,6 +1321,56 @@ class BaseRepository {
1203
1321
  }, options);
1204
1322
  return indexBelongsToRelation(children, parents, relation);
1205
1323
  }
1324
+ async loadMorphManyForParents(parents, relation, options = {}) {
1325
+ if (parents.length === 0) {
1326
+ return indexMorphManyRelation(parents, [], relation);
1327
+ }
1328
+ const parentIds = [...new Set(parents.map((parent) => parent[relation.localKey]))];
1329
+ const children = await this.findWhere({
1330
+ [relation.morphTypeKey]: relation.morphType,
1331
+ [relation.morphIdKey]: parentIds
1332
+ }, options);
1333
+ return indexMorphManyRelation(parents, children, relation);
1334
+ }
1335
+ async loadMorphOneForParents(parents, relation, options = {}) {
1336
+ const grouped = await this.loadMorphManyForParents(parents, relation, options);
1337
+ const result = new Map;
1338
+ for (const parent of parents) {
1339
+ const matches = grouped.get(parent[relation.localKey]) ?? [];
1340
+ result.set(parent[relation.localKey], matches[0]);
1341
+ }
1342
+ return result;
1343
+ }
1344
+ async loadMorphToForChildren(children, relation, repositoriesByType, options = {}) {
1345
+ if (children.length === 0) {
1346
+ return new Map;
1347
+ }
1348
+ const idsByType = new Map;
1349
+ for (const child of children) {
1350
+ const morphType = String(child[relation.morphTypeKey]);
1351
+ const morphId = child[relation.morphIdKey];
1352
+ const ids = idsByType.get(morphType) ?? new Set;
1353
+ ids.add(morphId);
1354
+ idsByType.set(morphType, ids);
1355
+ }
1356
+ const parentsByType = new Map;
1357
+ for (const [morphType, ids] of idsByType) {
1358
+ const repository = repositoriesByType.get(morphType);
1359
+ if (!repository) {
1360
+ continue;
1361
+ }
1362
+ const ownerKey = repository.getTable().primaryKey;
1363
+ const parents = await repository.withConnection(this.connection).findWhere({
1364
+ [ownerKey]: [...ids]
1365
+ }, options);
1366
+ const indexed = new Map;
1367
+ for (const parent of parents) {
1368
+ indexed.set(parent[ownerKey], parent);
1369
+ }
1370
+ parentsByType.set(morphType, indexed);
1371
+ }
1372
+ return indexMorphToRelation(children, parentsByType, relation);
1373
+ }
1206
1374
  }
1207
1375
  var baseRepository_default = BaseRepository;
1208
1376
  // ../../src/core/database/connection.ts
@@ -2176,8 +2344,14 @@ export {
2176
2344
  quoteIdentifier,
2177
2345
  qualifyColumn,
2178
2346
  parseQualifiedColumn,
2347
+ morphTo,
2348
+ morphOne,
2349
+ morphMany,
2179
2350
  mapDatabaseError,
2180
2351
  inferReferencedTable,
2352
+ indexMorphToRelation,
2353
+ indexMorphOneRelation,
2354
+ indexMorphManyRelation,
2181
2355
  indexHasOneRelation,
2182
2356
  indexHasManyRelation,
2183
2357
  indexBelongsToRelation,