Skip to content

sql-storage-adapter v0.7.16

Choose a tag to compare

@github-actions github-actions released this 17 Oct 23:17
· 153 commits to master since this release
f213076

Fixed

  • SupabaseAdapter with enableCache() on never answers a row as it stood before one of its own writes. get and all kept each answer by statement and parameters, and no write cleared them, so a row read, then changed through run, exec, transaction or batchWrite, came back from the cache unchanged. They also kept the answer of a statement that writes: get('INSERT ... RETURNING id', params) ran once, and the second call answered the first row without inserting, and get('SELECT bump(?)', params), whose function writes, did the same. The cache now holds the answers of SELECTs alone (a statement whose first word, past white space and comments, is SELECT), and of those only the ones that wrote nothing: a SELECT the cache does not hold runs once, in a transaction of its own, and its answer is kept only when PostgreSQL gave that transaction no ID, which PostgreSQL gives a transaction when it first writes. That check reads pg_current_xact_id_if_assigned(), so the cache needs PostgreSQL 13 or later. Every statement that writes and every transaction clears the cache when it ends, and a read that a write or clearCache() overtook keeps nothing. A string of several statements counts as a write: a COMMIT in it ended the cache's transaction, and an UPDATE after it committed in one of its own, which the check could not see. The key of an answer names its call, so get and all of one statement no longer answer each other's row or list, and it writes each parameter as pg binds it. It wrote them as JSON: a bigint parameter threw (JSON.stringify cannot write one) before the statement reached the database, a statement bound to NaN answered the row kept for null, one bound to a Date, from this realm or another, answered the row kept for the Date's ISO text, which pg binds as other text (local time with its offset), one bound to bytes and one bound to an object JSON writes alike ({ type: 'Buffer', data: [1] }) answered each other's row, two objects that pg binds through their own toPostgres shared a key whenever JSON wrote them alike, as it writes any two whose state is private, and text spelling a Date's key (U+0000, then the Date's tag and time), which PostgreSQL refuses, answered the row kept for that Date. A SELECT bound to an object with a toPostgres of its own, or to text holding U+0000, now runs each time it is asked. A hit answered the kept row or list itself, and the first caller got it too, so a caller that changed what it was given changed what the cache answered next; the cache now keeps a copy and answers a copy, with each Date and Buffer copied as itself, and keeps no answer holding a value with no faithful copy, such as an interval, which pg parses to an object of its own. A write through another adapter, pool or process, an effect that writes no row, such as pg_notify() or an advisory lock, and a SELECT whose answer changes from one call to the next by itself, such as one that calls random(), now() or nextval(), can still answer from the cache until clearCache(); run a statement wanted for its effect through run, or begin it with a word other than SELECT, such as VALUES (nextval('ids')).
  • S3StorageProvider.list (#64) answers every key under the prefix: it sends ListObjectsV2 again with each page's NextContinuationToken until a page is not truncated. It answered the first page alone.