Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/storage-and-codegen-notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'zero-swift': patch
---

Documents that the main thread waits up to about 5 s when it opens a database another program holds locked, and up to about 10 s in `flush()` or `close()` on a busy one; that two generated schemas with a table of the same name need modules of their own; and that a flipped `whereExists` reaching a `limit` early, where JS asserts "Unexpected early return prevented full hydration", keeps working in Swift.
5 changes: 5 additions & 0 deletions packages/zero-swift-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ Rename a row struct whose name clashes with a type you use. A table named
`list` generates `struct List`, which hides SwiftUI's `List`; set
`tables.list.type` to `NoteList`, or set a `typePrefix`.

Two generated schemas with a table of the same name can't share a module:
both declare `tx.mutate.<table>`. Generate each into a module of its own.
Code that imports both names the row type, as in
`TypedTableMutator<Issue>(tx.mutate).insert(…)`.

### Names

Tables, columns, relationships, JSON fields and enumeration values keep
Expand Down
10 changes: 9 additions & 1 deletion swift/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,10 +219,18 @@ Rationale:
- If the store can't be opened, the client runs on memory and calls
`onStorageFailure`, as JS does. A failed write stops writing and calls it
too. A write that finds the database busy is kept and written with the
next one, or by `flush()` and `close()`, which try twice more before they
next one, or by `flush()` and `close()`, which try once more before they
call it a failure. Stored data that doesn't decode is lost client state,
as a corrupt ref count is in JS: the client deletes the database, starts
a new one, and calls `onClientStateNotFound` if the app set it.
- These waits are on the main thread, each up to SQLite's 5 s busy
timeout. Opening a database another connection holds locked blocks
`Zero.init` for about 5 s before the client falls back to memory, and
`flush()` or `close()` on a busy database blocks for up to about 10 s:
the queued write, then the retry. With one process per store, only
another program with the file open, such as a SQLite browser, holds
such a lock. Opening and closing the store off the main actor would
avoid the waits; that is deferred.
- A client writes a poke's snapshot only when its cookie is newer than the
stored one, as Replicache persists, so a client of the group that is
behind another doesn't overwrite it.
Expand Down
7 changes: 7 additions & 0 deletions swift/Sources/Zero/Zero.docc/JSParity.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,13 @@ is written or sent.
connection in the `error` state, a mutation that fails is committed and
its `client` outcome is the error, and later mutations, `materialize`,
and `run` fail with the same message.
- **A flipped `whereExists` stopping a `limit` early.** To learn whether a
row a change brings has a match, a flipped `whereExists` reads its
subquery's first row only. When that read goes through a `limit` whose
rows for this row weren't read before, JS asserts ("Unexpected early
return prevented full hydration") and the change fails as above. Swift
keeps working and shows the rows JS shows once its `Take` reads the rest
of such a fetch, as the comment by that assertion proposes.
- **Nulls in columns that can't be null.** When the server sends null for
a column the schema says isn't optional, a `String`, `Double`, `Int`, or
`Bool` property reads as `""`, `0`, or `false`. JS hands the null
Expand Down
Loading