@getstrata/core 0.5.97 → 0.5.99

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,18 +1,164 @@
1
1
  // @bun
2
+ // ../../src/core/database/inflection.ts
3
+ function singularize(word) {
4
+ if (word.endsWith("ies") && word.length > 3) {
5
+ return `${word.slice(0, -3)}y`;
6
+ }
7
+ if (/(ses|xes|zes|ches|shes)$/i.test(word)) {
8
+ return word.slice(0, -2);
9
+ }
10
+ if (word.endsWith("s") && !word.endsWith("ss")) {
11
+ return word.slice(0, -1);
12
+ }
13
+ return word;
14
+ }
15
+ function foreignKeyFromTable(tableName) {
16
+ return `${singularize(tableName)}_id`;
17
+ }
18
+ function pivotTableName(leftTable, rightTable) {
19
+ return [singularize(leftTable), singularize(rightTable)].sort().join("_");
20
+ }
21
+
2
22
  // ../../src/core/database/factory.ts
23
+ function inferFactoryForeignKey(parent, explicit) {
24
+ if (explicit) {
25
+ if (explicit.endsWith("_id")) {
26
+ return explicit;
27
+ }
28
+ return `${explicit}_id`;
29
+ }
30
+ if (typeof parent.getRepository === "function") {
31
+ return foreignKeyFromTable(parent.getRepository().getTable().name);
32
+ }
33
+ throw new Error("Factory.for() requires a foreign key or a parent Model.");
34
+ }
35
+
3
36
  class Factory {
4
- constructor() {}
37
+ quantity = 1;
38
+ counted = false;
39
+ sequenceIndex = 0;
40
+ stateTransforms = [];
41
+ sequenceItems = [];
42
+ parentAssociations = [];
43
+ children = [];
44
+ afterMakingCallbacks = [];
45
+ afterCreatingCallbacks = [];
46
+ model;
5
47
  definition() {
6
48
  throw new Error("Factory definition must be implemented by subclass.");
7
49
  }
50
+ clone() {
51
+ const next = Object.create(Object.getPrototypeOf(this));
52
+ Object.assign(next, this);
53
+ next.stateTransforms = [...this.stateTransforms];
54
+ next.sequenceItems = [...this.sequenceItems];
55
+ next.parentAssociations = [...this.parentAssociations];
56
+ next.children = [...this.children];
57
+ next.afterMakingCallbacks = [...this.afterMakingCallbacks];
58
+ next.afterCreatingCallbacks = [...this.afterCreatingCallbacks];
59
+ return next;
60
+ }
61
+ count(quantity) {
62
+ if (!Number.isInteger(quantity) || quantity < 1) {
63
+ throw new Error("Factory.count() requires a positive integer.");
64
+ }
65
+ const next = this.clone();
66
+ next.quantity = quantity;
67
+ next.counted = true;
68
+ return next;
69
+ }
70
+ state(state) {
71
+ const next = this.clone();
72
+ next.stateTransforms = [...this.stateTransforms, state];
73
+ return next;
74
+ }
75
+ sequence(...items) {
76
+ if (items.length === 0) {
77
+ throw new Error("Factory.sequence() requires at least one attribute set.");
78
+ }
79
+ const next = this.clone();
80
+ next.sequenceItems = [...this.sequenceItems, ...items];
81
+ return next;
82
+ }
83
+ for(parent, foreignKey) {
84
+ if (parent.id === undefined || parent.id === null) {
85
+ throw new Error("Factory.for() requires a parent with an id.");
86
+ }
87
+ const key = inferFactoryForeignKey(parent, foreignKey);
88
+ const next = this.clone();
89
+ next.parentAssociations = [...this.parentAssociations, { foreignKey: key, value: parent.id }];
90
+ return next;
91
+ }
92
+ recycle(parent, foreignKey) {
93
+ return this.for(parent, foreignKey);
94
+ }
95
+ afterMaking(callback) {
96
+ const next = this.clone();
97
+ next.afterMakingCallbacks = [...this.afterMakingCallbacks, callback];
98
+ return next;
99
+ }
100
+ afterCreating(callback) {
101
+ const next = this.clone();
102
+ next.afterCreatingCallbacks = [...this.afterCreatingCallbacks, callback];
103
+ return next;
104
+ }
105
+ has(factory, foreignKey) {
106
+ const next = this.clone();
107
+ next.children = [
108
+ ...this.children,
109
+ { factory, foreignKey }
110
+ ];
111
+ return next;
112
+ }
8
113
  make(overrides = {}) {
9
- return {
10
- ...this.definition(),
114
+ if (!this.counted) {
115
+ return this.makeOne(overrides);
116
+ }
117
+ return Array.from({ length: this.quantity }, () => this.makeOne(overrides));
118
+ }
119
+ async create(overrides = {}) {
120
+ if (!this.counted) {
121
+ return await this.createOne(overrides);
122
+ }
123
+ const records = [];
124
+ for (let index = 0;index < this.quantity; index += 1) {
125
+ records.push(await this.createOne(overrides));
126
+ }
127
+ return records;
128
+ }
129
+ makeOne(overrides = {}) {
130
+ let record = { ...this.definition() };
131
+ for (const state of this.stateTransforms) {
132
+ const patch = typeof state === "function" ? state(record) : state;
133
+ record = { ...record, ...patch };
134
+ }
135
+ if (this.sequenceItems.length > 0) {
136
+ const item = this.sequenceItems[this.sequenceIndex % this.sequenceItems.length];
137
+ const patch = typeof item === "function" ? item(this.sequenceIndex) : item;
138
+ record = { ...record, ...patch };
139
+ this.sequenceIndex += 1;
140
+ }
141
+ for (const association of this.parentAssociations) {
142
+ record[association.foreignKey] = association.value;
143
+ }
144
+ const made = {
145
+ ...record,
11
146
  ...overrides
12
147
  };
148
+ for (const callback of this.afterMakingCallbacks) {
149
+ callback(made);
150
+ }
151
+ return made;
13
152
  }
14
- async create(overrides = {}) {
15
- return this.persist(this.insertable(this.make(overrides)));
153
+ async createOne(overrides = {}) {
154
+ const created = await this.persist(this.insertable(this.makeOne(overrides)));
155
+ for (const child of this.children) {
156
+ await child.factory.for(created, child.foreignKey).create();
157
+ }
158
+ for (const callback of this.afterCreatingCallbacks) {
159
+ await callback(created);
160
+ }
161
+ return created;
16
162
  }
17
163
  insertable(record) {
18
164
  const values = { ...record };
@@ -21,7 +167,14 @@ class Factory {
21
167
  }
22
168
  return values;
23
169
  }
24
- persist(_values) {
170
+ async persist(values) {
171
+ if (this.model) {
172
+ const created = await this.model.create(values);
173
+ if (created && typeof created.toObject === "function") {
174
+ return created.toObject();
175
+ }
176
+ return created;
177
+ }
25
178
  throw new Error("Factory.persist() must be implemented to use create().");
26
179
  }
27
180
  }