Description
Feature description
The new package @graphile/lds2
is in essence a copy of the current implementation with two changes (1 & 2) and one addition (3):
-
Minimal required version of wal2json is at this time of writing 2.3, due to requiring the
include-pk
parameter to be available. This is required for@graphile/subscriptions-lds
to properly work in cases whereREPLICA IDENTITY FULL
is enabled on a table. -
Dropping support for
version-format 1
, and moving toversion-format 2
which no longer reports changes on a transaction level, but on a tuple level. Additional bonus is that in my opinion the json object is structured more like what the industry standard is today. -
Adding watch capability much to what I believe
graphile-build
has for building it schema. Currently@graphile/lds
is not able to actively listen to schema changes, adding this would allow us to circumvent the need for theinclude-pk
parameter and as such also keep supportingversion-format 1
and wal2json <= 2.3, yet this is not the main goal of this addition.I believe the most useful purpose of adding a watch capability is to be able to support subscriptions on native pg >=11 partitioned tables and timescale hypertables. These table structures are providing a
virtual
table that one can doinsert
,update
,delete
,select
upon, but in actuality these operations are redirected to one or more sub tables (partitions). wal2json does NOT report changes on this (virtual
) parent table level, but on the actual subtable that the change occurred. This makes it impossible to subscribe to these type of tables with the current implementation of@graphile/lds
. I am aware of the fact that native pg >= 11 partitioned tables are NOT very well supported inpostgraphile
atm (Only the partitions are showing up in the schema, not the virtual table), but due to the different technical implementation of timescale hypertables these are actually coming out in the generated schema just fine (No partitions are shown, just the parent table).Having this watch capability allows us to figure out that when a change occurs in one of these sub tables, we also need to fabricate a same change for the (
virtual
) parent table.
Motivating example
Motivation for this alternative version is twofold, being that the the current implementation of @graphile/lds
:
-
Assumes that the primary key information of a change is always included in the property
oldkeys
if the propertyoldkeys
is included. This is NOT always the case due to the possibilty of enablingREPLICA IDENTITY FULL
on a table which changes the contents ofoldkeys
from not only containing the primary key(s), but to containing the entire record as it was before said change (much like theOLD
value in update/delete triggers). As such, enabling this feature on a table breaks the current implementation of@graphile/lds
.Fixing the above issue requires the use of a parameter
include-pk
which is only available in version >=2.3 of wal2json, and as of right now we haven't been able to find a method to detect which version of wal2json is installed. The only way seems to be that oftry {} catch {}
the code with the parameter and falling back on one without if it fails with a parameter unknown error. Problem I have with this approach is that we'd have to resort to string matching to determine the cause, which feels a bit too iffy to me. -
Is built on
version-format 1
of wal2json which produces a JSON object per transaction. All of the new/old tuples are available in the JSON object. Whereas the newerversion-format 2
produces a JSON object per tuple, supports thetruncate
operation and provides in my opinion a more logical constructed object.Below are both formats as defined in
typescript
definitions, these are both the default format which can be augmented with additional metadata based on parameters. One of which is the much neededinclude-pk
which is only available in wal2json >= 2.3format-version 1
:export interface Change { kind: Kind; schema: string; table: string; columnnames?: string[]; columntypes?: string[]; columnvalues?: Columnvalue[]; oldkeys?: Oldkeys; } enum Kind { Insert = 'insert', Update = 'update', Delete = 'delete' } export type Columnvalue = any; export interface Oldkeys { keynames: string[]; keytypes: string[]; keyvalues: Keyvalue[]; } export type Keyvalue = string;
format-version 2
:export interface Change { action: Action; schema: string; table: string; columns?: Column[]; identity?: Column[]; } enum Action { Insert = 'I', Update = 'U', Delete = 'D', Truncate = 'T' } export interface Column { name: string; type: string; value: Value; } export type Value = any;
As we discussed in Discord fixing/adding the above 2 points would result in such breaking changes that are whole new package is warranted. This new package @graphile/lds2
would have more strict requirements on which version of wal2json is used.
Breaking changes
None, because it is a new package. Yet, in order to make this package useful an update to @graphile/subscription-lds
or alternative package that does the same but using @graphile/lds2
is required.
Supporting development
I [tick all that apply]:
- am interested in building this feature myself
- am interested in collaborating on building this feature
- am willing to help testing this feature before it's released
- am willing to write a test-driven test suite for this feature (before it exists)
- am a Graphile sponsor ❤️
- have an active support or consultancy contract with Graphile