omni-rest 0.3.3 → 0.4.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.mjs CHANGED
@@ -77,6 +77,19 @@ function buildModelMap(models, allowList) {
77
77
  const filtered = allowList ? models.filter((m) => allowList.includes(m.routeName)) : models;
78
78
  return Object.fromEntries(filtered.map((m) => [m.routeName, m]));
79
79
  }
80
+ function detectSoftDeleteField(fields, explicitField) {
81
+ if (explicitField) {
82
+ const f = fields.find((f2) => f2.name === explicitField);
83
+ if (!f) return null;
84
+ const value = f.type === "Boolean" ? false : /* @__PURE__ */ new Date();
85
+ return { field: explicitField, value };
86
+ }
87
+ const deletedAt = fields.find((f) => f.name === "deletedAt" && f.type === "DateTime");
88
+ if (deletedAt) return { field: "deletedAt", value: /* @__PURE__ */ new Date() };
89
+ const isActive = fields.find((f) => f.name === "isActive" && f.type === "Boolean");
90
+ if (isActive) return { field: "isActive", value: false };
91
+ return null;
92
+ }
80
93
  function getDelegate(prisma, meta) {
81
94
  const key = meta.name.charAt(0).toLowerCase() + meta.name.slice(1);
82
95
  const delegate = prisma[key];
@@ -108,9 +121,11 @@ var RESERVED_KEYS = /* @__PURE__ */ new Set([
108
121
  "limit",
109
122
  "sort",
110
123
  "include",
111
- "select"
124
+ "select",
125
+ "fields",
126
+ "search"
112
127
  ]);
113
- function buildQuery(searchParams, defaultLimit = 20, maxLimit = 100) {
128
+ function buildQuery(searchParams, defaultLimit = 20, maxLimit = 100, modelFields) {
114
129
  const where = {};
115
130
  const orderBy = {};
116
131
  let include = {};
@@ -134,13 +149,25 @@ function buildQuery(searchParams, defaultLimit = 20, maxLimit = 100) {
134
149
  if (rel.trim()) include[rel.trim()] = true;
135
150
  }
136
151
  }
137
- const selectParam = searchParams.get("select");
152
+ const selectParam = searchParams.get("select") ?? searchParams.get("fields");
138
153
  if (selectParam) {
139
154
  select = {};
140
155
  for (const field of selectParam.split(",")) {
141
156
  if (field.trim()) select[field.trim()] = true;
142
157
  }
143
158
  }
159
+ const searchValue = searchParams.get("search");
160
+ if (searchValue && modelFields) {
161
+ const stringFields = modelFields.filter(
162
+ (f) => f.type === "String" && !f.isRelation
163
+ );
164
+ if (stringFields.length > 0) {
165
+ const orClauses = stringFields.map((f) => ({
166
+ [f.name]: { contains: searchValue, mode: "insensitive" }
167
+ }));
168
+ where["OR"] = orClauses;
169
+ }
170
+ }
144
171
  for (const [key, value] of searchParams.entries()) {
145
172
  if (RESERVED_KEYS.has(key)) continue;
146
173
  let matched = false;
@@ -202,7 +229,9 @@ function createRouter(prisma, options = {}) {
202
229
  beforeOperation,
203
230
  afterOperation,
204
231
  defaultLimit = 20,
205
- maxLimit = 100
232
+ maxLimit = 100,
233
+ softDelete = false,
234
+ softDeleteField
206
235
  } = options;
207
236
  const models = getModels(prisma);
208
237
  const modelMap = buildModelMap(models, allow);
@@ -236,7 +265,9 @@ function createRouter(prisma, options = {}) {
236
265
  searchParams,
237
266
  defaultLimit,
238
267
  maxLimit,
239
- operation
268
+ operation,
269
+ softDelete,
270
+ softDeleteField
240
271
  );
241
272
  } catch (e) {
242
273
  return handlePrismaError(e);
@@ -252,12 +283,13 @@ function createRouter(prisma, options = {}) {
252
283
  }
253
284
  return { handle, modelMap, models };
254
285
  }
255
- async function executeOperation(prisma, meta, method, id, body, searchParams, defaultLimit, maxLimit, operation) {
286
+ async function executeOperation(prisma, meta, method, id, body, searchParams, defaultLimit, maxLimit, operation, softDelete = false, softDeleteField) {
256
287
  const delegate = getDelegate(prisma, meta);
257
288
  const { where, orderBy, skip, take, include, select } = buildQuery(
258
289
  searchParams,
259
290
  defaultLimit,
260
- maxLimit
291
+ maxLimit,
292
+ meta.fields
261
293
  );
262
294
  const includeArg = Object.keys(include).length > 0 ? include : void 0;
263
295
  const selectArg = select && Object.keys(select).length > 0 ? select : void 0;
@@ -320,9 +352,11 @@ async function executeOperation(prisma, meta, method, id, body, searchParams, de
320
352
  };
321
353
  }
322
354
  if (method === "GET" && !id) {
355
+ const softDeleteInfo = softDelete ? detectSoftDeleteField(meta.fields, softDeleteField) : null;
356
+ const listWhere = softDeleteInfo ? { ...where, [softDeleteInfo.field]: softDeleteInfo.field === "isActive" ? true : null } : where;
323
357
  const [data, total] = await prisma.$transaction([
324
- delegate.findMany({ where, orderBy, skip, take, ...projection }),
325
- delegate.count({ where })
358
+ delegate.findMany({ where: listWhere, orderBy, skip, take, ...projection }),
359
+ delegate.count({ where: listWhere })
326
360
  ]);
327
361
  return {
328
362
  status: 200,
@@ -359,6 +393,14 @@ async function executeOperation(prisma, meta, method, id, body, searchParams, de
359
393
  return { status: 200, data: record };
360
394
  }
361
395
  if (method === "DELETE" && id) {
396
+ const softDeleteInfo = softDelete ? detectSoftDeleteField(meta.fields, softDeleteField) : null;
397
+ if (softDeleteInfo) {
398
+ const record = await delegate.update({
399
+ where: { [meta.idField]: coerceId(id) },
400
+ data: { [softDeleteInfo.field]: softDeleteInfo.value }
401
+ });
402
+ return { status: 200, data: record };
403
+ }
362
404
  await delegate.delete({
363
405
  where: { [meta.idField]: coerceId(id) }
364
406
  });
@@ -862,6 +904,68 @@ function buildListParameters() {
862
904
  ];
863
905
  }
864
906
 
907
+ // src/config-generator.ts
908
+ function generateConfig(prisma) {
909
+ const models = getModels(prisma);
910
+ const PRISMA_TO_ZOD2 = {
911
+ String: "z.string()",
912
+ Int: "z.number().int()",
913
+ Float: "z.number()",
914
+ Decimal: "z.number()",
915
+ Boolean: "z.boolean()",
916
+ DateTime: "z.coerce.date()",
917
+ Json: "z.any()",
918
+ BigInt: "z.bigint()",
919
+ Bytes: "z.any()"
920
+ };
921
+ function fieldToZod2(field) {
922
+ if (field.isRelation) return null;
923
+ let zod = PRISMA_TO_ZOD2[field.type] ?? "z.any()";
924
+ if (!field.isRequired) zod = `${zod}.optional()`;
925
+ if (field.isList) zod = `z.array(${zod})`;
926
+ return zod;
927
+ }
928
+ const schemaBlocks = models.map((meta) => {
929
+ const createFields = meta.fields.filter((f) => !f.isRelation && !f.isId && !f.hasDefaultValue && !f.isUpdatedAt).map((f) => {
930
+ const z = fieldToZod2(f);
931
+ return z ? ` ${f.name}: ${z},` : null;
932
+ }).filter(Boolean).join("\n");
933
+ const updateFields = meta.fields.filter((f) => !f.isRelation && !f.isId && !f.isUpdatedAt).map((f) => {
934
+ const z = fieldToZod2(f);
935
+ if (!z) return null;
936
+ const opt = z.includes(".optional()") ? z : `${z}.optional()`;
937
+ return ` ${f.name}: ${opt},`;
938
+ }).filter(Boolean).join("\n");
939
+ return `
940
+ // \u2500\u2500\u2500 ${meta.name} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
941
+
942
+ export const ${meta.name}CreateSchema = z.object({
943
+ ${createFields}
944
+ });
945
+
946
+ export const ${meta.name}UpdateSchema = z.object({
947
+ ${updateFields}
948
+ });
949
+
950
+ export type ${meta.name}Create = z.infer<typeof ${meta.name}CreateSchema>;
951
+ export type ${meta.name}Update = z.infer<typeof ${meta.name}UpdateSchema>;`.trim();
952
+ });
953
+ const zodSchemas = `/**
954
+ * Auto-generated Zod schemas from Prisma schema.
955
+ * Generated by omni-rest \u2014 do not edit manually.
956
+ */
957
+ import { z } from "zod";
958
+
959
+ ${schemaBlocks.join("\n\n")}
960
+ `;
961
+ return {
962
+ version: "1",
963
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
964
+ models,
965
+ zodSchemas
966
+ };
967
+ }
968
+
865
969
  // src/adapters/express.ts
866
970
  function expressAdapter(prisma, options = {}) {
867
971
  const { Router } = __require("express");
@@ -1320,6 +1424,6 @@ function nestjsController(prisma, options = {}, prefix = "api") {
1320
1424
  return OmniRestDynamicController;
1321
1425
  }
1322
1426
 
1323
- export { buildModelMap, buildQuery, buildRuntimeSchemas, createRouter, expressAdapter, fastifyAdapter, generateOpenApiSpec, generateZodSchemas, getDelegate, getModels, hapiAdapter, koaAdapter, nestjsController, nextjsAdapter, runGuard, runHook, toRouteName, validateBody, withValidation };
1427
+ export { buildModelMap, buildQuery, buildRuntimeSchemas, createRouter, expressAdapter, fastifyAdapter, generateConfig, generateOpenApiSpec, generateZodSchemas, getDelegate, getModels, hapiAdapter, koaAdapter, nestjsController, nextjsAdapter, runGuard, runHook, toRouteName, validateBody, withValidation };
1324
1428
  //# sourceMappingURL=index.mjs.map
1325
1429
  //# sourceMappingURL=index.mjs.map