@farming-labs/orm 0.0.9 → 0.0.11

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.cjs CHANGED
@@ -28,16 +28,25 @@ __export(index_exports, {
28
28
  createOrm: () => createOrm,
29
29
  datetime: () => datetime,
30
30
  defineSchema: () => defineSchema,
31
+ equalValues: () => equalValues,
31
32
  hasMany: () => hasMany,
32
33
  hasOne: () => hasOne,
33
34
  id: () => id,
35
+ integer: () => integer,
36
+ isOperatorFilterObject: () => isOperatorFilterObject,
37
+ json: () => json,
34
38
  manyToMany: () => manyToMany,
39
+ mergeUniqueLookupCreateData: () => mergeUniqueLookupCreateData,
35
40
  model: () => model,
36
41
  renderDrizzleSchema: () => renderDrizzleSchema,
37
42
  renderPrismaSchema: () => renderPrismaSchema,
38
43
  renderSafeSql: () => renderSafeSql,
39
44
  replaceGeneratedBlock: () => replaceGeneratedBlock,
40
- string: () => string
45
+ requireUniqueLookup: () => requireUniqueLookup,
46
+ resolveRowIdentityLookup: () => resolveRowIdentityLookup,
47
+ string: () => string,
48
+ toUniqueLookupWhere: () => toUniqueLookupWhere,
49
+ validateUniqueLookupUpdateData: () => validateUniqueLookupUpdateData
41
50
  });
42
51
  module.exports = __toCommonJS(index_exports);
43
52
 
@@ -113,6 +122,9 @@ var FieldBuilder = class {
113
122
  this.config = config;
114
123
  }
115
124
  _tag = "field";
125
+ __kind;
126
+ __nullable;
127
+ __value;
116
128
  unique() {
117
129
  return cloneField({
118
130
  ...this.config,
@@ -185,8 +197,189 @@ function datetime() {
185
197
  unique: false
186
198
  });
187
199
  }
200
+ function integer() {
201
+ return new FieldBuilder({
202
+ kind: "integer",
203
+ nullable: false,
204
+ unique: false
205
+ });
206
+ }
207
+ function json() {
208
+ return new FieldBuilder({
209
+ kind: "json",
210
+ nullable: false,
211
+ unique: false
212
+ });
213
+ }
188
214
 
189
215
  // src/manifest.ts
216
+ var import_node_util = require("util");
217
+ var filterOperatorKeys = /* @__PURE__ */ new Set(["eq", "contains", "in", "not", "gt", "gte", "lt", "lte"]);
218
+ function isFilterObject(value) {
219
+ return !!value && typeof value === "object" && !(value instanceof Date) && !Array.isArray(value);
220
+ }
221
+ function isOperatorFilterObject(value) {
222
+ if (!isFilterObject(value)) {
223
+ return false;
224
+ }
225
+ const keys = Object.keys(value);
226
+ return keys.length > 0 && keys.every((key) => filterOperatorKeys.has(key));
227
+ }
228
+ function equalValues(left, right) {
229
+ return (0, import_node_util.isDeepStrictEqual)(left, right);
230
+ }
231
+ function extractEqualityValue(filter) {
232
+ if (!isOperatorFilterObject(filter)) {
233
+ return {
234
+ supported: true,
235
+ value: filter
236
+ };
237
+ }
238
+ const keys = Object.keys(filter);
239
+ if (keys.length === 1 && "eq" in filter) {
240
+ return {
241
+ supported: true,
242
+ value: filter.eq
243
+ };
244
+ }
245
+ return {
246
+ supported: false,
247
+ value: void 0
248
+ };
249
+ }
250
+ function requireEqualityValues(model2, where, operation) {
251
+ const keys = Object.keys(where).filter((key) => key !== "AND" && key !== "OR" && key !== "NOT");
252
+ if ("AND" in where || "OR" in where || "NOT" in where || keys.length === 0) {
253
+ throw new Error(
254
+ `${operation} on model "${model2.name}" requires a unique equality filter in "where".`
255
+ );
256
+ }
257
+ const values = {};
258
+ for (const fieldName of keys) {
259
+ const field = model2.fields[fieldName];
260
+ if (!field) {
261
+ throw new Error(`Unknown field "${fieldName}" on model "${model2.name}".`);
262
+ }
263
+ const { supported, value } = extractEqualityValue(where[fieldName]);
264
+ if (!supported || value === void 0 || value === null) {
265
+ throw new Error(
266
+ `${operation} on model "${model2.name}" requires the "where" field "${fieldName}" to use a single non-null equality value.`
267
+ );
268
+ }
269
+ values[fieldName] = value;
270
+ }
271
+ return values;
272
+ }
273
+ function sameFieldSet(left, right) {
274
+ return left.length === right.length && left.every((fieldName) => right.includes(fieldName));
275
+ }
276
+ function requireUniqueLookup(model2, where, operation) {
277
+ const values = requireEqualityValues(model2, where, operation);
278
+ const keys = Object.keys(values);
279
+ if (keys.length === 1) {
280
+ const field = model2.fields[keys[0]];
281
+ if (field.kind === "id") {
282
+ return {
283
+ kind: "id",
284
+ fields: [field],
285
+ values
286
+ };
287
+ }
288
+ if (field.unique) {
289
+ return {
290
+ kind: "field",
291
+ fields: [field],
292
+ values
293
+ };
294
+ }
295
+ }
296
+ const constraint = model2.constraints.unique.find(
297
+ (candidate) => sameFieldSet([...candidate.fields], keys)
298
+ );
299
+ if (!constraint) {
300
+ throw new Error(
301
+ `${operation} on model "${model2.name}" requires the "where" clause to match an id field, unique field, or declared unique constraint using equality values only.`
302
+ );
303
+ }
304
+ return {
305
+ kind: "constraint",
306
+ fields: constraint.fields.map((fieldName) => model2.fields[fieldName]),
307
+ values: Object.fromEntries(
308
+ constraint.fields.map((fieldName) => [fieldName, values[fieldName]])
309
+ ),
310
+ constraint
311
+ };
312
+ }
313
+ function resolveRowIdentityLookup(model2, row) {
314
+ const idField = model2.fields.id;
315
+ if (idField && row[idField.name] !== void 0 && row[idField.name] !== null) {
316
+ return {
317
+ kind: "id",
318
+ fields: [idField],
319
+ values: {
320
+ [idField.name]: row[idField.name]
321
+ }
322
+ };
323
+ }
324
+ const uniqueField = Object.values(model2.fields).find(
325
+ (field) => field.unique && row[field.name] !== void 0 && row[field.name] !== null
326
+ );
327
+ if (uniqueField) {
328
+ return {
329
+ kind: "field",
330
+ fields: [uniqueField],
331
+ values: {
332
+ [uniqueField.name]: row[uniqueField.name]
333
+ }
334
+ };
335
+ }
336
+ for (const constraint of model2.constraints.unique) {
337
+ if (constraint.fields.every(
338
+ (fieldName) => row[fieldName] !== void 0 && row[fieldName] !== null
339
+ )) {
340
+ return {
341
+ kind: "constraint",
342
+ fields: constraint.fields.map((fieldName) => model2.fields[fieldName]),
343
+ values: Object.fromEntries(
344
+ constraint.fields.map((fieldName) => [fieldName, row[fieldName]])
345
+ ),
346
+ constraint
347
+ };
348
+ }
349
+ }
350
+ throw new Error(
351
+ `Model "${model2.name}" requires an "id" field, unique field, or declared unique constraint with non-null values for identity lookups.`
352
+ );
353
+ }
354
+ function toUniqueLookupWhere(lookup) {
355
+ return Object.fromEntries(lookup.fields.map((field) => [field.name, lookup.values[field.name]]));
356
+ }
357
+ function mergeUniqueLookupCreateData(model2, createData, lookup, operation) {
358
+ const output = {
359
+ ...createData
360
+ };
361
+ for (const field of lookup.fields) {
362
+ const currentValue = output[field.name];
363
+ const expectedValue = lookup.values[field.name];
364
+ if (currentValue !== void 0 && !equalValues(currentValue, expectedValue)) {
365
+ throw new Error(
366
+ `${operation} on model "${model2.name}" requires create.${field.name} to match where.${field.name}.`
367
+ );
368
+ }
369
+ output[field.name] = currentValue ?? expectedValue;
370
+ }
371
+ return output;
372
+ }
373
+ function validateUniqueLookupUpdateData(model2, updateData, lookup, operation) {
374
+ for (const field of lookup.fields) {
375
+ const nextValue = updateData[field.name];
376
+ if (nextValue !== void 0 && !equalValues(nextValue, lookup.values[field.name])) {
377
+ throw new Error(
378
+ `${operation} on model "${model2.name}" cannot change the conflict field "${field.name}".`
379
+ );
380
+ }
381
+ }
382
+ }
190
383
  function createConstraintName(table, columns, suffix) {
191
384
  const base = [table, ...columns].join("_").replace(/[^a-zA-Z0-9_]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
192
385
  return `${base}_${suffix}`;
@@ -297,6 +490,10 @@ function prismaType(field) {
297
490
  return "Boolean";
298
491
  case "datetime":
299
492
  return "DateTime";
493
+ case "integer":
494
+ return "Int";
495
+ case "json":
496
+ return "Json";
300
497
  }
301
498
  }
302
499
  function drizzleConstraintProperty(constraint) {
@@ -317,6 +514,12 @@ function drizzleImports(dialect, manifest) {
317
514
  const needsDate = models.some(
318
515
  (model2) => Object.values(model2.fields).some((field) => field.kind === "datetime")
319
516
  );
517
+ const needsInteger = models.some(
518
+ (model2) => Object.values(model2.fields).some((field) => field.kind === "integer")
519
+ );
520
+ const needsJson = models.some(
521
+ (model2) => Object.values(model2.fields).some((field) => field.kind === "json")
522
+ );
320
523
  const needsIndexes = models.some(
321
524
  (model2) => model2.constraints.indexes.length || model2.constraints.unique.length
322
525
  );
@@ -325,7 +528,9 @@ function drizzleImports(dialect, manifest) {
325
528
  "pgTable",
326
529
  "text",
327
530
  needsBoolean ? "boolean" : null,
531
+ needsInteger ? "integer" : null,
328
532
  needsDate ? "timestamp" : null,
533
+ needsJson ? "jsonb" : null,
329
534
  needsIndexes ? "index" : null,
330
535
  needsIndexes ? "uniqueIndex" : null
331
536
  ].filter(Boolean);
@@ -336,7 +541,9 @@ function drizzleImports(dialect, manifest) {
336
541
  "varchar",
337
542
  "text",
338
543
  needsBoolean ? "boolean" : null,
544
+ needsInteger ? "int" : null,
339
545
  needsDate ? "datetime" : null,
546
+ needsJson ? "json" : null,
340
547
  needsIndexes ? "index" : null,
341
548
  needsIndexes ? "uniqueIndex" : null
342
549
  ].filter(Boolean);
@@ -350,6 +557,10 @@ function drizzleImports(dialect, manifest) {
350
557
  ].filter(Boolean);
351
558
  }
352
559
  function drizzleColumn(field, dialect, options = {}) {
560
+ const renderDefault = () => {
561
+ if (field.defaultValue === void 0 || field.kind === "json") return "";
562
+ return `.default(${JSON.stringify(field.defaultValue)})`;
563
+ };
353
564
  if (field.kind === "id") {
354
565
  if (dialect === "mysql") {
355
566
  return `varchar("${field.column}", { length: 191 }).primaryKey()`;
@@ -359,15 +570,30 @@ function drizzleColumn(field, dialect, options = {}) {
359
570
  if (field.kind === "string") {
360
571
  if (dialect === "mysql") {
361
572
  const base = field.unique || field.references || options.indexed ? `varchar("${field.column}", { length: 191 })` : `text("${field.column}")`;
362
- return `${base}${field.nullable ? "" : ".notNull()"}${field.unique ? ".unique()" : ""}${field.defaultValue !== void 0 ? `.default(${JSON.stringify(field.defaultValue)})` : ""}`;
573
+ return `${base}${field.nullable ? "" : ".notNull()"}${field.unique ? ".unique()" : ""}${renderDefault()}`;
363
574
  }
364
- return `text("${field.column}")${field.nullable ? "" : ".notNull()"}${field.unique ? ".unique()" : ""}${field.defaultValue !== void 0 ? `.default(${JSON.stringify(field.defaultValue)})` : ""}`;
575
+ return `text("${field.column}")${field.nullable ? "" : ".notNull()"}${field.unique ? ".unique()" : ""}${renderDefault()}`;
365
576
  }
366
577
  if (field.kind === "boolean") {
367
578
  if (dialect === "sqlite") {
368
- return `integer("${field.column}", { mode: "boolean" })${field.nullable ? "" : ".notNull()"}${field.defaultValue !== void 0 ? `.default(${String(field.defaultValue)})` : ""}`;
579
+ return `integer("${field.column}", { mode: "boolean" })${field.nullable ? "" : ".notNull()"}${renderDefault()}`;
369
580
  }
370
- return `boolean("${field.column}")${field.nullable ? "" : ".notNull()"}${field.defaultValue !== void 0 ? `.default(${String(field.defaultValue)})` : ""}`;
581
+ return `boolean("${field.column}")${field.nullable ? "" : ".notNull()"}${renderDefault()}`;
582
+ }
583
+ if (field.kind === "integer") {
584
+ if (dialect === "mysql") {
585
+ return `int("${field.column}")${field.nullable ? "" : ".notNull()"}${renderDefault()}`;
586
+ }
587
+ return `integer("${field.column}")${field.nullable ? "" : ".notNull()"}${renderDefault()}`;
588
+ }
589
+ if (field.kind === "json") {
590
+ if (dialect === "pg") {
591
+ return `jsonb("${field.column}")${field.nullable ? "" : ".notNull()"}`;
592
+ }
593
+ if (dialect === "mysql") {
594
+ return `json("${field.column}")${field.nullable ? "" : ".notNull()"}`;
595
+ }
596
+ return `text("${field.column}", { mode: "json" })${field.nullable ? "" : ".notNull()"}`;
371
597
  }
372
598
  if (dialect === "mysql") {
373
599
  return `datetime("${field.column}", { mode: "date" })${field.nullable ? "" : ".notNull()"}`;
@@ -387,6 +613,14 @@ function sqlType(field, dialect, options = {}) {
387
613
  if (field.kind === "boolean") {
388
614
  return dialect === "sqlite" ? "integer" : "boolean";
389
615
  }
616
+ if (field.kind === "integer") {
617
+ return "integer";
618
+ }
619
+ if (field.kind === "json") {
620
+ if (dialect === "postgres") return "jsonb";
621
+ if (dialect === "mysql") return "json";
622
+ return "text";
623
+ }
390
624
  if (dialect === "mysql") {
391
625
  return "datetime";
392
626
  }
@@ -440,7 +674,7 @@ function renderPrismaSchema(schema, options = {}) {
440
674
  if (field.kind === "id") modifiers.push("@id");
441
675
  if (field.generated === "id") modifiers.push("@default(cuid())");
442
676
  if (field.generated === "now") modifiers.push("@default(now())");
443
- if (field.defaultValue !== void 0 && field.generated === void 0) {
677
+ if (field.defaultValue !== void 0 && field.generated === void 0 && field.kind !== "json") {
444
678
  modifiers.push(
445
679
  typeof field.defaultValue === "string" ? `@default("${field.defaultValue}")` : `@default(${String(field.defaultValue)})`
446
680
  );
@@ -598,7 +832,7 @@ function renderSafeSql(schema, options) {
598
832
  if (field.kind === "id") parts.push("primary key");
599
833
  if (!field.nullable) parts.push("not null");
600
834
  if (field.unique && field.kind !== "id") parts.push("unique");
601
- if (field.defaultValue !== void 0) {
835
+ if (field.defaultValue !== void 0 && field.kind !== "json") {
602
836
  parts.push(
603
837
  `default ${typeof field.defaultValue === "string" ? `'${field.defaultValue}'` : String(field.defaultValue)}`
604
838
  );
@@ -649,17 +883,24 @@ ${block}
649
883
 
650
884
  // src/memory.ts
651
885
  var import_node_crypto = require("crypto");
652
- var isDate = (value) => value instanceof Date;
886
+ var manifestCache = /* @__PURE__ */ new WeakMap();
887
+ function getManifest(schema) {
888
+ const cached = manifestCache.get(schema);
889
+ if (cached) return cached;
890
+ const next = createManifest(schema);
891
+ manifestCache.set(schema, next);
892
+ return next;
893
+ }
653
894
  function evaluateFilter(value, filter) {
654
- if (filter === void 0 || filter === null || typeof filter !== "object" || isDate(filter) || Array.isArray(filter)) {
655
- return value === filter;
895
+ if (!isOperatorFilterObject(filter)) {
896
+ return equalValues(value, filter);
656
897
  }
657
898
  const record = filter;
658
- if ("eq" in record && value !== record.eq) return false;
659
- if ("not" in record && value === record.not) return false;
899
+ if ("eq" in record && !equalValues(value, record.eq)) return false;
900
+ if ("not" in record && equalValues(value, record.not)) return false;
660
901
  if ("in" in record) {
661
902
  const values = Array.isArray(record.in) ? record.in : [];
662
- if (!values.includes(value)) return false;
903
+ if (!values.some((candidate) => equalValues(candidate, value))) return false;
663
904
  }
664
905
  if ("contains" in record) {
665
906
  if (typeof value !== "string" || typeof record.contains !== "string") return false;
@@ -842,6 +1083,11 @@ function createMemoryDriver(seed) {
842
1083
  return projectRow(schema, model2, row, args.select);
843
1084
  },
844
1085
  async findUnique(schema, model2, args) {
1086
+ requireUniqueLookup(
1087
+ getManifest(schema).models[model2],
1088
+ args.where,
1089
+ "FindUnique"
1090
+ );
845
1091
  const row = applyQuery(getRows(model2), args)[0];
846
1092
  if (!row) return null;
847
1093
  return projectRow(schema, model2, row, args.select);
@@ -873,12 +1119,32 @@ function createMemoryDriver(seed) {
873
1119
  return rows.length;
874
1120
  },
875
1121
  async upsert(schema, model2, args) {
1122
+ const lookup = requireUniqueLookup(
1123
+ getManifest(schema).models[model2],
1124
+ args.where,
1125
+ "Upsert"
1126
+ );
1127
+ validateUniqueLookupUpdateData(
1128
+ getManifest(schema).models[model2],
1129
+ args.update,
1130
+ lookup,
1131
+ "Upsert"
1132
+ );
876
1133
  const row = getRows(model2).find((item) => matchesWhere(item, args.where));
877
1134
  if (row) {
878
1135
  Object.assign(row, args.update);
879
1136
  return projectRow(schema, model2, row, args.select);
880
1137
  }
881
- const created = buildRow(schema, model2, args.create);
1138
+ const created = buildRow(
1139
+ schema,
1140
+ model2,
1141
+ mergeUniqueLookupCreateData(
1142
+ getManifest(schema).models[model2],
1143
+ args.create,
1144
+ lookup,
1145
+ "Upsert"
1146
+ )
1147
+ );
882
1148
  getRows(model2).push(created);
883
1149
  return projectRow(schema, model2, created, args.select);
884
1150
  },
@@ -970,15 +1236,24 @@ function defineSchema(models) {
970
1236
  createOrm,
971
1237
  datetime,
972
1238
  defineSchema,
1239
+ equalValues,
973
1240
  hasMany,
974
1241
  hasOne,
975
1242
  id,
1243
+ integer,
1244
+ isOperatorFilterObject,
1245
+ json,
976
1246
  manyToMany,
1247
+ mergeUniqueLookupCreateData,
977
1248
  model,
978
1249
  renderDrizzleSchema,
979
1250
  renderPrismaSchema,
980
1251
  renderSafeSql,
981
1252
  replaceGeneratedBlock,
982
- string
1253
+ requireUniqueLookup,
1254
+ resolveRowIdentityLookup,
1255
+ string,
1256
+ toUniqueLookupWhere,
1257
+ validateUniqueLookupUpdateData
983
1258
  });
984
1259
  //# sourceMappingURL=index.cjs.map