◆ 更新処理を行うまでは同じクエリの結果はキャッシュを使う
◆ クエリに依存テーブルを指定して SELECT 以外を送信したら更新されたとみなす
◆ SELECT クエリに依存するテーブルがキャッシュしたときから更新があったら再取得

以前 DB から通知を受け取って変更があったらテーブルのデータを全部取得しなおすつくりのものを作りました
前提が DB のデータは全部変数上にロードしておくというものだったのですが データが多いときように SQL 単位でキャッシュすることを考えてみました
こういうふうに書けるものにします

SQL`
SELECT * FROM user LEFT JOIN article USING user_id WHERE user_id = ${user_id}
`(["user", "article"])

SQL`
INSERT INTO article (user_id, body, created_at) VALUES (${user_id}, ${body}, NOW())
`(["article"])

SQL 関数をタグにしたテンプレートリテラルで SQL を記述します
可変部分は ${} を利用して値を埋め込みます
この処理が返す関数を実行すると SQL を実行します
引数には配列で依存テーブル名のリストを指定します

SELECT の場合 クエリと結果をキャッシュして 同じ SQL と埋め込み値の場合は前回と同じ結果を DB との通信なしに返します
ただし 前回のキャッシュしたタイミングから依存テーブルに更新が発生していた場合はキャッシュを破棄して再取得します
その結果はまたキャッシュされます

SELECT 以外の場合は依存テーブルに更新があったことをマークします
実際には更新された行がなくても SELECT 以外のクエリの送信時に変更があったとみなします


そういう前提で作ったものがこちらです
db には適当な db への connection を入れておきます
ここでは DB の種類は重要じゃないので省略します

const db = null

const sqache = {
table_ver: {},
cache: {},
get(id, tables) {
const cache = this.cache[id]
if (cache && tables.every((v, i) => cache.table_ver[i] === this.table_ver[v])) {
return cache.result
}
},
set(id, result, tables) {
this.cache[id] = { result, table_ver: tables.map(table => this.table_ver[table]) }
},
update(tables) {
for (const table of tables) {
this.table_ver[table] = ~~this.table_ver[table] + 1
}
},
}

class Query {
constructor(tpls, values) {
this.sql = tpls.reduce((a, b, i) => a + "$" + i + b)
this.values = values
}
createId() {
return [this.sql, ...this.values].join(";")
}
getAction() {
return this.sql
.trimLeft()
.split(" ", 1)[0]
.toUpperCase()
}
async exec() {
const result = await db.query(this.sql, this.values)
return result.rows
}
}

const SQL = (tpls, ...values) => tables => {
const query = new Query(tpls, values)
const id = query.createId()
const action = query.getAction()
if (action === "SELECT") {
const cache = sqache.get(id, tables)
if (cache) return cache
}
return query.exec().then(result => {
if (action === "SELECT") {
sqache.set(id, result, tables)
} else {
sqache.update(tables)
}
return result
})
}