@meridianjs/framework-utils 0.1.0 → 0.1.2
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.
- package/dist/index.d.mts +0 -6
- package/dist/index.d.ts +0 -6
- package/dist/index.js +84 -41
- package/dist/index.mjs +84 -41
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -156,12 +156,6 @@ type InferModel<M extends ModelDefinition> = M extends ModelDefinition<infer Sch
|
|
|
156
156
|
*/
|
|
157
157
|
declare function MeridianService(models: Record<string, ModelDefinition>): new (container: MeridianContainer) => IModuleService;
|
|
158
158
|
|
|
159
|
-
/**
|
|
160
|
-
* Converts a DML ModelDefinition to a MikroORM EntitySchema.
|
|
161
|
-
*
|
|
162
|
-
* Automatically adds `created_at`, `updated_at`, and `deleted_at` timestamp
|
|
163
|
-
* columns to every entity.
|
|
164
|
-
*/
|
|
165
159
|
declare function dmlToEntitySchema(def: ModelDefinition): EntitySchema;
|
|
166
160
|
/**
|
|
167
161
|
* Wraps a MikroORM EntityManager into the Repository interface expected
|
package/dist/index.d.ts
CHANGED
|
@@ -156,12 +156,6 @@ type InferModel<M extends ModelDefinition> = M extends ModelDefinition<infer Sch
|
|
|
156
156
|
*/
|
|
157
157
|
declare function MeridianService(models: Record<string, ModelDefinition>): new (container: MeridianContainer) => IModuleService;
|
|
158
158
|
|
|
159
|
-
/**
|
|
160
|
-
* Converts a DML ModelDefinition to a MikroORM EntitySchema.
|
|
161
|
-
*
|
|
162
|
-
* Automatically adds `created_at`, `updated_at`, and `deleted_at` timestamp
|
|
163
|
-
* columns to every entity.
|
|
164
|
-
*/
|
|
165
159
|
declare function dmlToEntitySchema(def: ModelDefinition): EntitySchema;
|
|
166
160
|
/**
|
|
167
161
|
* Wraps a MikroORM EntityManager into the Repository interface expected
|
package/dist/index.js
CHANGED
|
@@ -55,10 +55,10 @@ function Module(key, definition) {
|
|
|
55
55
|
|
|
56
56
|
// src/define-link.ts
|
|
57
57
|
function normalizeEndpoint(input) {
|
|
58
|
-
if ("
|
|
59
|
-
return input;
|
|
58
|
+
if ("tableName" in input) {
|
|
59
|
+
return { linkable: input };
|
|
60
60
|
}
|
|
61
|
-
return
|
|
61
|
+
return input;
|
|
62
62
|
}
|
|
63
63
|
function defineLink(left, right, options) {
|
|
64
64
|
const leftEndpoint = normalizeEndpoint(left);
|
|
@@ -184,54 +184,88 @@ var model = {
|
|
|
184
184
|
};
|
|
185
185
|
|
|
186
186
|
// src/service-factory.ts
|
|
187
|
+
var UPDATE_RESERVED = /* @__PURE__ */ new Set([
|
|
188
|
+
"id",
|
|
189
|
+
"created_at",
|
|
190
|
+
"updated_at",
|
|
191
|
+
"deleted_at",
|
|
192
|
+
"__proto__",
|
|
193
|
+
"constructor",
|
|
194
|
+
"prototype"
|
|
195
|
+
]);
|
|
187
196
|
function MeridianService(models) {
|
|
188
197
|
class BaseService {
|
|
189
198
|
// Use private class field to avoid conflicting with the index signature
|
|
190
199
|
#container;
|
|
191
200
|
constructor(container) {
|
|
192
201
|
this.#container = container;
|
|
202
|
+
const hasCustomMethod = (name) => typeof this[name] === "function";
|
|
193
203
|
for (const [modelName, _modelDef] of Object.entries(models)) {
|
|
194
204
|
const pluralName = `${modelName}s`;
|
|
195
205
|
const repoToken = `${modelName.charAt(0).toLowerCase()}${modelName.slice(1)}Repository`;
|
|
196
206
|
const capitalized = `${modelName.charAt(0).toUpperCase()}${modelName.slice(1)}`;
|
|
197
207
|
const capitalizedPlural = `${pluralName.charAt(0).toUpperCase()}${pluralName.slice(1)}`;
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
208
|
+
const listMethod = `list${capitalizedPlural}`;
|
|
209
|
+
if (!hasCustomMethod(listMethod)) {
|
|
210
|
+
this[listMethod] = async (filters = {}, options = {}) => {
|
|
211
|
+
const repo = this.#container.resolve(repoToken);
|
|
212
|
+
return repo.find({ deleted_at: null, ...filters }, options);
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
const listAndCountMethod = `listAndCount${capitalizedPlural}`;
|
|
216
|
+
if (!hasCustomMethod(listAndCountMethod)) {
|
|
217
|
+
this[listAndCountMethod] = async (filters = {}, options = {}) => {
|
|
218
|
+
const repo = this.#container.resolve(repoToken);
|
|
219
|
+
return repo.findAndCount({ deleted_at: null, ...filters }, options);
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
const retrieveMethod = `retrieve${capitalized}`;
|
|
223
|
+
if (!hasCustomMethod(retrieveMethod)) {
|
|
224
|
+
this[retrieveMethod] = async (id) => {
|
|
225
|
+
const repo = this.#container.resolve(repoToken);
|
|
226
|
+
return repo.findOneOrFail({ id, deleted_at: null });
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
const createMethod = `create${capitalized}`;
|
|
230
|
+
if (!hasCustomMethod(createMethod)) {
|
|
231
|
+
this[createMethod] = async (data) => {
|
|
232
|
+
const repo = this.#container.resolve(repoToken);
|
|
233
|
+
const entity = repo.create(data);
|
|
234
|
+
await repo.persistAndFlush(entity);
|
|
235
|
+
return entity;
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
const updateMethod = `update${capitalized}`;
|
|
239
|
+
if (!hasCustomMethod(updateMethod)) {
|
|
240
|
+
this[updateMethod] = async (id, data) => {
|
|
241
|
+
const repo = this.#container.resolve(repoToken);
|
|
242
|
+
const entity = await repo.findOneOrFail({ id, deleted_at: null });
|
|
243
|
+
const safe = Object.fromEntries(
|
|
244
|
+
Object.entries(data).filter(([k]) => !UPDATE_RESERVED.has(k))
|
|
245
|
+
);
|
|
246
|
+
Object.assign(entity, safe);
|
|
247
|
+
await repo.flush();
|
|
248
|
+
return entity;
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
const deleteMethod = `delete${capitalized}`;
|
|
252
|
+
if (!hasCustomMethod(deleteMethod)) {
|
|
253
|
+
this[deleteMethod] = async (id) => {
|
|
254
|
+
const repo = this.#container.resolve(repoToken);
|
|
255
|
+
const entity = await repo.findOneOrFail({ id });
|
|
256
|
+
await repo.removeAndFlush(entity);
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
const softDeleteMethod = `softDelete${capitalized}`;
|
|
260
|
+
if (!hasCustomMethod(softDeleteMethod)) {
|
|
261
|
+
this[softDeleteMethod] = async (id) => {
|
|
262
|
+
const repo = this.#container.resolve(repoToken);
|
|
263
|
+
const entity = await repo.findOneOrFail({ id, deleted_at: null });
|
|
264
|
+
entity.deleted_at = /* @__PURE__ */ new Date();
|
|
265
|
+
await repo.flush();
|
|
266
|
+
return entity;
|
|
267
|
+
};
|
|
268
|
+
}
|
|
235
269
|
}
|
|
236
270
|
}
|
|
237
271
|
}
|
|
@@ -240,7 +274,15 @@ function MeridianService(models) {
|
|
|
240
274
|
|
|
241
275
|
// src/orm-utils.ts
|
|
242
276
|
var import_core = require("@mikro-orm/core");
|
|
277
|
+
var RESERVED_TIMESTAMP_KEYS = ["created_at", "updated_at", "deleted_at"];
|
|
243
278
|
function dmlToEntitySchema(def) {
|
|
279
|
+
for (const key of RESERVED_TIMESTAMP_KEYS) {
|
|
280
|
+
if (key in def.schema) {
|
|
281
|
+
throw new Error(
|
|
282
|
+
`Model "${def.tableName}" defines reserved column "${key}". Meridian automatically manages created_at, updated_at, and deleted_at.`
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
244
286
|
const properties = {};
|
|
245
287
|
for (const [key, prop] of Object.entries(def.schema)) {
|
|
246
288
|
if (prop instanceof IdProperty) {
|
|
@@ -322,9 +364,10 @@ function createRepository(em, entityName) {
|
|
|
322
364
|
return repo.find(filters, options);
|
|
323
365
|
},
|
|
324
366
|
async findAndCount(filters, options = {}) {
|
|
367
|
+
const { limit, offset, ...countOptions } = options;
|
|
325
368
|
const [data, count] = await Promise.all([
|
|
326
369
|
repo.find(filters, options),
|
|
327
|
-
repo.count(filters)
|
|
370
|
+
repo.count(filters, countOptions)
|
|
328
371
|
]);
|
|
329
372
|
return [data, count];
|
|
330
373
|
},
|
package/dist/index.mjs
CHANGED
|
@@ -5,10 +5,10 @@ function Module(key, definition) {
|
|
|
5
5
|
|
|
6
6
|
// src/define-link.ts
|
|
7
7
|
function normalizeEndpoint(input) {
|
|
8
|
-
if ("
|
|
9
|
-
return input;
|
|
8
|
+
if ("tableName" in input) {
|
|
9
|
+
return { linkable: input };
|
|
10
10
|
}
|
|
11
|
-
return
|
|
11
|
+
return input;
|
|
12
12
|
}
|
|
13
13
|
function defineLink(left, right, options) {
|
|
14
14
|
const leftEndpoint = normalizeEndpoint(left);
|
|
@@ -134,54 +134,88 @@ var model = {
|
|
|
134
134
|
};
|
|
135
135
|
|
|
136
136
|
// src/service-factory.ts
|
|
137
|
+
var UPDATE_RESERVED = /* @__PURE__ */ new Set([
|
|
138
|
+
"id",
|
|
139
|
+
"created_at",
|
|
140
|
+
"updated_at",
|
|
141
|
+
"deleted_at",
|
|
142
|
+
"__proto__",
|
|
143
|
+
"constructor",
|
|
144
|
+
"prototype"
|
|
145
|
+
]);
|
|
137
146
|
function MeridianService(models) {
|
|
138
147
|
class BaseService {
|
|
139
148
|
// Use private class field to avoid conflicting with the index signature
|
|
140
149
|
#container;
|
|
141
150
|
constructor(container) {
|
|
142
151
|
this.#container = container;
|
|
152
|
+
const hasCustomMethod = (name) => typeof this[name] === "function";
|
|
143
153
|
for (const [modelName, _modelDef] of Object.entries(models)) {
|
|
144
154
|
const pluralName = `${modelName}s`;
|
|
145
155
|
const repoToken = `${modelName.charAt(0).toLowerCase()}${modelName.slice(1)}Repository`;
|
|
146
156
|
const capitalized = `${modelName.charAt(0).toUpperCase()}${modelName.slice(1)}`;
|
|
147
157
|
const capitalizedPlural = `${pluralName.charAt(0).toUpperCase()}${pluralName.slice(1)}`;
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
158
|
+
const listMethod = `list${capitalizedPlural}`;
|
|
159
|
+
if (!hasCustomMethod(listMethod)) {
|
|
160
|
+
this[listMethod] = async (filters = {}, options = {}) => {
|
|
161
|
+
const repo = this.#container.resolve(repoToken);
|
|
162
|
+
return repo.find({ deleted_at: null, ...filters }, options);
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
const listAndCountMethod = `listAndCount${capitalizedPlural}`;
|
|
166
|
+
if (!hasCustomMethod(listAndCountMethod)) {
|
|
167
|
+
this[listAndCountMethod] = async (filters = {}, options = {}) => {
|
|
168
|
+
const repo = this.#container.resolve(repoToken);
|
|
169
|
+
return repo.findAndCount({ deleted_at: null, ...filters }, options);
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
const retrieveMethod = `retrieve${capitalized}`;
|
|
173
|
+
if (!hasCustomMethod(retrieveMethod)) {
|
|
174
|
+
this[retrieveMethod] = async (id) => {
|
|
175
|
+
const repo = this.#container.resolve(repoToken);
|
|
176
|
+
return repo.findOneOrFail({ id, deleted_at: null });
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
const createMethod = `create${capitalized}`;
|
|
180
|
+
if (!hasCustomMethod(createMethod)) {
|
|
181
|
+
this[createMethod] = async (data) => {
|
|
182
|
+
const repo = this.#container.resolve(repoToken);
|
|
183
|
+
const entity = repo.create(data);
|
|
184
|
+
await repo.persistAndFlush(entity);
|
|
185
|
+
return entity;
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const updateMethod = `update${capitalized}`;
|
|
189
|
+
if (!hasCustomMethod(updateMethod)) {
|
|
190
|
+
this[updateMethod] = async (id, data) => {
|
|
191
|
+
const repo = this.#container.resolve(repoToken);
|
|
192
|
+
const entity = await repo.findOneOrFail({ id, deleted_at: null });
|
|
193
|
+
const safe = Object.fromEntries(
|
|
194
|
+
Object.entries(data).filter(([k]) => !UPDATE_RESERVED.has(k))
|
|
195
|
+
);
|
|
196
|
+
Object.assign(entity, safe);
|
|
197
|
+
await repo.flush();
|
|
198
|
+
return entity;
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
const deleteMethod = `delete${capitalized}`;
|
|
202
|
+
if (!hasCustomMethod(deleteMethod)) {
|
|
203
|
+
this[deleteMethod] = async (id) => {
|
|
204
|
+
const repo = this.#container.resolve(repoToken);
|
|
205
|
+
const entity = await repo.findOneOrFail({ id });
|
|
206
|
+
await repo.removeAndFlush(entity);
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
const softDeleteMethod = `softDelete${capitalized}`;
|
|
210
|
+
if (!hasCustomMethod(softDeleteMethod)) {
|
|
211
|
+
this[softDeleteMethod] = async (id) => {
|
|
212
|
+
const repo = this.#container.resolve(repoToken);
|
|
213
|
+
const entity = await repo.findOneOrFail({ id, deleted_at: null });
|
|
214
|
+
entity.deleted_at = /* @__PURE__ */ new Date();
|
|
215
|
+
await repo.flush();
|
|
216
|
+
return entity;
|
|
217
|
+
};
|
|
218
|
+
}
|
|
185
219
|
}
|
|
186
220
|
}
|
|
187
221
|
}
|
|
@@ -190,7 +224,15 @@ function MeridianService(models) {
|
|
|
190
224
|
|
|
191
225
|
// src/orm-utils.ts
|
|
192
226
|
import { EntitySchema } from "@mikro-orm/core";
|
|
227
|
+
var RESERVED_TIMESTAMP_KEYS = ["created_at", "updated_at", "deleted_at"];
|
|
193
228
|
function dmlToEntitySchema(def) {
|
|
229
|
+
for (const key of RESERVED_TIMESTAMP_KEYS) {
|
|
230
|
+
if (key in def.schema) {
|
|
231
|
+
throw new Error(
|
|
232
|
+
`Model "${def.tableName}" defines reserved column "${key}". Meridian automatically manages created_at, updated_at, and deleted_at.`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
194
236
|
const properties = {};
|
|
195
237
|
for (const [key, prop] of Object.entries(def.schema)) {
|
|
196
238
|
if (prop instanceof IdProperty) {
|
|
@@ -272,9 +314,10 @@ function createRepository(em, entityName) {
|
|
|
272
314
|
return repo.find(filters, options);
|
|
273
315
|
},
|
|
274
316
|
async findAndCount(filters, options = {}) {
|
|
317
|
+
const { limit, offset, ...countOptions } = options;
|
|
275
318
|
const [data, count] = await Promise.all([
|
|
276
319
|
repo.find(filters, options),
|
|
277
|
-
repo.count(filters)
|
|
320
|
+
repo.count(filters, countOptions)
|
|
278
321
|
]);
|
|
279
322
|
return [data, count];
|
|
280
323
|
},
|
package/package.json
CHANGED