@rocicorp/zero 0.3.2024102300 → 0.3.2024102500

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.
Files changed (135) hide show
  1. package/out/react.js +0 -1
  2. package/out/react.js.map +2 -2
  3. package/out/zero-cache/src/db/create.js +1 -1
  4. package/out/zero-cache/src/db/create.js.map +1 -1
  5. package/out/zero-cache/src/db/migration-lite.d.ts +78 -0
  6. package/out/zero-cache/src/db/migration-lite.d.ts.map +1 -0
  7. package/out/zero-cache/src/db/migration-lite.js +181 -0
  8. package/out/zero-cache/src/db/migration-lite.js.map +1 -0
  9. package/out/zero-cache/src/db/migration.d.ts +79 -0
  10. package/out/zero-cache/src/db/migration.d.ts.map +1 -0
  11. package/out/zero-cache/src/db/migration.js +156 -0
  12. package/out/zero-cache/src/db/migration.js.map +1 -0
  13. package/out/zero-cache/src/db/specs.d.ts +1 -1
  14. package/out/zero-cache/src/db/specs.d.ts.map +1 -1
  15. package/out/zero-cache/src/server/main.js +1 -1
  16. package/out/zero-cache/src/server/main.js.map +1 -1
  17. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  18. package/out/zero-cache/src/server/syncer.js +1 -1
  19. package/out/zero-cache/src/server/syncer.js.map +1 -1
  20. package/out/zero-cache/src/services/change-streamer/pg/change-source.js +2 -2
  21. package/out/zero-cache/src/services/change-streamer/pg/change-source.js.map +1 -1
  22. package/out/zero-cache/src/services/change-streamer/pg/initial-sync.d.ts.map +1 -1
  23. package/out/zero-cache/src/services/change-streamer/pg/initial-sync.js +7 -4
  24. package/out/zero-cache/src/services/change-streamer/pg/initial-sync.js.map +1 -1
  25. package/out/zero-cache/src/services/change-streamer/pg/schema/ddl.d.ts.map +1 -1
  26. package/out/zero-cache/src/services/change-streamer/pg/schema/ddl.js +28 -0
  27. package/out/zero-cache/src/services/change-streamer/pg/schema/ddl.js.map +1 -1
  28. package/out/zero-cache/src/services/change-streamer/pg/schema/init.d.ts +5 -0
  29. package/out/zero-cache/src/services/change-streamer/pg/schema/init.d.ts.map +1 -0
  30. package/out/zero-cache/src/services/change-streamer/pg/schema/init.js +18 -0
  31. package/out/zero-cache/src/services/change-streamer/pg/schema/init.js.map +1 -0
  32. package/out/zero-cache/src/services/change-streamer/pg/schema/{zero.d.ts → shard.d.ts} +9 -4
  33. package/out/zero-cache/src/services/change-streamer/pg/schema/shard.d.ts.map +1 -0
  34. package/out/zero-cache/src/services/change-streamer/pg/schema/{zero.js → shard.js} +60 -41
  35. package/out/zero-cache/src/services/change-streamer/pg/schema/shard.js.map +1 -0
  36. package/out/zero-cache/src/services/change-streamer/pg/sync-schema.d.ts.map +1 -1
  37. package/out/zero-cache/src/services/change-streamer/pg/sync-schema.js +12 -6
  38. package/out/zero-cache/src/services/change-streamer/pg/sync-schema.js.map +1 -1
  39. package/out/zero-cache/src/services/change-streamer/schema/init.d.ts +2 -2
  40. package/out/zero-cache/src/services/change-streamer/schema/init.d.ts.map +1 -1
  41. package/out/zero-cache/src/services/change-streamer/schema/init.js +14 -6
  42. package/out/zero-cache/src/services/change-streamer/schema/init.js.map +1 -1
  43. package/out/zero-cache/src/services/change-streamer/schema/tables.js +6 -6
  44. package/out/zero-cache/src/services/change-streamer/storer.js +4 -4
  45. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
  46. package/out/zero-cache/src/services/mutagen/mutagen.js +4 -3
  47. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  48. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
  49. package/out/zero-cache/src/services/replicator/incremental-sync.js +12 -1
  50. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  51. package/out/zero-cache/src/services/replicator/schema/change-log.js +4 -4
  52. package/out/zero-cache/src/services/replicator/schema/replication-state.d.ts +1 -1
  53. package/out/zero-cache/src/services/replicator/schema/replication-state.d.ts.map +1 -1
  54. package/out/zero-cache/src/services/replicator/schema/replication-state.js +9 -9
  55. package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
  56. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +1 -1
  57. package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
  58. package/out/zero-cache/src/services/view-syncer/client-handler.js +6 -3
  59. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  60. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +1 -3
  61. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
  62. package/out/zero-cache/src/services/view-syncer/cvr-store.js +14 -10
  63. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  64. package/out/zero-cache/src/services/view-syncer/cvr.d.ts +10 -7
  65. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
  66. package/out/zero-cache/src/services/view-syncer/cvr.js +21 -12
  67. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  68. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +2 -0
  69. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  70. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +10 -0
  71. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  72. package/out/zero-cache/src/services/view-syncer/schema/cvr.d.ts +2 -1
  73. package/out/zero-cache/src/services/view-syncer/schema/cvr.d.ts.map +1 -1
  74. package/out/zero-cache/src/services/view-syncer/schema/cvr.js +4 -3
  75. package/out/zero-cache/src/services/view-syncer/schema/cvr.js.map +1 -1
  76. package/out/zero-cache/src/services/view-syncer/schema/init.d.ts +4 -0
  77. package/out/zero-cache/src/services/view-syncer/schema/init.d.ts.map +1 -0
  78. package/out/zero-cache/src/services/view-syncer/schema/init.js +16 -0
  79. package/out/zero-cache/src/services/view-syncer/schema/init.js.map +1 -0
  80. package/out/zero-cache/src/services/view-syncer/schema/types.d.ts +0 -208
  81. package/out/zero-cache/src/services/view-syncer/schema/types.d.ts.map +1 -1
  82. package/out/zero-cache/src/services/view-syncer/schema/types.js +0 -2
  83. package/out/zero-cache/src/services/view-syncer/schema/types.js.map +1 -1
  84. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +2 -2
  85. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  86. package/out/zero-cache/src/services/view-syncer/view-syncer.js +56 -35
  87. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  88. package/out/zero-cache/src/types/lite.d.ts.map +1 -1
  89. package/out/zero-cache/src/types/lite.js +8 -9
  90. package/out/zero-cache/src/types/lite.js.map +1 -1
  91. package/out/zero-cache/src/types/pg.d.ts +4 -4
  92. package/out/zero-cache/src/types/pg.d.ts.map +1 -1
  93. package/out/zero-cache/src/types/pg.js +27 -18
  94. package/out/zero-cache/src/types/pg.js.map +1 -1
  95. package/out/zero-cache/src/workers/connection.d.ts +2 -2
  96. package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
  97. package/out/zero-cache/src/workers/connection.js +3 -2
  98. package/out/zero-cache/src/workers/connection.js.map +1 -1
  99. package/out/zero-client/src/mod.d.ts +1 -0
  100. package/out/zero-client/src/mod.d.ts.map +1 -1
  101. package/out/zero-client/src/mod.js +1 -0
  102. package/out/zero-client/src/mod.js.map +1 -1
  103. package/out/zero-react/src/use-query.d.ts.map +1 -1
  104. package/out/zero.js +23 -9
  105. package/out/zero.js.map +3 -3
  106. package/out/zql/src/zql/builder/builder.d.ts +0 -1
  107. package/out/zql/src/zql/builder/builder.d.ts.map +1 -1
  108. package/out/zql/src/zql/builder/builder.js +0 -1
  109. package/out/zql/src/zql/builder/builder.js.map +1 -1
  110. package/out/zql/src/zql/ivm/array-view.d.ts +4 -11
  111. package/out/zql/src/zql/ivm/array-view.d.ts.map +1 -1
  112. package/out/zql/src/zql/ivm/array-view.js +3 -9
  113. package/out/zql/src/zql/ivm/array-view.js.map +1 -1
  114. package/out/zql/src/zql/query/like.d.ts +2 -0
  115. package/out/zql/src/zql/query/like.d.ts.map +1 -0
  116. package/out/zql/src/zql/query/like.js +18 -0
  117. package/out/zql/src/zql/query/like.js.map +1 -0
  118. package/out/zql/src/zql/query/query-impl.js.map +1 -1
  119. package/out/zql/src/zql/query/typed-view.d.ts +5 -2
  120. package/out/zql/src/zql/query/typed-view.d.ts.map +1 -1
  121. package/package.json +1 -1
  122. package/out/zero-cache/src/db/old-migration-lite.d.ts +0 -38
  123. package/out/zero-cache/src/db/old-migration-lite.d.ts.map +0 -1
  124. package/out/zero-cache/src/db/old-migration-lite.js +0 -161
  125. package/out/zero-cache/src/db/old-migration-lite.js.map +0 -1
  126. package/out/zero-cache/src/db/old-migration.d.ts +0 -38
  127. package/out/zero-cache/src/db/old-migration.d.ts.map +0 -1
  128. package/out/zero-cache/src/db/old-migration.js +0 -139
  129. package/out/zero-cache/src/db/old-migration.js.map +0 -1
  130. package/out/zero-cache/src/services/change-streamer/pg/schema/zero.d.ts.map +0 -1
  131. package/out/zero-cache/src/services/change-streamer/pg/schema/zero.js.map +0 -1
  132. package/out/zero-cache/src/services/view-syncer/schema/pg-migrations.d.ts +0 -4
  133. package/out/zero-cache/src/services/view-syncer/schema/pg-migrations.d.ts.map +0 -1
  134. package/out/zero-cache/src/services/view-syncer/schema/pg-migrations.js +0 -12
  135. package/out/zero-cache/src/services/view-syncer/schema/pg-migrations.js.map +0 -1
package/out/react.js CHANGED
@@ -141,7 +141,6 @@ var ViewWrapper = class {
141
141
  }
142
142
  this.#view = this.#query.materialize();
143
143
  this.#view.addListener(this.#onData);
144
- this.#view.hydrate();
145
144
  this.#onMaterialized(this);
146
145
  };
147
146
  getSnapshot = () => this.#snapshot;
package/out/react.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../zero-react/src/use-query.tsx", "../../shared/src/deep-clone.ts", "../../zero-react/src/use-zero.tsx"],
4
- "sourcesContent": ["import {useSyncExternalStore} from 'react';\nimport {deepClone} from '../../shared/src/deep-clone.js';\nimport type {\n Query,\n QueryImpl,\n QueryType,\n Smash,\n TableSchema,\n TypedView,\n} from '../../zero-client/src/mod.js';\nimport type {Immutable} from '../../shared/src/immutable.js';\nimport {useZero} from './use-zero.js';\n\nexport function useQuery<\n TSchema extends TableSchema,\n TReturn extends QueryType,\n>(q: Query<TSchema, TReturn>, enable: boolean = true): Smash<TReturn> {\n const z = useZero();\n const view = viewStore.getView(\n z.clientID,\n q as QueryImpl<TSchema, TReturn>,\n enable,\n );\n // https://react.dev/reference/react/useSyncExternalStore\n return useSyncExternalStore(view.subscribeReactInternals, view.getSnapshot);\n}\n\nconst emptyArray: unknown[] = [];\nconst disabledSubscriber = () => () => {};\n\n/**\n * A global store of all active views.\n *\n * React subscribes and unsubscribes to these views\n * via `useSyncExternalStore`.\n *\n * Managing views through `useEffect` or `useLayoutEffect` causes\n * inconsistencies because effects run after render.\n *\n * For example, if useQuery used use*Effect in the component below:\n * ```ts\n * function Foo({issueID}) {\n * const issue = useQuery(z.query.issue.where('id', issueID).one());\n * if (issue?.id !== undefined && issue.id !== issueID) {\n * console.log('MISMATCH!', issue.id, issueID);\n * }\n * }\n * ```\n *\n * `MISMATCH` will be printed whenever the `issueID` prop changes.\n *\n * This is because the component will render once with\n * the old state returned from `useQuery`. Then the effect inside\n * `useQuery` will run. The component will render again with the new\n * state. This inconsistent transition can cause unexpected results.\n *\n * Emulating `useEffect` via `useState` and `if` causes resource leaks.\n * That is:\n *\n * ```ts\n * function useQuery(q) {\n * const [oldHash, setOldHash] = useState();\n * if (hash(q) !== oldHash) {\n * // make new view\n * }\n *\n * useEffect(() => {\n * return () => view.destroy();\n * }, []);\n * }\n * ```\n *\n * I'm not sure why but in strict mode the cleanup function\n * fails to be called for the first instance of the view and only\n * cleans up later instances.\n *\n * Swapping `useState` to `useRef` has similar problems.\n */\nclass ViewStore {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n #views = new Map<string, ViewWrapper<any, any>>();\n\n getView<TSchema extends TableSchema, TReturn extends QueryType>(\n clientID: string,\n query: QueryImpl<TSchema, TReturn>,\n enabled: boolean,\n ): {\n getSnapshot: () => Smash<TReturn>;\n subscribeReactInternals: (internals: () => void) => () => void;\n } {\n if (!enabled) {\n return {\n getSnapshot: () =>\n (query.singular ? undefined : emptyArray) as Smash<TReturn>,\n subscribeReactInternals: disabledSubscriber,\n };\n }\n\n const hash = JSON.stringify(query.ast) + clientID;\n let existing = this.#views.get(hash);\n if (!existing) {\n existing = new ViewWrapper(\n query,\n view => {\n const lastView = this.#views.get(hash);\n // I don't think this can happen\n // but lets guard against it so we don't\n // leak resources.\n if (lastView && lastView !== view) {\n throw new Error('View already exists');\n }\n this.#views.set(hash, view);\n },\n () => {\n this.#views.delete(hash);\n },\n ) as ViewWrapper<TSchema, TReturn>;\n this.#views.set(hash, existing);\n }\n return existing;\n }\n}\n\nconst viewStore = new ViewStore();\n\n/**\n * This wraps and ref counts a view.\n *\n * The only signal we have from React as to whether or not it is\n * done with a view is when it calls `unsubscribe`.\n *\n * In non-strict-mode we can clean up the view as soon\n * as the listener count goes to 0.\n *\n * In strict-mode, the listener cound will go to 0 then a\n * new listener for the same view is immeidatiely added back.\n *\n * This is why the `onMaterialized` and `onDematerialized` callbacks exist --\n * they allow a view which React is still referencing to be added\n * back into the store when React re-subscribes to it.\n *\n * This wrapper also exists to deal with the various\n * `useSyncExternalStore` caveats that cause excessive\n * re-renders and materializations.\n *\n * See: https://react.dev/reference/react/useSyncExternalStore#caveats\n * Especially:\n * 1. The store snapshot returned by getSnapshot must be immutable. If the underlying store has mutable data, return a new immutable snapshot if the data has changed. Otherwise, return a cached last snapshot.\n * 2. If a different subscribe function is passed during a re-render, React will re-subscribe to the store using the newly passed subscribe function. You can prevent this by declaring subscribe outside the component.\n */\nclass ViewWrapper<TSchema extends TableSchema, TReturn extends QueryType> {\n #view: TypedView<Smash<TReturn>> | undefined;\n readonly #defaultSnapshot: Smash<TReturn>;\n readonly #onDematerialized;\n readonly #onMaterialized;\n readonly #query: QueryImpl<TSchema, TReturn>;\n #snapshot: Smash<TReturn>;\n #reactInternals: Set<() => void>;\n\n constructor(\n query: QueryImpl<TSchema, TReturn>,\n onMaterialized: (view: ViewWrapper<TSchema, TReturn>) => void,\n onDematerialized: () => void,\n ) {\n this.#defaultSnapshot = (query.singular\n ? undefined\n : emptyArray) as unknown as Smash<TReturn>;\n this.#snapshot = this.#defaultSnapshot;\n this.#onMaterialized = onMaterialized;\n this.#onDematerialized = onDematerialized;\n this.#reactInternals = new Set();\n this.#query = query;\n }\n\n #onData = (snap: Immutable<Smash<TReturn>>) => {\n this.#snapshot = (\n snap === undefined ? snap : deepClone(snap)\n ) as Smash<TReturn>;\n for (const internals of this.#reactInternals) {\n internals();\n }\n };\n\n #materializeIfNeeded = () => {\n if (this.#view) {\n return;\n }\n\n this.#view = this.#query.materialize();\n this.#view.addListener(this.#onData);\n this.#view.hydrate();\n\n this.#onMaterialized(this);\n };\n\n getSnapshot = () => this.#snapshot;\n\n subscribeReactInternals = (internals: () => void): (() => void) => {\n this.#reactInternals.add(internals);\n this.#materializeIfNeeded();\n return () => {\n this.#reactInternals.delete(internals);\n if (this.#reactInternals.size === 0) {\n this.#view?.destroy();\n this.#view = undefined;\n this.#onDematerialized();\n }\n };\n };\n}\n", "import {hasOwn} from './has-own.js';\nimport type {JSONValue, ReadonlyJSONValue} from './json.js';\n\nexport function deepClone(value: ReadonlyJSONValue): JSONValue {\n const seen: Array<ReadonlyJSONValue> = [];\n return internalDeepClone(value, seen);\n}\n\nexport function internalDeepClone(\n value: ReadonlyJSONValue,\n seen: Array<ReadonlyJSONValue>,\n): JSONValue {\n switch (typeof value) {\n case 'boolean':\n case 'number':\n case 'string':\n case 'undefined':\n return value;\n case 'object': {\n if (value === null) {\n return null;\n }\n if (seen.includes(value)) {\n throw new Error('Cyclic object');\n }\n seen.push(value);\n if (Array.isArray(value)) {\n const rv = value.map(v => internalDeepClone(v, seen));\n seen.pop();\n return rv;\n }\n\n const obj: JSONValue = {};\n\n for (const k in value) {\n if (hasOwn(value, k)) {\n const v = (value as Record<string, ReadonlyJSONValue>)[k];\n if (v !== undefined) {\n obj[k] = internalDeepClone(v, seen);\n }\n }\n }\n seen.pop();\n return obj;\n }\n\n default:\n throw new Error(`Invalid type: ${typeof value}`);\n }\n}\n", "import {createContext, useContext} from 'react';\nimport type {Schema, Zero} from '../../zero-client/src/mod.js';\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst ZeroContext = createContext<Zero<Schema> | undefined>(undefined);\n\nexport function useZero<S extends Schema>(): Zero<S> {\n const zero = useContext(ZeroContext);\n if (zero === undefined) {\n throw new Error('useZero must be used within a ZeroProvider');\n }\n return zero as Zero<S>;\n}\n\nexport function createUseZero<S extends Schema>() {\n return () => useZero<S>();\n}\n\nexport function ZeroProvider<S extends Schema>({\n children,\n zero,\n}: {\n children: React.ReactNode;\n zero: Zero<S>;\n}) {\n return (\n <ZeroContext.Provider value={zero as Zero<Schema>}>\n {children}\n </ZeroContext.Provider>\n );\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {useSyncExternalStore} from 'react';\nimport {deepClone} from '../../shared/src/deep-clone.js';\nimport type {Immutable} from '../../shared/src/immutable.js';\nimport type {\n Query,\n QueryImpl,\n QueryType,\n Smash,\n TableSchema,\n TypedView,\n} from '../../zero-client/src/mod.js';\nimport {useZero} from './use-zero.js';\n\nexport function useQuery<\n TSchema extends TableSchema,\n TReturn extends QueryType,\n>(q: Query<TSchema, TReturn>, enable: boolean = true): Smash<TReturn> {\n const z = useZero();\n const view = viewStore.getView(\n z.clientID,\n q as QueryImpl<TSchema, TReturn>,\n enable,\n );\n // https://react.dev/reference/react/useSyncExternalStore\n return useSyncExternalStore(view.subscribeReactInternals, view.getSnapshot);\n}\n\nconst emptyArray: unknown[] = [];\nconst disabledSubscriber = () => () => {};\n\n/**\n * A global store of all active views.\n *\n * React subscribes and unsubscribes to these views\n * via `useSyncExternalStore`.\n *\n * Managing views through `useEffect` or `useLayoutEffect` causes\n * inconsistencies because effects run after render.\n *\n * For example, if useQuery used use*Effect in the component below:\n * ```ts\n * function Foo({issueID}) {\n * const issue = useQuery(z.query.issue.where('id', issueID).one());\n * if (issue?.id !== undefined && issue.id !== issueID) {\n * console.log('MISMATCH!', issue.id, issueID);\n * }\n * }\n * ```\n *\n * `MISMATCH` will be printed whenever the `issueID` prop changes.\n *\n * This is because the component will render once with\n * the old state returned from `useQuery`. Then the effect inside\n * `useQuery` will run. The component will render again with the new\n * state. This inconsistent transition can cause unexpected results.\n *\n * Emulating `useEffect` via `useState` and `if` causes resource leaks.\n * That is:\n *\n * ```ts\n * function useQuery(q) {\n * const [oldHash, setOldHash] = useState();\n * if (hash(q) !== oldHash) {\n * // make new view\n * }\n *\n * useEffect(() => {\n * return () => view.destroy();\n * }, []);\n * }\n * ```\n *\n * I'm not sure why but in strict mode the cleanup function\n * fails to be called for the first instance of the view and only\n * cleans up later instances.\n *\n * Swapping `useState` to `useRef` has similar problems.\n */\nclass ViewStore {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n #views = new Map<string, ViewWrapper<any, any>>();\n\n getView<TSchema extends TableSchema, TReturn extends QueryType>(\n clientID: string,\n query: QueryImpl<TSchema, TReturn>,\n enabled: boolean,\n ): {\n getSnapshot: () => Smash<TReturn>;\n subscribeReactInternals: (internals: () => void) => () => void;\n } {\n if (!enabled) {\n return {\n getSnapshot: () =>\n (query.singular ? undefined : emptyArray) as Smash<TReturn>,\n subscribeReactInternals: disabledSubscriber,\n };\n }\n\n const hash = JSON.stringify(query.ast) + clientID;\n let existing = this.#views.get(hash);\n if (!existing) {\n existing = new ViewWrapper(\n query,\n view => {\n const lastView = this.#views.get(hash);\n // I don't think this can happen\n // but lets guard against it so we don't\n // leak resources.\n if (lastView && lastView !== view) {\n throw new Error('View already exists');\n }\n this.#views.set(hash, view);\n },\n () => {\n this.#views.delete(hash);\n },\n ) as ViewWrapper<TSchema, TReturn>;\n this.#views.set(hash, existing);\n }\n return existing;\n }\n}\n\nconst viewStore = new ViewStore();\n\n/**\n * This wraps and ref counts a view.\n *\n * The only signal we have from React as to whether or not it is\n * done with a view is when it calls `unsubscribe`.\n *\n * In non-strict-mode we can clean up the view as soon\n * as the listener count goes to 0.\n *\n * In strict-mode, the listener cound will go to 0 then a\n * new listener for the same view is immeidatiely added back.\n *\n * This is why the `onMaterialized` and `onDematerialized` callbacks exist --\n * they allow a view which React is still referencing to be added\n * back into the store when React re-subscribes to it.\n *\n * This wrapper also exists to deal with the various\n * `useSyncExternalStore` caveats that cause excessive\n * re-renders and materializations.\n *\n * See: https://react.dev/reference/react/useSyncExternalStore#caveats\n * Especially:\n * 1. The store snapshot returned by getSnapshot must be immutable. If the underlying store has mutable data, return a new immutable snapshot if the data has changed. Otherwise, return a cached last snapshot.\n * 2. If a different subscribe function is passed during a re-render, React will re-subscribe to the store using the newly passed subscribe function. You can prevent this by declaring subscribe outside the component.\n */\nclass ViewWrapper<TSchema extends TableSchema, TReturn extends QueryType> {\n #view: TypedView<Smash<TReturn>> | undefined;\n readonly #defaultSnapshot: Smash<TReturn>;\n readonly #onDematerialized;\n readonly #onMaterialized;\n readonly #query: QueryImpl<TSchema, TReturn>;\n #snapshot: Smash<TReturn>;\n #reactInternals: Set<() => void>;\n\n constructor(\n query: QueryImpl<TSchema, TReturn>,\n onMaterialized: (view: ViewWrapper<TSchema, TReturn>) => void,\n onDematerialized: () => void,\n ) {\n this.#defaultSnapshot = (query.singular\n ? undefined\n : emptyArray) as unknown as Smash<TReturn>;\n this.#snapshot = this.#defaultSnapshot;\n this.#onMaterialized = onMaterialized;\n this.#onDematerialized = onDematerialized;\n this.#reactInternals = new Set();\n this.#query = query;\n }\n\n #onData = (snap: Immutable<Smash<TReturn>>) => {\n this.#snapshot = (\n snap === undefined ? snap : deepClone(snap)\n ) as Smash<TReturn>;\n for (const internals of this.#reactInternals) {\n internals();\n }\n };\n\n #materializeIfNeeded = () => {\n if (this.#view) {\n return;\n }\n\n this.#view = this.#query.materialize();\n this.#view.addListener(this.#onData);\n\n this.#onMaterialized(this);\n };\n\n getSnapshot = () => this.#snapshot;\n\n subscribeReactInternals = (internals: () => void): (() => void) => {\n this.#reactInternals.add(internals);\n this.#materializeIfNeeded();\n return () => {\n this.#reactInternals.delete(internals);\n if (this.#reactInternals.size === 0) {\n this.#view?.destroy();\n this.#view = undefined;\n this.#onDematerialized();\n }\n };\n };\n}\n", "import {hasOwn} from './has-own.js';\nimport type {JSONValue, ReadonlyJSONValue} from './json.js';\n\nexport function deepClone(value: ReadonlyJSONValue): JSONValue {\n const seen: Array<ReadonlyJSONValue> = [];\n return internalDeepClone(value, seen);\n}\n\nexport function internalDeepClone(\n value: ReadonlyJSONValue,\n seen: Array<ReadonlyJSONValue>,\n): JSONValue {\n switch (typeof value) {\n case 'boolean':\n case 'number':\n case 'string':\n case 'undefined':\n return value;\n case 'object': {\n if (value === null) {\n return null;\n }\n if (seen.includes(value)) {\n throw new Error('Cyclic object');\n }\n seen.push(value);\n if (Array.isArray(value)) {\n const rv = value.map(v => internalDeepClone(v, seen));\n seen.pop();\n return rv;\n }\n\n const obj: JSONValue = {};\n\n for (const k in value) {\n if (hasOwn(value, k)) {\n const v = (value as Record<string, ReadonlyJSONValue>)[k];\n if (v !== undefined) {\n obj[k] = internalDeepClone(v, seen);\n }\n }\n }\n seen.pop();\n return obj;\n }\n\n default:\n throw new Error(`Invalid type: ${typeof value}`);\n }\n}\n", "import {createContext, useContext} from 'react';\nimport type {Schema, Zero} from '../../zero-client/src/mod.js';\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst ZeroContext = createContext<Zero<Schema> | undefined>(undefined);\n\nexport function useZero<S extends Schema>(): Zero<S> {\n const zero = useContext(ZeroContext);\n if (zero === undefined) {\n throw new Error('useZero must be used within a ZeroProvider');\n }\n return zero as Zero<S>;\n}\n\nexport function createUseZero<S extends Schema>() {\n return () => useZero<S>();\n}\n\nexport function ZeroProvider<S extends Schema>({\n children,\n zero,\n}: {\n children: React.ReactNode;\n zero: Zero<S>;\n}) {\n return (\n <ZeroContext.Provider value={zero as Zero<Schema>}>\n {children}\n </ZeroContext.Provider>\n );\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -34,6 +34,6 @@ export function createIndexStatement(index) {
34
34
  .map(([name, dir]) => `${id(name)} ${dir}`)
35
35
  .join(',');
36
36
  const unique = index.unique ? 'UNIQUE' : '';
37
- return `CREATE ${unique} INDEX ${id(index.name)} ON ${id(index.tableName)} (${columns})`;
37
+ return `CREATE ${unique} INDEX ${id(index.name)} ON ${id(index.tableName)} (${columns});`;
38
38
  }
39
39
  //# sourceMappingURL=create.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"create.js","sourceRoot":"","sources":["../../../../../zero-cache/src/db/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,EAAE,EAAE,MAAM,EAAC,MAAM,iBAAiB,CAAC;AAQ3C,MAAM,UAAU,SAAS,CAAC,IAAgB;IACxC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9B,IAAI,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,sBAAsB,GAAG,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC1B,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAA+B;IAClE,qEAAqE;IACrE,uEAAuE;IACvE,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;SACtC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAC,GAAG,EAAE,CAAC,EAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAC,GAAG,EAAE,CAAC,EAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;SAC/C,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,EAAC,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,EAAC,CAAC,EAAE,CAAC,CAAC;IAC5E,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,IAAI,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,UAAU,GACd,QAAQ,IAAI,IAAI;QACd,CAAC,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;QACtD,CAAC,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACxC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAoB;IACvD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;SAC1C,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;SAC1C,IAAI,CAAC,GAAG,CAAC,CAAC;IACb,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5C,OAAO,UAAU,MAAM,UAAU,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CACtD,KAAK,CAAC,SAAS,CAChB,KAAK,OAAO,GAAG,CAAC;AACnB,CAAC"}
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../../../../zero-cache/src/db/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,EAAE,EAAE,MAAM,EAAC,MAAM,iBAAiB,CAAC;AAQ3C,MAAM,UAAU,SAAS,CAAC,IAAgB;IACxC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9B,IAAI,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,sBAAsB,GAAG,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC1B,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAA+B;IAClE,qEAAqE;IACrE,uEAAuE;IACvE,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;SACtC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAC,GAAG,EAAE,CAAC,EAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAC,GAAG,EAAE,CAAC,EAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;SAC/C,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,EAAC,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,EAAC,CAAC,EAAE,CAAC,CAAC;IAC5E,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,IAAI,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,UAAU,GACd,QAAQ,IAAI,IAAI;QACd,CAAC,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;QACtD,CAAC,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACxC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAoB;IACvD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;SAC1C,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;SAC1C,IAAI,CAAC,GAAG,CAAC,CAAC;IACb,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5C,OAAO,UAAU,MAAM,UAAU,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CACtD,KAAK,CAAC,SAAS,CAChB,KAAK,OAAO,IAAI,CAAC;AACpB,CAAC"}
@@ -0,0 +1,78 @@
1
+ import type { LogContext } from '@rocicorp/logger';
2
+ import * as v from '../../../shared/src/valita.js';
3
+ import type { Database as Db } from '../../../zqlite/src/db.js';
4
+ type Operations = (log: LogContext, tx: Db) => Promise<void> | void;
5
+ /**
6
+ * Encapsulates the logic for setting up or upgrading to a new schema. After the
7
+ * Migration code successfully completes, {@link runSchemaMigrations}
8
+ * will update the schema version and commit the transaction.
9
+ */
10
+ export type Migration = {
11
+ /**
12
+ * Perform database operations that create or alter table structure. This is
13
+ * called at most once during lifetime of the application. If a `migrateData()`
14
+ * operation is defined, that will be performed after `migrateSchema()` succeeds.
15
+ */
16
+ migrateSchema?: Operations;
17
+ /**
18
+ * Perform database operations to migrate data to the new schema. This is
19
+ * called after `migrateSchema()` (if defined), and may be called again
20
+ * to re-migrate data after the server was rolled back to an earlier version,
21
+ * and rolled forward again.
22
+ *
23
+ * Consequently, the logic in `migrateData()` must be idempotent.
24
+ */
25
+ migrateData?: Operations;
26
+ /**
27
+ * Sets the `minSafeVersion` to the specified value, prohibiting running
28
+ * any earlier code versions.
29
+ */
30
+ minSafeVersion?: number;
31
+ };
32
+ /**
33
+ * Mapping of incremental migrations to move from the previous old code
34
+ * version to next one. Versions must be non-zero.
35
+ *
36
+ * The schema resulting from performing incremental migrations should be
37
+ * equivalent to that of the `setupMigration` on a blank database.
38
+ *
39
+ * The highest destinationVersion of this map denotes the current
40
+ * "code version", and is also used as the destination version when
41
+ * running the initial setup migration on a blank database.
42
+ */
43
+ export type IncrementalMigrationMap = {
44
+ [destinationVersion: number]: Migration;
45
+ };
46
+ /**
47
+ * Ensures that the schema is compatible with the current code, updating and
48
+ * migrating the schema if necessary.
49
+ */
50
+ export declare function runSchemaMigrations(log: LogContext, debugName: string, dbPath: string, setupMigration: Migration, incrementalMigrationMap: IncrementalMigrationMap): Promise<void>;
51
+ export declare const versionHistory: v.ObjectType<{
52
+ /**
53
+ * The `schemaVersion` is highest code version that has ever been run
54
+ * on the database, and is used to delineate the structure of the tables
55
+ * in the database. A schemaVersion only moves forward; rolling back to
56
+ * an earlier (safe) code version does not revert schema changes that
57
+ * have already been applied.
58
+ */
59
+ schemaVersion: v.Type<number>;
60
+ /**
61
+ * The data version is the code version of the latest server that ran.
62
+ * Note that this may be less than the schemaVersion in the case that
63
+ * a server is rolled back to an earlier version after a schema change.
64
+ * In such a case, data (but not schema), may need to be re-migrated
65
+ * when rolling forward again.
66
+ */
67
+ dataVersion: v.Type<number>;
68
+ /**
69
+ * The minimum code version that is safe to run. This is used when
70
+ * a schema migration is not backwards compatible with an older version
71
+ * of the code.
72
+ */
73
+ minSafeVersion: v.Type<number>;
74
+ }, undefined>;
75
+ export type VersionHistory = v.Infer<typeof versionHistory>;
76
+ export declare function getVersionHistory(db: Db): VersionHistory;
77
+ export {};
78
+ //# sourceMappingURL=migration-lite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-lite.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/migration-lite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAGjD,OAAO,KAAK,CAAC,MAAM,+BAA+B,CAAC;AACnD,OAAO,KAAK,EAAC,QAAQ,IAAI,EAAE,EAAC,MAAM,2BAA2B,CAAC;AAG9D,KAAK,UAAU,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAEpE;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,UAAU,CAAC;IAE3B;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,UAAU,CAAC;IAEzB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC,CAAC;AAEF;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,UAAU,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,SAAS,EACzB,uBAAuB,EAAE,uBAAuB,GAC/C,OAAO,CAAC,IAAI,CAAC,CAoFf;AAaD,eAAO,MAAM,cAAc;IACzB;;;;;;OAMG;;IAGH;;;;;;OAMG;;IAGH;;;;OAIG;;aAEH,CAAC;AAGH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAG5D,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,EAAE,GAAG,cAAc,CAmBxD"}
@@ -0,0 +1,181 @@
1
+ import { assert } from '../../../shared/src/asserts.js';
2
+ import { randInt } from '../../../shared/src/rand.js';
3
+ import * as v from '../../../shared/src/valita.js';
4
+ import { Database } from '../../../zqlite/src/db.js';
5
+ /**
6
+ * Ensures that the schema is compatible with the current code, updating and
7
+ * migrating the schema if necessary.
8
+ */
9
+ export async function runSchemaMigrations(log, debugName, dbPath, setupMigration, incrementalMigrationMap) {
10
+ log = log.withContext('initSchema', randInt(0, Number.MAX_SAFE_INTEGER).toString(36));
11
+ const db = new Database(log, dbPath);
12
+ db.pragma('foreign_keys = OFF');
13
+ try {
14
+ const versionMigrations = sorted(incrementalMigrationMap);
15
+ assert(versionMigrations.length, `Must specify a at least one version migration`);
16
+ assert(versionMigrations[0][0] > 0, `Versions must be non-zero positive numbers`);
17
+ const codeVersion = versionMigrations[versionMigrations.length - 1][0];
18
+ log.info?.(`Checking schema for compatibility with ${debugName} at schema v${codeVersion}`);
19
+ let versions = await runTransaction(log, db, tx => {
20
+ const versions = getVersionHistory(tx);
21
+ if (codeVersion < versions.minSafeVersion) {
22
+ throw new Error(`Cannot run ${debugName} at schema v${codeVersion} because rollback limit is v${versions.minSafeVersion}`);
23
+ }
24
+ if (versions.dataVersion > codeVersion) {
25
+ log.info?.(`Data is at v${versions.dataVersion}. Resetting to v${codeVersion}`);
26
+ return updateVersionHistory(log, tx, versions, codeVersion);
27
+ }
28
+ return versions;
29
+ });
30
+ if (versions.dataVersion < codeVersion) {
31
+ const migrations = versions.dataVersion === 0
32
+ ? // For the empty database v0, only run the setup migration.
33
+ [[codeVersion, setupMigration]]
34
+ : versionMigrations;
35
+ for (const [dest, migration] of migrations) {
36
+ if (versions.dataVersion < dest) {
37
+ log.info?.(`Migrating schema from v${versions.dataVersion} to v${dest}`);
38
+ void log.flush(); // Flush logs before each migration to help debug crash-y migrations.
39
+ db.pragma('synchronous = OFF'); // For schema migrations we'll wait for the disk flush after the migration.
40
+ versions = await runTransaction(log, db, async (tx) => {
41
+ // Fetch meta from within the transaction to make the migration atomic.
42
+ let versions = getVersionHistory(tx);
43
+ if (versions.dataVersion < dest) {
44
+ versions = await runMigration(log, tx, versions, dest, migration);
45
+ assert(versions.dataVersion === dest);
46
+ }
47
+ return versions;
48
+ });
49
+ db.pragma('synchronous = NORMAL');
50
+ db.exec('VACUUM');
51
+ log.info?.('VACUUM completed');
52
+ db.exec('ANALYZE main');
53
+ log.info?.('ANALYZE completed');
54
+ }
55
+ }
56
+ }
57
+ assert(versions.dataVersion === codeVersion);
58
+ log.info?.(`Running ${debugName} at schema v${codeVersion}`);
59
+ }
60
+ catch (e) {
61
+ log.error?.('Error in ensureSchemaMigrated', e);
62
+ throw e;
63
+ }
64
+ finally {
65
+ db.close();
66
+ void log.flush(); // Flush the logs but do not block server progress on it.
67
+ }
68
+ }
69
+ function sorted(incrementalMigrationMap) {
70
+ const versionMigrations = [];
71
+ for (const [v, m] of Object.entries(incrementalMigrationMap)) {
72
+ versionMigrations.push([Number(v), m]);
73
+ }
74
+ return versionMigrations.sort(([a], [b]) => a - b);
75
+ }
76
+ // Exposed for tests.
77
+ export const versionHistory = v.object({
78
+ /**
79
+ * The `schemaVersion` is highest code version that has ever been run
80
+ * on the database, and is used to delineate the structure of the tables
81
+ * in the database. A schemaVersion only moves forward; rolling back to
82
+ * an earlier (safe) code version does not revert schema changes that
83
+ * have already been applied.
84
+ */
85
+ schemaVersion: v.number(),
86
+ /**
87
+ * The data version is the code version of the latest server that ran.
88
+ * Note that this may be less than the schemaVersion in the case that
89
+ * a server is rolled back to an earlier version after a schema change.
90
+ * In such a case, data (but not schema), may need to be re-migrated
91
+ * when rolling forward again.
92
+ */
93
+ dataVersion: v.number(),
94
+ /**
95
+ * The minimum code version that is safe to run. This is used when
96
+ * a schema migration is not backwards compatible with an older version
97
+ * of the code.
98
+ */
99
+ minSafeVersion: v.number(),
100
+ });
101
+ // Exposed for tests
102
+ export function getVersionHistory(db) {
103
+ // Note: The `lock` column transparently ensures that at most one row exists.
104
+ db.prepare(`
105
+ CREATE TABLE IF NOT EXISTS "_zero.versionHistory" (
106
+ dataVersion INTEGER NOT NULL,
107
+ schemaVersion INTEGER NOT NULL,
108
+ minSafeVersion INTEGER NOT NULL,
109
+
110
+ lock INTEGER PRIMARY KEY DEFAULT 1 CHECK (lock=1)
111
+ );
112
+ `).run();
113
+ const result = db
114
+ .prepare('SELECT dataVersion, schemaVersion, minSafeVersion FROM "_zero.versionHistory"')
115
+ .get();
116
+ return result ?? { dataVersion: 0, schemaVersion: 0, minSafeVersion: 0 };
117
+ }
118
+ function updateVersionHistory(log, db, prev, newVersion, minSafeVersion) {
119
+ assert(newVersion > 0);
120
+ const meta = {
121
+ ...prev,
122
+ dataVersion: newVersion,
123
+ // The schemaVersion never moves backwards.
124
+ schemaVersion: Math.max(newVersion, prev.schemaVersion),
125
+ minSafeVersion: getMinSafeVersion(log, prev, minSafeVersion),
126
+ };
127
+ db.prepare(`
128
+ INSERT INTO "_zero.versionHistory" (dataVersion, schemaVersion, minSafeVersion, lock)
129
+ VALUES (@dataVersion, @schemaVersion, @minSafeVersion, 1)
130
+ ON CONFLICT (lock) DO UPDATE
131
+ SET dataVersion=@dataVersion,
132
+ schemaVersion=@schemaVersion,
133
+ minSafeVersion=@minSafeVersion
134
+ `).run(meta);
135
+ return meta;
136
+ }
137
+ async function runMigration(log, tx, versions, destinationVersion, migration) {
138
+ if (versions.schemaVersion < destinationVersion) {
139
+ await migration.migrateSchema?.(log, tx);
140
+ }
141
+ if (versions.dataVersion < destinationVersion) {
142
+ await migration.migrateData?.(log, tx);
143
+ }
144
+ return updateVersionHistory(log, tx, versions, destinationVersion, migration.minSafeVersion);
145
+ }
146
+ /**
147
+ * Bumps the rollback limit [[toAtLeast]] the specified version.
148
+ * Leaves the rollback limit unchanged if it is equal or greater.
149
+ */
150
+ function getMinSafeVersion(log, current, proposedSafeVersion) {
151
+ if (proposedSafeVersion === undefined) {
152
+ return current.minSafeVersion;
153
+ }
154
+ // Sanity check to maintain the invariant that running code is never
155
+ // earlier than the rollback limit.
156
+ assert(proposedSafeVersion <= current.dataVersion + 1);
157
+ if (current.minSafeVersion >= proposedSafeVersion) {
158
+ // The rollback limit must never move backwards.
159
+ log.debug?.(`rollback limit is already at ${current.minSafeVersion}, ` +
160
+ `don't need to bump to ${proposedSafeVersion}`);
161
+ return current.minSafeVersion;
162
+ }
163
+ log.info?.(`bumping rollback limit from ${current.minSafeVersion} to ${proposedSafeVersion}`);
164
+ return proposedSafeVersion;
165
+ }
166
+ // Note: We use a custom transaction wrapper (instead of db.begin(...)) in order
167
+ // to support async operations within the transaction.
168
+ async function runTransaction(log, db, tx) {
169
+ db.prepare('BEGIN EXCLUSIVE').run();
170
+ try {
171
+ const result = await tx(db);
172
+ db.prepare('COMMIT').run();
173
+ return result;
174
+ }
175
+ catch (e) {
176
+ db.prepare('ROLLBACK').run();
177
+ log.error?.('Aborted transaction due to error', e);
178
+ throw e;
179
+ }
180
+ }
181
+ //# sourceMappingURL=migration-lite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-lite.js","sourceRoot":"","sources":["../../../../../zero-cache/src/db/migration-lite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ import type { LogContext } from '@rocicorp/logger';
2
+ import type postgres from 'postgres';
3
+ import * as v from '../../../shared/src/valita.js';
4
+ import type { PostgresDB, PostgresTransaction } from '../types/pg.js';
5
+ type Operations = (log: LogContext, tx: PostgresTransaction) => Promise<void>;
6
+ /**
7
+ * Encapsulates the logic for setting up or upgrading to a new schema. After the
8
+ * Migration code successfully completes, {@link runSchemaMigrations}
9
+ * will update the schema version and commit the transaction.
10
+ */
11
+ export type Migration = {
12
+ /**
13
+ * Perform database operations that create or alter table structure. This is
14
+ * called at most once during lifetime of the application. If a `migrateData()`
15
+ * operation is defined, that will be performed after `migrateSchema()` succeeds.
16
+ */
17
+ migrateSchema?: Operations;
18
+ /**
19
+ * Perform database operations to migrate data to the new schema. This is
20
+ * called after `migrateSchema()` (if defined), and may be called again
21
+ * to re-migrate data after the server was rolled back to an earlier version,
22
+ * and rolled forward again.
23
+ *
24
+ * Consequently, the logic in `migrateData()` must be idempotent.
25
+ */
26
+ migrateData?: Operations;
27
+ /**
28
+ * Sets the `minSafeVersion` to the specified value, prohibiting running
29
+ * any earlier code versions.
30
+ */
31
+ minSafeVersion?: number;
32
+ };
33
+ /**
34
+ * Mapping of incremental migrations to move from the previous old code
35
+ * version to next one. Versions must be non-zero.
36
+ *
37
+ * The schema resulting from performing incremental migrations should be
38
+ * equivalent to that of the `setupMigration` on a blank database.
39
+ *
40
+ * The highest destinationVersion of this map denotes the current
41
+ * "code version", and is also used as the destination version when
42
+ * running the initial setup migration on a blank database.
43
+ */
44
+ export type IncrementalMigrationMap = {
45
+ [destinationVersion: number]: Migration;
46
+ };
47
+ /**
48
+ * Ensures that the schema is compatible with the current code, updating and
49
+ * migrating the schema if necessary.
50
+ */
51
+ export declare function runSchemaMigrations(log: LogContext, debugName: string, schemaName: string, db: PostgresDB, setupMigration: Migration, incrementalMigrationMap: IncrementalMigrationMap): Promise<void>;
52
+ export declare const versionHistory: v.ObjectType<{
53
+ /**
54
+ * The `schemaVersion` is highest code version that has ever been run
55
+ * on the database, and is used to delineate the structure of the tables
56
+ * in the database. A schemaVersion only moves forward; rolling back to
57
+ * an earlier (safe) code version does not revert schema changes that
58
+ * have already been applied.
59
+ */
60
+ schemaVersion: v.Type<number>;
61
+ /**
62
+ * The data version is the code version of the latest server that ran.
63
+ * Note that this may be less than the schemaVersion in the case that
64
+ * a server is rolled back to an earlier version after a schema change.
65
+ * In such a case, data (but not schema), may need to be re-migrated
66
+ * when rolling forward again.
67
+ */
68
+ dataVersion: v.Type<number>;
69
+ /**
70
+ * The minimum code version that is safe to run. This is used when
71
+ * a schema migration is not backwards compatible with an older version
72
+ * of the code.
73
+ */
74
+ minSafeVersion: v.Type<number>;
75
+ }, undefined>;
76
+ export type VersionHistory = v.Infer<typeof versionHistory>;
77
+ export declare function getVersionHistory(sql: postgres.Sql, schemaName: string): Promise<VersionHistory>;
78
+ export {};
79
+ //# sourceMappingURL=migration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/migration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAC;AAGrC,OAAO,KAAK,CAAC,MAAM,+BAA+B,CAAC;AACnD,OAAO,KAAK,EAAC,UAAU,EAAE,mBAAmB,EAAC,MAAM,gBAAgB,CAAC;AAEpE,KAAK,UAAU,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9E;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,UAAU,CAAC;IAE3B;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,UAAU,CAAC;IAEzB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC,CAAC;AAEF;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,UAAU,EACf,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,UAAU,EACd,cAAc,EAAE,SAAS,EACzB,uBAAuB,EAAE,uBAAuB,GAC/C,OAAO,CAAC,IAAI,CAAC,CA+Ef;AAaD,eAAO,MAAM,cAAc;IACzB;;;;;;OAMG;;IAGH;;;;;;OAMG;;IAGH;;;;OAIG;;aAEH,CAAC;AAGH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAG5D,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,QAAQ,CAAC,GAAG,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,cAAc,CAAC,CAsBzB"}
@@ -0,0 +1,156 @@
1
+ import { assert } from '../../../shared/src/asserts.js';
2
+ import { randInt } from '../../../shared/src/rand.js';
3
+ import * as v from '../../../shared/src/valita.js';
4
+ /**
5
+ * Ensures that the schema is compatible with the current code, updating and
6
+ * migrating the schema if necessary.
7
+ */
8
+ export async function runSchemaMigrations(log, debugName, schemaName, db, setupMigration, incrementalMigrationMap) {
9
+ log = log.withContext('initSchema', randInt(0, Number.MAX_SAFE_INTEGER).toString(36));
10
+ try {
11
+ const versionMigrations = sorted(incrementalMigrationMap);
12
+ assert(versionMigrations.length, `Must specify at least one version migration`);
13
+ assert(versionMigrations[0][0] > 0, `Versions must be non-zero positive numbers`);
14
+ const codeVersion = versionMigrations[versionMigrations.length - 1][0];
15
+ log.info?.(`Checking schema for compatibility with ${debugName} at schema v${codeVersion}`);
16
+ let versions = await db.begin(async (tx) => {
17
+ const versions = await getVersionHistory(tx, schemaName);
18
+ if (codeVersion < versions.minSafeVersion) {
19
+ throw new Error(`Cannot run ${debugName} at schema v${codeVersion} because rollback limit is v${versions.minSafeVersion}`);
20
+ }
21
+ if (versions.dataVersion > codeVersion) {
22
+ log.info?.(`Data is at v${versions.dataVersion}. Resetting to v${codeVersion}`);
23
+ return updateVersionHistory(log, tx, schemaName, versions, codeVersion);
24
+ }
25
+ return versions;
26
+ });
27
+ if (versions.dataVersion < codeVersion) {
28
+ const migrations = versions.dataVersion === 0
29
+ ? // For the empty database v0, only run the setup migration.
30
+ [[codeVersion, setupMigration]]
31
+ : versionMigrations;
32
+ for (const [dest, migration] of migrations) {
33
+ if (versions.dataVersion < dest) {
34
+ log.info?.(`Migrating schema from v${versions.dataVersion} to v${dest}`);
35
+ void log.flush(); // Flush logs before each migration to help debug crash-y migrations.
36
+ versions = await db.begin(async (tx) => {
37
+ // Fetch meta from within the transaction to make the migration atomic.
38
+ let versions = await getVersionHistory(tx, schemaName);
39
+ if (versions.dataVersion < dest) {
40
+ versions = await runMigration(log, schemaName, tx, versions, dest, migration);
41
+ assert(versions.dataVersion === dest);
42
+ }
43
+ return versions;
44
+ });
45
+ }
46
+ }
47
+ }
48
+ assert(versions.dataVersion === codeVersion);
49
+ log.info?.(`Running ${debugName} at schema v${codeVersion}`);
50
+ }
51
+ catch (e) {
52
+ log.error?.('Error in ensureSchemaMigrated', e);
53
+ throw e;
54
+ }
55
+ finally {
56
+ void log.flush(); // Flush the logs but do not block server progress on it.
57
+ }
58
+ }
59
+ function sorted(incrementalMigrationMap) {
60
+ const versionMigrations = [];
61
+ for (const [v, m] of Object.entries(incrementalMigrationMap)) {
62
+ versionMigrations.push([Number(v), m]);
63
+ }
64
+ return versionMigrations.sort(([a], [b]) => a - b);
65
+ }
66
+ // Exposed for tests.
67
+ export const versionHistory = v.object({
68
+ /**
69
+ * The `schemaVersion` is highest code version that has ever been run
70
+ * on the database, and is used to delineate the structure of the tables
71
+ * in the database. A schemaVersion only moves forward; rolling back to
72
+ * an earlier (safe) code version does not revert schema changes that
73
+ * have already been applied.
74
+ */
75
+ schemaVersion: v.number(),
76
+ /**
77
+ * The data version is the code version of the latest server that ran.
78
+ * Note that this may be less than the schemaVersion in the case that
79
+ * a server is rolled back to an earlier version after a schema change.
80
+ * In such a case, data (but not schema), may need to be re-migrated
81
+ * when rolling forward again.
82
+ */
83
+ dataVersion: v.number(),
84
+ /**
85
+ * The minimum code version that is safe to run. This is used when
86
+ * a schema migration is not backwards compatible with an older version
87
+ * of the code.
88
+ */
89
+ minSafeVersion: v.number(),
90
+ });
91
+ // Exposed for tests
92
+ export async function getVersionHistory(sql, schemaName) {
93
+ // Note: The `lock` column transparently ensures that at most one row exists.
94
+ const results = await sql `
95
+ CREATE SCHEMA IF NOT EXISTS ${sql(schemaName)};
96
+ CREATE TABLE IF NOT EXISTS ${sql(schemaName)}."versionHistory" (
97
+ "dataVersion" int NOT NULL,
98
+ "schemaVersion" int NOT NULL,
99
+ "minSafeVersion" int NOT NULL,
100
+
101
+ lock char(1) NOT NULL CONSTRAINT DF_schema_meta_lock DEFAULT 'v',
102
+ CONSTRAINT PK_schema_meta_lock PRIMARY KEY (lock),
103
+ CONSTRAINT CK_schema_meta_lock CHECK (lock='v')
104
+ );
105
+ SELECT "dataVersion", "schemaVersion", "minSafeVersion" FROM ${sql(schemaName)}."versionHistory";
106
+ `.simple();
107
+ const rows = results[1];
108
+ if (rows.length === 0) {
109
+ return { schemaVersion: 0, dataVersion: 0, minSafeVersion: 0 };
110
+ }
111
+ return v.parse(rows[0], versionHistory);
112
+ }
113
+ async function updateVersionHistory(log, sql, schemaName, prev, newVersion, minSafeVersion) {
114
+ assert(newVersion > 0);
115
+ const versions = {
116
+ dataVersion: newVersion,
117
+ // The schemaVersion never moves backwards.
118
+ schemaVersion: Math.max(newVersion, prev.schemaVersion),
119
+ minSafeVersion: getMinSafeVersion(log, prev, minSafeVersion),
120
+ };
121
+ await sql `
122
+ INSERT INTO ${sql(schemaName)}."versionHistory" ${sql(versions)}
123
+ ON CONFLICT (lock) DO UPDATE SET ${sql(versions)}
124
+ `;
125
+ return versions;
126
+ }
127
+ async function runMigration(log, schemaName, tx, versions, destinationVersion, migration) {
128
+ if (versions.schemaVersion < destinationVersion) {
129
+ await migration.migrateSchema?.(log, tx);
130
+ }
131
+ if (versions.dataVersion < destinationVersion) {
132
+ await migration.migrateData?.(log, tx);
133
+ }
134
+ return updateVersionHistory(log, tx, schemaName, versions, destinationVersion, migration.minSafeVersion);
135
+ }
136
+ /**
137
+ * Bumps the rollback limit [[toAtLeast]] the specified version.
138
+ * Leaves the rollback limit unchanged if it is equal or greater.
139
+ */
140
+ function getMinSafeVersion(log, current, proposedSafeVersion) {
141
+ if (proposedSafeVersion === undefined) {
142
+ return current.minSafeVersion;
143
+ }
144
+ // Sanity check to maintain the invariant that running code is never
145
+ // earlier than the rollback limit.
146
+ assert(proposedSafeVersion <= current.dataVersion + 1);
147
+ if (current.minSafeVersion >= proposedSafeVersion) {
148
+ // The rollback limit must never move backwards.
149
+ log.debug?.(`rollback limit is already at ${current.minSafeVersion}, ` +
150
+ `don't need to bump to ${proposedSafeVersion}`);
151
+ return current.minSafeVersion;
152
+ }
153
+ log.info?.(`bumping rollback limit from ${current.minSafeVersion} to ${proposedSafeVersion}`);
154
+ return proposedSafeVersion;
155
+ }
156
+ //# sourceMappingURL=migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration.js","sourceRoot":"","sources":["../../../../../zero-cache/src/db/migration.ts"],"names":[],"mappings":"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"}
@@ -60,7 +60,7 @@ export declare const liteIndexSpec: v.ObjectType<{
60
60
  columns: v.Type<Record<string, "ASC" | "DESC">>;
61
61
  }, undefined>;
62
62
  export type MutableLiteIndexSpec = v.Infer<typeof liteIndexSpec>;
63
- export type LiteIndexSpec = DeepReadonly<MutableLiteIndexSpec>;
63
+ export type LiteIndexSpec = Readonly<MutableLiteIndexSpec>;
64
64
  export declare const indexSpec: v.ObjectType<Omit<{
65
65
  name: v.Type<string>;
66
66
  tableName: v.Type<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"specs.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/specs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,CAAC,MAAM,+BAA+B,CAAC;AAEnD,eAAO,MAAM,UAAU;;;;;;aAMrB,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC;AAE9D,eAAO,MAAM,aAAa;;;;;;;;;;aAIxB,CAAC;AAEH,eAAO,MAAM,SAAS;;;;;;;;;;;;aAEpB,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;aAE5B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC;AAEpE,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC;AAE5D,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC,CAAC;AAE5E,eAAO,MAAM,eAAe,8CAA+C,CAAC;AAE5E,eAAO,MAAM,aAAa;;;;;aAKxB,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEjE,MAAM,MAAM,aAAa,GAAG,YAAY,CAAC,oBAAoB,CAAC,CAAC;AAE/D,eAAO,MAAM,SAAS;;;;;;;aAEpB,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"specs.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/specs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,CAAC,MAAM,+BAA+B,CAAC;AAEnD,eAAO,MAAM,UAAU;;;;;;aAMrB,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC;AAE9D,eAAO,MAAM,aAAa;;;;;;;;;;aAIxB,CAAC;AAEH,eAAO,MAAM,SAAS;;;;;;;;;;;;aAEpB,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;aAE5B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC;AAEpE,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC;AAE5D,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC,CAAC;AAE5E,eAAO,MAAM,eAAe,8CAA+C,CAAC;AAE5E,eAAO,MAAM,aAAa;;;;;aAKxB,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEjE,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,oBAAoB,CAAC,CAAC;AAE3D,eAAO,MAAM,SAAS;;;;;;;aAEpB,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC"}