convex-ents 0.12.0 → 0.13.0-alpha.1

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,7 +1,7 @@
1
1
  import { GenericEntsDataModel, GenericEdgeConfig, Expand, DeletionConfig } from './schema.js';
2
2
  import * as convex_values from 'convex/values';
3
3
  import { GenericId } from 'convex/values';
4
- import { TableNamesInDataModel, GenericDocument, DocumentByName, FilterBuilder, NamedTableInfo, ExpressionOrValue, PaginationOptions, IndexNames, FieldTypeFromFieldPath, SearchIndexNames, SearchFilterBuilder, NamedSearchIndex, SearchFilter, PaginationResult, IndexRangeBuilder, NamedIndex, IndexRange, WithoutSystemFields, WithOptionalSystemFields, GenericDataModel, GenericDatabaseReader, GenericDatabaseWriter, Scheduler } from 'convex/server';
4
+ import { TableNamesInDataModel, GenericDocument, DocumentByName, FilterBuilder, NamedTableInfo, ExpressionOrValue, PaginationOptions, IndexNames, FieldTypeFromFieldPath, SearchIndexNames, SearchFilterBuilder, NamedSearchIndex, SearchFilter, PaginationResult, IndexRangeBuilder, NamedIndex, IndexRange, WithoutSystemFields, WithOptionalSystemFields, GenericDataModel, GenericDatabaseReader, GenericDatabaseWriter, StorageWriter, Scheduler } from 'convex/server';
5
5
  import { ScheduledDeleteFuncRef } from './deletion.js';
6
6
  import { IndexFieldTypesForEq, EntsSystemDataModel, PromiseEdgeResult } from './shared.js';
7
7
 
@@ -11,7 +11,8 @@ declare class WriterImplBase<EntsDataModel extends GenericEntsDataModel, Table e
11
11
  protected table: Table;
12
12
  constructor(ctx: EntMutationCtx<EntsDataModel>, entDefinitions: EntsDataModel, table: Table);
13
13
  deleteId(id: GenericId<any>, behavior: "default" | "soft" | "hard"): Promise<GenericId<any>>;
14
- deletedIdIn(id: GenericId<any>, table: string, cascadingSoft: boolean): Promise<void>;
14
+ deleteIdIn(id: GenericId<any>, table: string, cascadingSoft: boolean): Promise<void>;
15
+ deleteSystem(table: string, id: GenericId<any>): Promise<void>;
15
16
  writeEdges(docId: GenericId<any>, changes: EdgeChanges, deleteSoftly?: boolean): Promise<void>;
16
17
  checkUniqueness(value: Partial<GenericDocument>, id?: GenericId<any>): Promise<void>;
17
18
  fieldsOnly(value: Partial<WithEdgePatches<DocumentByName<EntsDataModel, Table>, EntsDataModel[Table]["edges"]>>): GenericDocument;
@@ -34,6 +35,7 @@ type EdgeChanges = Record<string, {
34
35
  remove?: GenericId<any>[];
35
36
  removeEdges?: GenericId<any>[];
36
37
  }>;
38
+ declare function isSystemTable(table: string): boolean;
37
39
 
38
40
  interface PromiseOrderedQueryOrNull<EntsDataModel extends GenericEntsDataModel, Table extends TableNamesInDataModel<EntsDataModel>> extends Promise<Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[] | null> {
39
41
  filter(predicate: (q: FilterBuilder<NamedTableInfo<EntsDataModel, Table>>) => ExpressionOrValue<boolean>): this;
@@ -351,7 +353,7 @@ declare class EntInstance<EntsDataModel extends GenericEntsDataModel, Table exte
351
353
  }
352
354
  type Ent<Table extends TableNamesInDataModel<EntsDataModel>, Doc extends DocumentByName<EntsDataModel, Table>, EntsDataModel extends GenericEntsDataModel> = Doc & EntInstance<EntsDataModel, Table>;
353
355
  type GenericEnt<EntsDataModel extends GenericEntsDataModel, Table extends TableNamesInDataModel<EntsDataModel>> = Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>;
354
- type PromiseEdge<EntsDataModel extends GenericEntsDataModel, Table extends TableNamesInDataModel<EntsDataModel>, Edge extends keyof EntsDataModel[Table]["edges"], Config extends GenericEdgeConfig = EntsDataModel[Table]["edges"][Edge], ToTable extends TableNamesInDataModel<EntsDataModel> = EntsDataModel[Table]["edges"][Edge]["to"]> = PromiseEdgeResult<Config, PromiseEdgeEnts<EntsDataModel, ToTable>, PromiseQuery<EntsDataModel, ToTable>, PromiseEntOrNull<EntsDataModel, ToTable>, PromiseEnt<EntsDataModel, ToTable>>;
356
+ type PromiseEdge<EntsDataModel extends GenericEntsDataModel, Table extends TableNamesInDataModel<EntsDataModel>, Edge extends keyof EntsDataModel[Table]["edges"], Config extends GenericEdgeConfig = EntsDataModel[Table]["edges"][Edge], ToTable extends TableNamesInDataModel<EntsDataModel> = EntsDataModel[Table]["edges"][Edge]["to"]> = PromiseEdgeResult<Config, PromiseEdgeEnts<EntsDataModel, ToTable>, PromiseQuery<EntsDataModel, ToTable>, ToTable extends "_storage" | "_scheduled_functions" ? PromiseEntOrNull<EntsSystemDataModel, ToTable> : PromiseEntOrNull<EntsDataModel, ToTable>, ToTable extends "_storage" ? PromiseEnt<EntsSystemDataModel, ToTable> : ToTable extends "_scheduled_functions" ? PromiseEntOrNull<EntsSystemDataModel, ToTable> : PromiseEnt<EntsDataModel, ToTable>>;
355
357
  type PromiseEdgeOrThrow<EntsDataModel extends GenericEntsDataModel, Table extends TableNamesInDataModel<EntsDataModel>, Edge extends keyof EntsDataModel[Table]["edges"], Config extends GenericEdgeConfig = EntsDataModel[Table]["edges"][Edge], ToTable extends TableNamesInDataModel<EntsDataModel> = EntsDataModel[Table]["edges"][Edge]["to"]> = PromiseEdgeResult<Config, PromiseEdgeEnts<EntsDataModel, ToTable>, PromiseQuery<EntsDataModel, ToTable>, PromiseEnt<EntsDataModel, ToTable>, PromiseEnt<EntsDataModel, ToTable>>;
356
358
  type PromiseEdgeOrNull<EntsDataModel extends GenericEntsDataModel, Table extends TableNamesInDataModel<EntsDataModel>, Edge extends keyof EntsDataModel[Table]["edges"], Config extends GenericEdgeConfig = EntsDataModel[Table]["edges"][Edge], ToTable extends TableNamesInDataModel<EntsDataModel> = EntsDataModel[Table]["edges"][Edge]["to"]> = PromiseEdgeResult<Config, PromiseEdgeEntsOrNull<EntsDataModel, ToTable>, PromiseQueryOrNull<EntsDataModel, ToTable>, PromiseEntOrNull<EntsDataModel, ToTable>, PromiseEntOrNull<EntsDataModel, ToTable>>;
357
359
  type PromiseEdgeWriter<EntsDataModel extends GenericEntsDataModel, Table extends TableNamesInDataModel<EntsDataModel>, Edge extends keyof EntsDataModel[Table]["edges"], Config extends GenericEdgeConfig = EntsDataModel[Table]["edges"][Edge], ToTable extends TableNamesInDataModel<EntsDataModel> = EntsDataModel[Table]["edges"][Edge]["to"]> = PromiseEdgeResult<Config, PromiseEdgeEntsWriter<EntsDataModel, ToTable>, PromiseQueryWriter<EntsDataModel, ToTable>, PromiseEntWriterOrNull<EntsDataModel, ToTable>, PromiseEntWriter<EntsDataModel, ToTable>>;
@@ -499,6 +501,7 @@ interface EntQueryCtx<DataModel extends GenericDataModel> {
499
501
  }
500
502
  interface EntMutationCtx<DataModel extends GenericDataModel> extends EntQueryCtx<DataModel> {
501
503
  db: GenericDatabaseWriter<DataModel>;
504
+ storage: StorageWriter;
502
505
  scheduler: Scheduler;
503
506
  }
504
507
  type DocRetriever<ID, Doc> = () => Promise<{
@@ -543,4 +546,4 @@ declare function getWriteRule(entDefinitions: GenericEntsDataModel, table: strin
543
546
  }) => Promise<boolean>) | undefined;
544
547
  declare function getDeletionConfig<EntsDataModel extends GenericEntsDataModel, Table extends TableNamesInDataModel<EntsDataModel>>(entDefinitions: EntsDataModel, table: Table): DeletionConfig | undefined;
545
548
 
546
- export { type EntQueryCtx as $, type PromiseEnt as A, type PromiseArrayOrNull as B, type PromiseArray as C, entWrapper as D, type EdgeChanges as E, entsTableFactory as F, type EntsTable as G, type EntsTableWriter as H, type Ent as I, type GenericEnt as J, type PromiseEdge as K, type PromiseEdgeOrThrow as L, type PromiseEdgeWriter as M, type PromiseEdgeWriterOrThrow as N, type PromiseEdgeWriterOrNull as O, type PromiseOrderedQueryOrNull as P, type PromiseOrderedQueryWriter as Q, type PromiseQueryWriter as R, type PromiseEntsWriter as S, type PromisePaginationResultWriterOrNull as T, type PromisePaginationResultWriter as U, type PromiseTableWriter as V, WriterImplBase as W, type PromiseEntWriterOrNull as X, type PromiseEntWriter as Y, type GenericEntWriter as Z, type PromiseEntId as _, type WithEdgeInserts as a, type EntMutationCtx as a0, type DocRetriever as a1, addEntRules as a2, getReadRule as a3, getWriteRule as a4, getDeletionConfig as a5, type WithEdges as b, type WithEdgePatches as c, type PromiseOrderedQueryWriterOrNull as d, type PromiseQueryOrNull as e, type PromiseQueryWriterOrNull as f, type PromiseTableBase as g, type PromiseTable as h, type PromiseOrderedQueryBase as i, type PromiseOrderedQuery as j, type PromiseQuery as k, type PromisePaginationResultOrNull as l, type PromisePaginationResult as m, type PromiseEntsOrNull as n, type PromiseEntsWriterOrNull as o, type PromiseEnts as p, type PromiseEntsOrNulls as q, type PromiseEdgeOrderedEntsOrNull as r, type PromiseEdgeEntsOrNull as s, type PromiseEdgeOrderedEntsWriterOrNull as t, type PromiseEdgeEntsWriterOrNull as u, type PromiseEdgeOrderedEnts as v, type PromiseEdgeEnts as w, type PromiseEdgeOrderedEntsWriter as x, type PromiseEdgeEntsWriter as y, type PromiseEntOrNull as z };
549
+ export { type PromiseEntId as $, type PromiseEntOrNull as A, type PromiseEnt as B, type PromiseArrayOrNull as C, type PromiseArray as D, type EdgeChanges as E, entWrapper as F, entsTableFactory as G, type EntsTable as H, type EntsTableWriter as I, type Ent as J, type GenericEnt as K, type PromiseEdge as L, type PromiseEdgeOrThrow as M, type PromiseEdgeWriter as N, type PromiseEdgeWriterOrThrow as O, type PromiseOrderedQueryOrNull as P, type PromiseEdgeWriterOrNull as Q, type PromiseOrderedQueryWriter as R, type PromiseQueryWriter as S, type PromiseEntsWriter as T, type PromisePaginationResultWriterOrNull as U, type PromisePaginationResultWriter as V, WriterImplBase as W, type PromiseTableWriter as X, type PromiseEntWriterOrNull as Y, type PromiseEntWriter as Z, type GenericEntWriter as _, type WithEdgeInserts as a, type EntQueryCtx as a0, type EntMutationCtx as a1, type DocRetriever as a2, addEntRules as a3, getReadRule as a4, getWriteRule as a5, getDeletionConfig as a6, type WithEdges as b, type WithEdgePatches as c, type PromiseOrderedQueryWriterOrNull as d, type PromiseQueryOrNull as e, type PromiseQueryWriterOrNull as f, type PromiseTableBase as g, type PromiseTable as h, isSystemTable as i, type PromiseOrderedQueryBase as j, type PromiseOrderedQuery as k, type PromiseQuery as l, type PromisePaginationResultOrNull as m, type PromisePaginationResult as n, type PromiseEntsOrNull as o, type PromiseEntsWriterOrNull as p, type PromiseEnts as q, type PromiseEntsOrNulls as r, type PromiseEdgeOrderedEntsOrNull as s, type PromiseEdgeEntsOrNull as t, type PromiseEdgeOrderedEntsWriterOrNull as u, type PromiseEdgeEntsWriterOrNull as v, type PromiseEdgeOrderedEnts as w, type PromiseEdgeEnts as x, type PromiseEdgeOrderedEntsWriter as y, type PromiseEdgeEntsWriter as z };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { EntDefinition, defineEnt, defineEntFromTable, defineEntSchema, defineEntsFromTables, getEntDefinitions } from './schema.js';
2
- export { J as GenericEnt, Z as GenericEntWriter, w as PromiseEdgeEnts, s as PromiseEdgeEntsOrNull, y as PromiseEdgeEntsWriter, M as PromiseEdgeWriter, O as PromiseEdgeWriterOrNull, N as PromiseEdgeWriterOrThrow, A as PromiseEnt, _ as PromiseEntId, z as PromiseEntOrNull, Y as PromiseEntWriter, X as PromiseEntWriterOrNull, p as PromiseEnts, n as PromiseEntsOrNull, q as PromiseEntsOrNulls, S as PromiseEntsWriter, o as PromiseEntsWriterOrNull, j as PromiseOrderedQuery, i as PromiseOrderedQueryBase, P as PromiseOrderedQueryOrNull, Q as PromiseOrderedQueryWriter, d as PromiseOrderedQueryWriterOrNull, k as PromiseQuery, e as PromiseQueryOrNull, R as PromiseQueryWriter, f as PromiseQueryWriterOrNull, h as PromiseTable, g as PromiseTableBase, V as PromiseTableWriter, a2 as addEntRules, F as entsTableFactory } from './index-kwzjMMHy.js';
2
+ export { K as GenericEnt, _ as GenericEntWriter, x as PromiseEdgeEnts, t as PromiseEdgeEntsOrNull, z as PromiseEdgeEntsWriter, N as PromiseEdgeWriter, Q as PromiseEdgeWriterOrNull, O as PromiseEdgeWriterOrThrow, B as PromiseEnt, $ as PromiseEntId, A as PromiseEntOrNull, Z as PromiseEntWriter, Y as PromiseEntWriterOrNull, q as PromiseEnts, o as PromiseEntsOrNull, r as PromiseEntsOrNulls, T as PromiseEntsWriter, p as PromiseEntsWriterOrNull, k as PromiseOrderedQuery, j as PromiseOrderedQueryBase, P as PromiseOrderedQueryOrNull, R as PromiseOrderedQueryWriter, d as PromiseOrderedQueryWriterOrNull, l as PromiseQuery, e as PromiseQueryOrNull, S as PromiseQueryWriter, f as PromiseQueryWriterOrNull, h as PromiseTable, g as PromiseTableBase, X as PromiseTableWriter, a3 as addEntRules, G as entsTableFactory } from './index-surAwtky.js';
3
3
  export { scheduledDeleteFactory } from './deletion.js';
4
4
  import 'convex/server';
5
5
  import 'convex/values';
package/dist/index.js CHANGED
@@ -41,13 +41,31 @@ function defineEntSchema(schema, options) {
41
41
  for (const edge of edgeConfigsBeforeDefineSchema(table)) {
42
42
  if (
43
43
  // Skip inverse edges, we process their forward edges
44
- edge.cardinality === "multiple" && edge.type === "ref" && edge.inverse !== void 0 || // symmetric is only set by defineEntSchema,
44
+ edge.cardinality === "multiple" && edge.type === "ref" && (edge.inverse !== void 0 || // symmetric is only set by defineEntSchema,
45
45
  // so we already processed the pair
46
- edge.symmetric !== void 0
46
+ edge.symmetric !== void 0)
47
47
  ) {
48
48
  continue;
49
49
  }
50
50
  const otherTableName = edge.to;
51
+ if (otherTableName.startsWith("_")) {
52
+ if (edge.cardinality !== "single") {
53
+ throw new Error(
54
+ `Many:many edge "${edge.name}" in table "${tableName}" points to a system table "${otherTableName}", but only 1:1 edges can point to system tables`
55
+ );
56
+ }
57
+ if (edge.type !== "field") {
58
+ throw new Error(
59
+ `Edge "${edge.name}" in table "${tableName}" pointing to a system table "${otherTableName}" must store the edge by storing the system document ID. Remove the \`ref\` option.`
60
+ );
61
+ }
62
+ if (edge.deletion === "soft") {
63
+ throw new Error(
64
+ `Edge "${edge.name}" in table "${tableName}" pointing to a system table "${otherTableName}" cannot use soft deletion, because system documents cannot be soft deleted.`
65
+ );
66
+ }
67
+ continue;
68
+ }
51
69
  const otherTable = schema[otherTableName];
52
70
  if (otherTable === void 0) {
53
71
  throw new Error(
@@ -77,7 +95,7 @@ function defineEntSchema(schema, options) {
77
95
  }
78
96
  if (inverseEdge.cardinality === "single" && inverseEdge.type === "ref") {
79
97
  throw new Error(
80
- `Both edge "${edge.name}" in table "${inverseEdge.to}" and edge "${inverseEdge.name}" in table "${edge.to}" are marked as optional, choose one to be required.`
98
+ `Both edge "${edge.name}" in table "${inverseEdge.to}" and edge "${inverseEdge.name}" in table "${edge.to}" are marked as references, choose one to store the edge by removing the \`ref\` option.`
81
99
  );
82
100
  }
83
101
  if (inverseEdge.cardinality !== "single" || inverseEdge.type !== "field") {
@@ -90,7 +108,7 @@ function defineEntSchema(schema, options) {
90
108
  }
91
109
  inverseEdge.unique = true;
92
110
  }
93
- if (edge.cardinality === "single" && edge.type === "ref" || edge.cardinality === "multiple" && edge.type === "field") {
111
+ if (edge.cardinality === "single" || edge.cardinality === "multiple" && edge.type === "field") {
94
112
  if (edge.deletion !== void 0 && deletionConfigFromEntDefinition(otherTable) === void 0) {
95
113
  throw new Error(
96
114
  `Cannot specify soft deletion behavior for edge "${edge.name}" in table "${tableName}" because the target table "${otherTableName}" does not have a "soft" or "scheduled" deletion behavior configured.`
@@ -106,7 +124,7 @@ function defineEntSchema(schema, options) {
106
124
  if (inverseEdge?.cardinality === "single") {
107
125
  if (inverseEdge.type === "ref") {
108
126
  throw new Error(
109
- `The edge "${inverseEdge.name}" in table "${otherTableName}" cannot be optional, as it must store the 1:many edge as a field. Check the its inverse edge "${edge.name}" in table "${tableName}".`
127
+ `The edge "${inverseEdge.name}" in table "${otherTableName}" specified \`ref\`, but it must store the 1:many edge as a field. Check the its inverse edge "${edge.name}" in table "${tableName}".`
110
128
  );
111
129
  }
112
130
  if (edge.type === "ref") {
@@ -146,17 +164,19 @@ function defineEntSchema(schema, options) {
146
164
  ]);
147
165
  }
148
166
  schema[edgeTableName] = edgeTable;
149
- edge.type = "ref";
150
- edge.table = edgeTableName;
151
- edge.field = forwardId;
152
- edge.ref = inverseId;
153
- edge.symmetric = inverseEdge === void 0;
167
+ const edgeConfig = edge;
168
+ edgeConfig.type = "ref";
169
+ edgeConfig.table = edgeTableName;
170
+ edgeConfig.field = forwardId;
171
+ edgeConfig.ref = inverseId;
172
+ edgeConfig.symmetric = inverseEdge === void 0;
154
173
  if (inverseEdge !== void 0) {
155
174
  inverseEdge.type = "ref";
156
- inverseEdge.table = edgeTableName;
157
- inverseEdge.field = inverseId;
158
- inverseEdge.ref = forwardId;
159
- inverseEdge.symmetric = false;
175
+ const inverseEdgeConfig = inverseEdge;
176
+ inverseEdgeConfig.table = edgeTableName;
177
+ inverseEdgeConfig.field = inverseId;
178
+ inverseEdgeConfig.ref = forwardId;
179
+ inverseEdgeConfig.symmetric = false;
160
180
  }
161
181
  }
162
182
  }
@@ -305,7 +325,12 @@ var EntDefinitionImpl = class {
305
325
  throw new Error(`Duplicate edge "${edgeName}"`);
306
326
  }
307
327
  const to = options?.to ?? edgeName + "s";
308
- if (options?.field !== void 0 || options?.optional !== true) {
328
+ if (options?.field !== void 0 && options?.ref !== void 0) {
329
+ throw new Error(
330
+ `Cannot specify both \`field\` and \`ref\` for the same edge, choose one to be the reference and the other to store the foreign key.`
331
+ );
332
+ }
333
+ if (options?.field !== void 0 || options?.ref === void 0) {
309
334
  const fieldName = options?.field ?? edgeName + "Id";
310
335
  this.documentSchema = {
311
336
  ...this.documentSchema,
@@ -317,7 +342,8 @@ var EntDefinitionImpl = class {
317
342
  cardinality: "single",
318
343
  type: "field",
319
344
  field: fieldName,
320
- optional: options?.optional === true
345
+ optional: options?.optional === true,
346
+ deletion: options?.deletion
321
347
  };
322
348
  this.indexes.push({
323
349
  indexDescriptor: fieldName,
@@ -325,15 +351,14 @@ var EntDefinitionImpl = class {
325
351
  });
326
352
  return this;
327
353
  }
328
- if (options.optional === true) {
329
- this.edgeConfigs[edgeName] = {
330
- name: edgeName,
331
- to,
332
- cardinality: "single",
333
- type: "ref",
334
- ref: options.ref ?? null
335
- };
336
- }
354
+ this.edgeConfigs[edgeName] = {
355
+ name: edgeName,
356
+ to,
357
+ cardinality: "single",
358
+ type: "ref",
359
+ ref: options.ref === true ? null : options.ref,
360
+ deletion: options.deletion
361
+ };
337
362
  return this;
338
363
  }
339
364
  edges(name, options) {
@@ -427,7 +452,7 @@ var WriterImplBase = class _WriterImplBase {
427
452
  const isDeletingSoftly = behavior !== "hard" && deletionConfig !== void 0 && (deletionConfig.type === "soft" || deletionConfig.type === "scheduled");
428
453
  if (behavior === "soft" && !isDeletingSoftly) {
429
454
  throw new Error(
430
- `Cannot soft delete document with ID "${id}" in table "${this.table}" because it does not have an "allowSoft", "soft" or "scheduled" deletion behavior configured.`
455
+ `Cannot soft delete document with ID "${id}" in table "${this.table}" because it does not have a "soft" or "scheduled" deletion behavior configured.`
431
456
  );
432
457
  }
433
458
  const edges = {};
@@ -443,6 +468,16 @@ var WriterImplBase = class _WriterImplBase {
443
468
  ).collect()).map((doc) => doc._id);
444
469
  edges[key] = { remove };
445
470
  }
471
+ } else if (edgeDefinition.cardinality === "single") {
472
+ if (edgeDefinition.deletion !== void 0 && (!isDeletingSoftly || edgeDefinition.deletion === "soft")) {
473
+ const doc = await this.ctx.db.get(id);
474
+ if (doc !== null) {
475
+ const otherId = doc[edgeDefinition.field];
476
+ edges[key] = {
477
+ remove: otherId !== void 0 ? [otherId] : []
478
+ };
479
+ }
480
+ }
446
481
  } else if (edgeDefinition.cardinality === "multiple") {
447
482
  if (!isDeletingSoftly) {
448
483
  const removeEdges = (await this.ctx.db.query(edgeDefinition.table).withIndex(
@@ -486,12 +521,26 @@ var WriterImplBase = class _WriterImplBase {
486
521
  }
487
522
  return id;
488
523
  }
489
- async deletedIdIn(id, table, cascadingSoft) {
524
+ async deleteIdIn(id, table, cascadingSoft) {
490
525
  await new _WriterImplBase(this.ctx, this.entDefinitions, table).deleteId(
491
526
  id,
492
527
  cascadingSoft ? "soft" : "hard"
493
528
  );
494
529
  }
530
+ async deleteSystem(table, id) {
531
+ switch (table) {
532
+ case "_storage":
533
+ await this.ctx.storage.delete(id);
534
+ break;
535
+ case "_scheduled_functions":
536
+ await this.ctx.scheduler.cancel(id);
537
+ break;
538
+ default:
539
+ throw new Error(
540
+ `Cannot cascade deletion to unsupported system table "${table}".`
541
+ );
542
+ }
543
+ }
495
544
  async writeEdges(docId, changes, deleteSoftly) {
496
545
  await Promise.all(
497
546
  Object.values(getEdgeDefinitions(this.entDefinitions, this.table)).map(
@@ -504,7 +553,7 @@ var WriterImplBase = class _WriterImplBase {
504
553
  if (idOrIds.remove !== void 0 && idOrIds.remove.length > 0) {
505
554
  await Promise.all(
506
555
  idOrIds.remove.map(
507
- (id) => this.deletedIdIn(
556
+ (id) => this.deleteIdIn(
508
557
  id,
509
558
  edgeDefinition.to,
510
559
  (deleteSoftly ?? false) && edgeDefinition.deletion === "soft"
@@ -521,6 +570,18 @@ var WriterImplBase = class _WriterImplBase {
521
570
  )
522
571
  );
523
572
  }
573
+ } else if (edgeDefinition.cardinality === "single") {
574
+ if (idOrIds.remove !== void 0 && idOrIds.remove.length > 0) {
575
+ await Promise.all(
576
+ idOrIds.remove.map(
577
+ isSystemTable(edgeDefinition.to) ? (id) => this.deleteSystem(edgeDefinition.to, id) : (id) => this.deleteIdIn(
578
+ id,
579
+ edgeDefinition.to,
580
+ (deleteSoftly ?? false) && edgeDefinition.deletion === "soft"
581
+ )
582
+ )
583
+ );
584
+ }
524
585
  } else if (edgeDefinition.cardinality === "multiple") {
525
586
  if ((idOrIds.removeEdges ?? []).length > 0) {
526
587
  await Promise.all(
@@ -605,7 +666,7 @@ var WriterImplBase = class _WriterImplBase {
605
666
  this.entDefinitions,
606
667
  this.table
607
668
  )[key];
608
- if (edgeDefinition === void 0) {
669
+ if (edgeDefinition === void 0 || edgeDefinition.cardinality === "single" && edgeDefinition.type === "field" && edgeDefinition.field === key) {
609
670
  fields[key] = value[key];
610
671
  }
611
672
  });
@@ -664,6 +725,9 @@ var WriterImplBase = class _WriterImplBase {
664
725
  }
665
726
  }
666
727
  };
728
+ function isSystemTable(table) {
729
+ return table.startsWith("_");
730
+ }
667
731
 
668
732
  // src/functions.ts
669
733
  var PromiseQueryOrNullImpl = class _PromiseQueryOrNullImpl extends Promise {
@@ -1454,7 +1518,7 @@ var PromiseEntOrNullImpl = class extends Promise {
1454
1518
  );
1455
1519
  }
1456
1520
  const otherDoc = await this.ctx.db.get(otherId);
1457
- if (otherDoc === null) {
1521
+ if (otherDoc === null && edgeDefinition.to !== "_scheduled_functions") {
1458
1522
  throw new Error(
1459
1523
  `Dangling reference for edge "${edgeDefinition.name}" in table "${this.table}" on document with ID "${id}": Could not find a document with ID "${otherId}" in table "${edgeDefinition.to}".`
1460
1524
  );
@@ -1723,7 +1787,7 @@ var PromiseEntWriterImpl = class extends PromiseEntOrNullImpl {
1723
1787
  if (edgeDefinition.type === "ref") {
1724
1788
  const oldDoc = await this.ctx.db.get(docId);
1725
1789
  if (oldDoc[key] !== void 0 && oldDoc[key] !== idOrIds) {
1726
- throw new Error("Cannot set 1:1 edge from optional end.");
1790
+ throw new Error("Cannot set 1:1 edge from ref end.");
1727
1791
  }
1728
1792
  }
1729
1793
  } else {
@@ -1881,9 +1945,6 @@ function getWriteRule(entDefinitions, table) {
1881
1945
  function getDeletionConfig(entDefinitions, table) {
1882
1946
  return entDefinitions[table].deletionConfig;
1883
1947
  }
1884
- function isSystemTable(table) {
1885
- return table.startsWith("_");
1886
- }
1887
1948
 
1888
1949
  // src/deletion.ts
1889
1950
  var import_server3 = require("convex/server");
@@ -1933,11 +1994,11 @@ function scheduledDeleteFactory(entDefinitions, options) {
1933
1994
  if (doc.deletionTime !== origin.deletionTime) {
1934
1995
  if (inProgress) {
1935
1996
  console.error(
1936
- `[Ents] Already in-progress scheduled deletion for "${origin.id}" was cancelled!`
1997
+ `[Ents] Already in-progress scheduled deletion for "${origin.id}" was canceled!`
1937
1998
  );
1938
1999
  } else {
1939
2000
  console.log(
1940
- `[Ents] Scheduled deletion for "${origin.id}" was cancelled`
2001
+ `[Ents] Scheduled deletion for "${origin.id}" was canceled`
1941
2002
  );
1942
2003
  }
1943
2004
  return;