Storage & Immutability
GraphQL Paper uses
immer under the hood to be able to handle changes and optimize sharing references for unchanged portions in an object tree.
DocumentStores are considered stale-on-arrival which means they should not be directly edited. There are safeguards in place that try and prevent editing a document or store outside of a Mutate Transaction. This immutability also allows versioning the
Documents. Comparing different versions of documents is also possible based on their Document Keys.
Documents have a few hidden symboled properties that assist with tracking some internal state:
Document Keys are uniquely generated string at the time a document is created. It is an internal identifier or reference used by the library to be able to track and reference a document across versions. This leaves any
ID fields on a GraphQL type as data in "user land" although GraphQL Paper does provide a validator to check that
IDs on fields are unique within a type.
Connections for a document are stored as an array of document keys (strings) representing the documents they are connected to.
GraphQL Type Name
Documents are "typed" by a GraphQL type. The type is registered when a document is created and should never change.
mutatewith a Mutate Transaction callback
- Any previous transactions are waited to finish, in order, before the provided the transaction can run
- Expand connections so that properties references the appropriate connected documents
- Call the transaction callback using
- Capture any returned documents as represented by their keys
- Collapse connections so that references are stashed by their document key
- Run validations on new version created by
- Determine which events can be created by comparing new and old versions of the store
- Dispatch store events and custom events
- Set new version as the current
- Push the new version on to the history
- Return transaction captured keys as frozen Documents for the
Connection Lookup, Expansion and Collapsing
When accessing Documents outside of a Mutate Transaction the documents are wrapped in a proxy to assist with lookups of connections and to prevent document properties from being mutated outside a Mutate Transaction. The proxy also has a reference to the copy of the store when the document is retrieved ensuring that any connections looked up will also be frozen at the same point in time.
Before a transaction can occur each document has its connections expanded from document properties by the array of document keys to references to the other documents. If the field supports a GraphQL List type then the documents are represented as an array of Documents.
After a transaction any document properties that have references are collapsed into an internal array for connections, being stored as document keys.
Since GraphQL has a concept of nullable lists, that is lists that contain null, and connections are represented by documents there is a special reserved
nullDocument used in storing lists that contain null. This is a special case and not something that normally crops up during average usage and is kept relatively hidden in the library but would be important to consider when writing a custom validator that needs to check connections. During expansion of connections
nullDocuments in lists are represented by
null values and when collapsed the proxy ensures that any lists containing
nullDocuments are represented by