feat: JSON support for kv driver

This commit is contained in:
KernelDeimos 2024-07-08 15:24:26 -04:00 committed by Eric Dubé
parent 1f659f7c01
commit 3ed7916856
3 changed files with 51 additions and 5 deletions

View File

@ -58,6 +58,11 @@ class DBKVStore extends Driver {
`SELECT * FROM kv WHERE user_id=? AND (app IS NULL OR app = 'global') AND kkey_hash=? LIMIT 1`, `SELECT * FROM kv WHERE user_id=? AND (app IS NULL OR app = 'global') AND kkey_hash=? LIMIT 1`,
[ user.id, key_hash ] [ user.id, key_hash ]
); );
if ( kv[0] ) kv[0].value = db.case({
mysql: () => kv[0].value,
otherwise: () => JSON.parse(kv[0].value ?? 'null'),
})();
return kv[0]?.value ?? null; return kv[0]?.value ?? null;
}, },
@ -74,10 +79,11 @@ class DBKVStore extends Driver {
} }
// Validate the value // Validate the value
value = value === undefined ? null : String(value); value = value === undefined ? null : value;
if ( if (
value !== null && value !== null &&
Buffer.byteLength(value, 'utf8') > config.kv_max_value_size Buffer.byteLength(JSON.stringify(value), 'utf8') >
config.kv_max_value_size
) { ) {
throw new Error(`value is too large. Max size is ${config.kv_max_value_size}.`); throw new Error(`value is too large. Max size is ${config.kv_max_value_size}.`);
} }
@ -102,7 +108,8 @@ class DBKVStore extends Driver {
sqlite: 'ON CONFLICT(user_id, app, kkey_hash) DO UPDATE SET value = excluded.value', sqlite: 'ON CONFLICT(user_id, app, kkey_hash) DO UPDATE SET value = excluded.value',
}), }),
[ [
user.id, app?.uid ?? 'global', key_hash, key, value, user.id, app?.uid ?? 'global', key_hash, key,
JSON.stringify(value),
...db.case({ mysql: [value], otherwise: [] }), ...db.case({ mysql: [value], otherwise: [] }),
] ]
); );
@ -164,7 +171,10 @@ class DBKVStore extends Driver {
rows = rows.map(row => ({ rows = rows.map(row => ({
key: row.kkey, key: row.kkey,
value: row.value, value: db.case({
mysql: () => row.value,
otherwise: () => JSON.parse(row.value ?? 'null')
})(),
})); }));
as = as || 'entries'; as = as || 'entries';

View File

@ -42,7 +42,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
this.db = new Database(this.config.path); this.db = new Database(this.config.path);
// Database upgrade logic // Database upgrade logic
const TARGET_VERSION = 20; const TARGET_VERSION = 21;
if ( do_setup ) { if ( do_setup ) {
this.log.noticeme(`SETUP: creating database at ${this.config.path}`); this.log.noticeme(`SETUP: creating database at ${this.config.path}`);
@ -69,6 +69,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
'0020_dev-center.sql', '0020_dev-center.sql',
'0021_app-owner-id.sql', '0021_app-owner-id.sql',
'0022_dev-center-max.sql', '0022_dev-center-max.sql',
'0023_fix-kv.sql',
].map(p => path_.join(__dirname, 'sqlite_setup', p)); ].map(p => path_.join(__dirname, 'sqlite_setup', p));
const fs = require('fs'); const fs = require('fs');
for ( const filename of sql_files ) { for ( const filename of sql_files ) {
@ -165,6 +166,10 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
upgrade_files.push('0022_dev-center-max.sql'); upgrade_files.push('0022_dev-center-max.sql');
} }
if ( user_version <= 20 ) {
upgrade_files.push('0023_fix-kv.sql');
}
if ( upgrade_files.length > 0 ) { if ( upgrade_files.length > 0 ) {
this.log.noticeme(`Database out of date: ${this.config.path}`); this.log.noticeme(`Database out of date: ${this.config.path}`);
this.log.noticeme(`UPGRADING DATABASE: ${user_version} -> ${TARGET_VERSION}`); this.log.noticeme(`UPGRADING DATABASE: ${user_version} -> ${TARGET_VERSION}`);

View File

@ -0,0 +1,31 @@
CREATE TABLE `new_kv` (
`id` INTEGER PRIMARY KEY,
`app` char(40) DEFAULT NULL,
`user_id` int(10) NOT NULL,
`kkey_hash` bigint(20) NOT NULL,
`kkey` text NOT NULL,
`value` JSON,
`migrated` tinyint(1) DEFAULT '0',
UNIQUE (user_id, app, kkey_hash)
);
INSERT INTO `new_kv`
(
`app`,
`user_id`,
`kkey_hash`,
`kkey`,
`value`
)
SELECT
`app`,
`user_id`,
`kkey_hash`,
`kkey`,
json_quote(value)
FROM `kv`;
DROP TABLE `kv`;
ALTER TABLE `new_kv`
RENAME TO `kv`;