@verdant-web/store 4.1.3 → 4.1.5

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,6 +1,12 @@
1
1
  export class ShutdownHandler {
2
2
  private consumed = false;
3
3
  private readonly handlers: (() => Promise<void>)[] = [];
4
+ constructor(
5
+ private log?: (
6
+ level: 'debug' | 'info' | 'warn' | 'error' | 'critical',
7
+ ...args: any[]
8
+ ) => void,
9
+ ) {}
4
10
 
5
11
  register(handler: () => Promise<void>) {
6
12
  this.handlers.push(handler);
@@ -8,7 +14,7 @@ export class ShutdownHandler {
8
14
 
9
15
  async shutdown() {
10
16
  if (this.consumed) {
11
- console.warn('ShutdownHandler already consumed');
17
+ this.log?.('warn', 'ShutdownHandler already consumed');
12
18
  }
13
19
 
14
20
  this.consumed = true;
@@ -11,7 +11,7 @@ import {
11
11
  createFileRef,
12
12
  createRef,
13
13
  getChildFieldSchema,
14
- getDefault,
14
+ getFieldDefault,
15
15
  hasDefault,
16
16
  isFile,
17
17
  isFileRef,
@@ -199,7 +199,7 @@ export class Entity<
199
199
  if (viewIsWrongType) {
200
200
  // this will cover lists and maps, too.
201
201
  if (hasDefault(this.schema)) {
202
- return getDefault(this.schema);
202
+ return getFieldDefault(this.schema);
203
203
  }
204
204
  // force null - invalid - will require parent prune
205
205
  return null as any;
@@ -656,17 +656,11 @@ export class Entity<
656
656
  requireDefaults: true,
657
657
  })
658
658
  ) {
659
- if (hasDefault(fieldSchema)) {
660
- // FIXME: this returns []/{} for arrays and objects, but the contract
661
- // of this method should return an Entity for such object fields.
662
- // I want to write a test case for this one before attempting to fix
663
- // just to be sure the fix works.
664
- return getDefault(fieldSchema);
665
- }
666
- if (isNullable(fieldSchema)) {
667
- return null as any;
668
- }
669
- return undefined as any;
659
+ // FIXME: this returns []/{} for arrays and objects, but the contract
660
+ // of this method should return an Entity for such object fields.
661
+ // I want to write a test case for this one before attempting to fix
662
+ // just to be sure the fix works.
663
+ return getFieldDefault(fieldSchema);
670
664
  }
671
665
  return child as KeyValue[Key];
672
666
  }
@@ -890,13 +884,20 @@ export class Entity<
890
884
  merge = true,
891
885
  replaceSubObjects = false,
892
886
  preserveUndefined = false,
887
+ dangerouslyDisableMerge = false,
893
888
  }: {
894
889
  replaceSubObjects?: boolean;
895
890
  merge?: boolean;
896
891
  preserveUndefined?: boolean;
892
+ dangerouslyDisableMerge?: boolean;
897
893
  } = {},
898
894
  ): void => {
899
- if (!merge && this.schema.type !== 'any' && this.schema.type !== 'map') {
895
+ if (
896
+ !merge &&
897
+ !dangerouslyDisableMerge &&
898
+ this.schema.type !== 'any' &&
899
+ this.schema.type !== 'map'
900
+ ) {
900
901
  throw new Error(
901
902
  'Cannot use .update without merge if the field has a strict schema type. merge: false is only available on "any" or "map" types.',
902
903
  );
@@ -163,6 +163,13 @@ export interface ObjectEntity<
163
163
  * Default: true
164
164
  */
165
165
  merge?: boolean;
166
+ /**
167
+ * If set to true, bypasses the restrictions around merge: false for
168
+ * object fields. This means you can accidentally erase required fields
169
+ * on this object or a sub-object. Unless you are certain your passed
170
+ * data conforms to the expected schema, you should not use this option.
171
+ */
172
+ dangerouslyDisableMerge?: boolean;
166
173
  },
167
174
  ): void;
168
175
  /**
@@ -1,10 +1,10 @@
1
1
  import { Migration } from '@verdant-web/common';
2
- import { getMigrationPath } from './paths.js';
3
- import { OpenDocumentDbContext } from './types.js';
2
+ import { ShutdownHandler } from '../../context/ShutdownHandler.js';
3
+ import { PersistenceNamespace } from '../interfaces.js';
4
4
  import { getMigrationEngine } from './engine.js';
5
5
  import { finalizeMigration } from './finalize.js';
6
- import { PersistenceNamespace } from '../interfaces.js';
7
- import { ShutdownHandler } from '../../context/ShutdownHandler.js';
6
+ import { getMigrationPath } from './paths.js';
7
+ import { OpenDocumentDbContext } from './types.js';
8
8
 
9
9
  export async function migrate({
10
10
  context,
@@ -79,7 +79,7 @@ export async function runMigrations({
79
79
  const migrationContext = {
80
80
  ...context,
81
81
  schema: migration.oldSchema,
82
- shutdownHandler: new ShutdownHandler(),
82
+ shutdownHandler: new ShutdownHandler(context.log),
83
83
  };
84
84
  // this will only write to our metadata store via operations!
85
85
  const engine = await getMigrationEngine({
@@ -139,7 +139,7 @@ export async function importPersistence(
139
139
  disableRebasing: true,
140
140
  },
141
141
  },
142
- persistenceShutdownHandler: new ShutdownHandler(),
142
+ persistenceShutdownHandler: new ShutdownHandler(ctx.log),
143
143
  });
144
144
  // load imported data into persistence
145
145
  await importedContext.meta.resetFrom(exportedData.data);
@@ -176,7 +176,7 @@ export async function importPersistence(
176
176
  const currentSchema = ctx.schema;
177
177
  const upgradedContext = await initializePersistence({
178
178
  ...importedContext,
179
- persistenceShutdownHandler: new ShutdownHandler(),
179
+ persistenceShutdownHandler: new ShutdownHandler(ctx.log),
180
180
  schema: currentSchema,
181
181
  });
182
182