Use @signalapp/sqlcipher

This commit is contained in:
Fedor Indutny
2025-03-12 14:45:54 -07:00
committed by GitHub
parent df7997b313
commit 5a9253bd44
118 changed files with 2497 additions and 1485 deletions

View File

@@ -2,9 +2,10 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { noop } from 'lodash';
import SQL from '@signalapp/better-sqlite3';
import SQL from '@signalapp/sqlcipher';
import type { ReadableDB, WritableDB } from '../../sql/Interface';
import type { QueryTemplate } from '../../sql/util';
import { SCHEMA_VERSIONS } from '../../sql/migrations';
import { consoleLogger } from '../../util/consoleLogger';
@@ -13,7 +14,7 @@ export function createDB(): WritableDB {
}
export function updateToVersion(db: WritableDB, version: number): void {
const startVersion = db.pragma('user_version', { simple: true });
const startVersion = db.pragma('user_version', { simple: true }) as number;
const silentLogger = {
...consoleLogger,
@@ -68,7 +69,7 @@ export function getTableData(db: ReadableDB, table: string): TableRows {
return db
.prepare(`SELECT * FROM ${table}`)
.all()
.map((row: Record<string, string | number | Buffer | null>) => {
.map(row => {
const result: Record<
string,
string | number | null | Record<string, unknown>
@@ -77,8 +78,8 @@ export function getTableData(db: ReadableDB, table: string): TableRows {
if (value == null) {
continue;
}
if (Buffer.isBuffer(value)) {
result[key] = value.toString('hex');
if (value instanceof Uint8Array) {
result[key] = Buffer.from(value).toString('hex');
continue;
}
try {
@@ -93,3 +94,14 @@ export function getTableData(db: ReadableDB, table: string): TableRows {
return result;
});
}
export function explain(db: ReadableDB, template: QueryTemplate): string {
const [query, params] = template;
const details = db
.prepare(`EXPLAIN QUERY PLAN ${query}`)
.all<{ detail: string }>(params)
.map(({ detail }) => detail)
.join('\n');
return details;
}

View File

@@ -52,8 +52,8 @@ describe('SQL/updateToSchemaVersion1000', () => {
${message.id},
${message.conversationId},
${message.type},
${message.readStatus},
${message.seenStatus},
${message.readStatus ?? null},
${message.seenStatus ?? null},
${json}
)
`;
@@ -95,7 +95,7 @@ describe('SQL/updateToSchemaVersion1000', () => {
`;
return db
.prepare(query)
.all()
.all<{ json: string; readStatus: ReadStatus; seenStatus: SeenStatus }>()
.map(row => {
return {
message: jsonToObject<MessageType>(row.json),

View File

@@ -5,20 +5,22 @@ import { assert } from 'chai';
import type { ReadableDB, WritableDB } from '../../sql/Interface';
import { jsonToObject, objectToJSON, sql, sqlJoin } from '../../sql/util';
import { createDB, updateToVersion } from './helpers';
import { createDB, updateToVersion, explain } from './helpers';
import type { LegacyAttachmentDownloadJobType } from '../../sql/migrations/1040-undownloaded-backed-up-media';
import type { AttachmentType } from '../../types/Attachment';
import type { AttachmentDownloadJobType } from '../../types/AttachmentDownload';
import { IMAGE_JPEG } from '../../types/MIME';
function getAttachmentDownloadJobs(db: ReadableDB) {
function getAttachmentDownloadJobs(
db: ReadableDB
): Array<Record<string, unknown>> {
const [query] = sql`
SELECT * FROM attachment_downloads ORDER BY receivedAt DESC;
`;
return db
.prepare(query)
.all()
.all<{ attachmentJson: string }>()
.map(job => ({
...omit(job, 'attachmentJson'),
attachment: jsonToObject(job.attachmentJson),
@@ -64,7 +66,7 @@ function insertNewJob(
${job.messageId},
${job.attachmentType},
${objectToJSON(job.attachment)},
${job.attachment.digest},
${job.attachment.digest ?? null},
${job.attachment.contentType},
${job.attachment.size},
${job.receivedAt},
@@ -238,7 +240,7 @@ describe('SQL/updateToSchemaVersion1040', () => {
});
{
const [query, params] = sql`
const template = sql`
SELECT * FROM attachment_downloads
WHERE
active = 0
@@ -248,6 +250,7 @@ describe('SQL/updateToSchemaVersion1040', () => {
LIMIT 5
`;
const [query, params] = template;
const result = db.prepare(query).all(params);
assert.strictEqual(result.length, 2);
assert.deepStrictEqual(
@@ -255,11 +258,7 @@ describe('SQL/updateToSchemaVersion1040', () => {
['message4', 'message1']
);
const details = db
.prepare(`EXPLAIN QUERY PLAN ${query}`)
.all(params)
.map(step => step.detail)
.join(', ');
const details = explain(db, template);
assert.include(
details,
'USING INDEX attachment_downloads_active_receivedAt'
@@ -269,7 +268,7 @@ describe('SQL/updateToSchemaVersion1040', () => {
}
{
const messageIds = ['message1', 'message2', 'message4'];
const [query, params] = sql`
const template = sql`
SELECT * FROM attachment_downloads
INDEXED BY attachment_downloads_active_messageId
WHERE
@@ -282,17 +281,15 @@ describe('SQL/updateToSchemaVersion1040', () => {
LIMIT 5
`;
const [query, params] = template;
const result = db.prepare(query).all(params);
assert.strictEqual(result.length, 2);
assert.deepStrictEqual(
result.map(res => res.messageId),
['message1', 'message4']
);
const details = db
.prepare(`EXPLAIN QUERY PLAN ${query}`)
.all(params)
.map(step => step.detail)
.join(', ');
const details = explain(db, template);
// This query _will_ use a temp b-tree for ordering, but the number of rows
// should be quite low.
@@ -466,16 +463,16 @@ function insertLegacyJob(
job: Partial<LegacyAttachmentDownloadJobType>
): void {
db.prepare('INSERT OR REPLACE INTO messages (id) VALUES ($id)').run({
id: job.messageId,
id: job.messageId ?? null,
});
const [query, params] = sql`
INSERT INTO attachment_downloads
(id, timestamp, pending, json)
VALUES
(
${job.id},
${job.timestamp},
${job.pending},
${job.id ?? null},
${job.timestamp ?? null},
${job.pending ?? null},
${objectToJSON(job)}
);
`;

View File

@@ -11,7 +11,7 @@ import {
} from '../../sql/Server';
import type { WritableDB, ReadableDB, MessageType } from '../../sql/Interface';
import { sql, jsonToObject } from '../../sql/util';
import { insertData, updateToVersion, createDB } from './helpers';
import { insertData, updateToVersion, createDB, explain } from './helpers';
import { MAX_SYNC_TASK_ATTEMPTS } from '../../util/syncTasks.types';
import { WEEK } from '../../util/durations';
@@ -36,7 +36,7 @@ export function getMostRecentAddressableMessages(
LIMIT ${limit};
`;
const rows = db.prepare(query).all(parameters);
const rows = db.prepare(query).all<{ json: string }>(parameters);
return rows.map(row => jsonToObject(row.json));
}
@@ -169,10 +169,9 @@ describe('SQL/updateToSchemaVersion1060', () => {
});
it('ensures that index is used for getMostRecentAddressableMessages, with storyId', () => {
const { detail } = db
.prepare(
`
EXPLAIN QUERY PLAN
const detail = explain(
db,
sql`
SELECT json FROM messages
INDEXED BY messages_by_date_addressable
WHERE
@@ -181,8 +180,7 @@ describe('SQL/updateToSchemaVersion1060', () => {
ORDER BY received_at DESC, sent_at DESC
LIMIT 5;
`
)
.get();
);
assert.notInclude(detail, 'B-TREE');
assert.notInclude(detail, 'SCAN');

View File

@@ -6,7 +6,7 @@ import { v4 as generateGuid } from 'uuid';
import type { WritableDB, ReadableDB, MessageType } from '../../sql/Interface';
import { sql, jsonToObject } from '../../sql/util';
import { createDB, insertData, updateToVersion } from './helpers';
import { createDB, insertData, updateToVersion, explain } from './helpers';
import type { MessageAttributesType } from '../../model-types';
import { DurationInSeconds } from '../../util/durations/duration-in-seconds';
@@ -43,7 +43,7 @@ export function getMostRecentAddressableNondisappearingMessages(
LIMIT ${limit};
`;
const rows = db.prepare(query).all(parameters);
const rows = db.prepare(query).all<{ json: string }>(parameters);
return rows.map(row => jsonToObject(row.json));
}
@@ -159,10 +159,9 @@ describe('SQL/updateToSchemaVersion1080', () => {
});
it('ensures that index is used for getMostRecentAddressableNondisappearingMessagesSync, with storyId', () => {
const { detail } = db
.prepare(
`
EXPLAIN QUERY PLAN
const detail = explain(
db,
sql`
SELECT json FROM messages
INDEXED BY messages_by_date_addressable_nondisappearing
WHERE
@@ -172,8 +171,7 @@ describe('SQL/updateToSchemaVersion1080', () => {
ORDER BY received_at DESC, sent_at DESC
LIMIT 5;
`
)
.get();
);
assert.notInclude(detail, 'B-TREE');
assert.notInclude(detail, 'SCAN');

View File

@@ -3,7 +3,8 @@
import { assert } from 'chai';
import type { WritableDB } from '../../sql/Interface';
import { createDB, updateToVersion } from './helpers';
import { sql } from '../../sql/util';
import { createDB, updateToVersion, explain } from './helpers';
describe('SQL/updateToSchemaVersion1090', () => {
let db: WritableDB;
@@ -18,16 +19,12 @@ describe('SQL/updateToSchemaVersion1090', () => {
describe('Additional messages_on_delete indexes', () => {
it('uses index for selecting reactions by messageId', () => {
const details = db
.prepare(
`EXPLAIN QUERY PLAN
SELECT rowid FROM reactions
const details = explain(
db,
sql`SELECT rowid FROM reactions
WHERE messageId = '123';
`
)
.all()
.map(step => step.detail)
.join(', ');
);
assert.strictEqual(
details,
@@ -36,15 +33,10 @@ describe('SQL/updateToSchemaVersion1090', () => {
});
it('uses index for selecting storyReads by storyId', () => {
const details = db
.prepare(
`EXPLAIN QUERY PLAN
DELETE FROM storyReads WHERE storyId = '123';
`
)
.all()
.map(step => step.detail)
.join(', ');
const details = explain(
db,
sql`DELETE FROM storyReads WHERE storyId = '123';`
);
assert.strictEqual(
details,

View File

@@ -3,7 +3,8 @@
import { assert } from 'chai';
import type { WritableDB } from '../../sql/Interface';
import { createDB, updateToVersion } from './helpers';
import { sql } from '../../sql/util';
import { createDB, updateToVersion, explain } from './helpers';
describe('SQL/updateToSchemaVersion1120', () => {
let db: WritableDB;
@@ -17,15 +18,10 @@ describe('SQL/updateToSchemaVersion1120', () => {
});
it('uses index for deleting edited messages', () => {
const details = db
.prepare(
`EXPLAIN QUERY PLAN
DELETE FROM edited_messages WHERE messageId = 'messageId';
`
)
.all()
.map(step => step.detail)
.join(', ');
const details = explain(
db,
sql`DELETE FROM edited_messages WHERE messageId = 'messageId';`
);
assert.strictEqual(
details,
@@ -34,15 +30,10 @@ describe('SQL/updateToSchemaVersion1120', () => {
});
it('uses index for deleting mentions', () => {
const details = db
.prepare(
`EXPLAIN QUERY PLAN
DELETE FROM mentions WHERE messageId = 'messageId';
`
)
.all()
.map(step => step.detail)
.join(', ');
const details = explain(
db,
sql`DELETE FROM mentions WHERE messageId = 'messageId';`
);
assert.strictEqual(
details,

View File

@@ -3,7 +3,8 @@
import { assert } from 'chai';
import type { WritableDB } from '../../sql/Interface';
import { createDB, updateToVersion } from './helpers';
import { sql } from '../../sql/util';
import { createDB, updateToVersion, explain } from './helpers';
describe('SQL/updateToSchemaVersion1130', () => {
let db: WritableDB;
@@ -17,10 +18,9 @@ describe('SQL/updateToSchemaVersion1130', () => {
});
it('uses new index for getAllStories query and no params', () => {
const details = db
.prepare(
`
EXPLAIN QUERY PLAN
const details = explain(
db,
sql`
SELECT json, id
FROM messages
WHERE
@@ -29,19 +29,15 @@ describe('SQL/updateToSchemaVersion1130', () => {
(NULL IS NULL OR sourceServiceId IS NULL)
ORDER BY received_at ASC, sent_at ASC;
`
)
.all()
.map(step => step.detail)
.join(', ');
);
assert.strictEqual(details, 'SCAN messages USING INDEX messages_isStory');
});
it('uses new index for getAllStories query and with conversationId', () => {
const details = db
.prepare(
`
EXPLAIN QUERY PLAN
const details = explain(
db,
sql`
SELECT json, id
FROM messages
WHERE
@@ -50,19 +46,15 @@ describe('SQL/updateToSchemaVersion1130', () => {
(NULL IS NULL OR sourceServiceId IS NULL)
ORDER BY received_at ASC, sent_at ASC;
`
)
.all()
.map(step => step.detail)
.join(', ');
);
assert.strictEqual(details, 'SCAN messages USING INDEX messages_isStory');
});
it('uses new index for getAllStories query and with sourceServiceId', () => {
const details = db
.prepare(
`
EXPLAIN QUERY PLAN
const details = explain(
db,
sql`
SELECT json, id
FROM messages
WHERE
@@ -71,19 +63,15 @@ describe('SQL/updateToSchemaVersion1130', () => {
('something' IS NULL OR sourceServiceId IS 'something')
ORDER BY received_at ASC, sent_at ASC;
`
)
.all()
.map(step => step.detail)
.join(', ');
);
assert.strictEqual(details, 'SCAN messages USING INDEX messages_isStory');
});
it('uses new index for getAllStories query and both params', () => {
const details = db
.prepare(
`
EXPLAIN QUERY PLAN
const details = explain(
db,
sql`
SELECT json, id
FROM messages
WHERE
@@ -92,27 +80,20 @@ describe('SQL/updateToSchemaVersion1130', () => {
('something' IS NULL OR sourceServiceId IS 'something')
ORDER BY received_at ASC, sent_at ASC;
`
)
.all()
.map(step => step.detail)
.join(', ');
);
assert.strictEqual(details, 'SCAN messages USING INDEX messages_isStory');
});
it('uses previous index for getAllStories get replies query', () => {
const details = db
.prepare(
`
EXPLAIN QUERY PLAN
const details = explain(
db,
sql`
SELECT DISTINCT storyId
FROM messages
WHERE storyId IS NOT NULL
`
)
.all()
.map(step => step.detail)
.join(', ');
);
assert.strictEqual(
details,
@@ -121,10 +102,9 @@ describe('SQL/updateToSchemaVersion1130', () => {
});
it('uses previous index for getAllStories get replies from self query', () => {
const details = db
.prepare(
`
EXPLAIN QUERY PLAN
const details = explain(
db,
sql`
SELECT DISTINCT storyId
FROM messages
WHERE (
@@ -132,10 +112,7 @@ describe('SQL/updateToSchemaVersion1130', () => {
type IS 'outgoing'
)
`
)
.all()
.map(step => step.detail)
.join(', ');
);
assert.strictEqual(
details,

View File

@@ -4,7 +4,7 @@
import { assert } from 'chai';
import { omit } from 'lodash';
import type { WritableDB } from '../../sql/Interface';
import { createDB, updateToVersion } from './helpers';
import { createDB, updateToVersion, explain } from './helpers';
import type { AttachmentDownloadJobType } from '../../types/AttachmentDownload';
import { jsonToObject, objectToJSON, sql } from '../../sql/util';
import { IMAGE_BMP } from '../../types/MIME';
@@ -59,14 +59,14 @@ function insertOldJob(
db.prepare(query).run(params);
}
function getAttachmentDownloadJobs(db: WritableDB) {
function getAttachmentDownloadJobs(db: WritableDB): unknown {
const [query] = sql`
SELECT * FROM attachment_downloads ORDER BY receivedAt DESC;
`;
return db
.prepare(query)
.all()
.all<{ active: number; attachmentJson: string }>()
.map(job => ({
...omit(job, 'attachmentJson'),
active: job.active === 1,
@@ -108,17 +108,13 @@ describe('SQL/updateToSchemaVersion1180', () => {
});
it('uses convering index for summing all pending backup jobs', async () => {
updateToVersion(db, 1180);
const details = db
.prepare(
const details = explain(
db,
sql`
SELECT SUM(ciphertextSize) FROM attachment_downloads
WHERE source = 'backup_import';
`
EXPLAIN QUERY PLAN
SELECT SUM(ciphertextSize) FROM attachment_downloads
WHERE source = 'backup_import';
`
)
.all()
.map(step => step.detail)
.join(', ');
);
assert.strictEqual(
details,
@@ -127,17 +123,13 @@ describe('SQL/updateToSchemaVersion1180', () => {
});
it('uses index for deleting all backup jobs', async () => {
updateToVersion(db, 1180);
const details = db
.prepare(
const details = explain(
db,
sql`
DELETE FROM attachment_downloads
WHERE source = 'backup_import';
`
EXPLAIN QUERY PLAN
DELETE FROM attachment_downloads
WHERE source = 'backup_import';
`
)
.all()
.map(step => step.detail)
.join(', ');
);
assert.strictEqual(
details,

View File

@@ -5,7 +5,7 @@ import { assert } from 'chai';
import { AttachmentDownloadSource, type WritableDB } from '../../sql/Interface';
import { objectToJSON, sql } from '../../sql/util';
import { createDB, updateToVersion } from './helpers';
import { createDB, updateToVersion, explain } from './helpers';
import type { AttachmentDownloadJobType } from '../../types/AttachmentDownload';
import { IMAGE_JPEG } from '../../types/MIME';
@@ -71,7 +71,7 @@ function insertJob(
${job.messageId},
${job.attachmentType},
${objectToJSON(job.attachment)},
${job.attachment.digest},
${job.attachment.digest ?? null},
${job.attachment.contentType},
${job.attachment.size},
${job.receivedAt},
@@ -113,7 +113,7 @@ describe('SQL/updateToSchemaVersion1200', () => {
it('uses correct index for standard query', () => {
const now = Date.now();
const [query, params] = sql`
const template = sql`
SELECT * FROM attachment_downloads
WHERE
active = 0
@@ -122,11 +122,7 @@ describe('SQL/updateToSchemaVersion1200', () => {
ORDER BY receivedAt DESC
LIMIT 3
`;
const details = db
.prepare(`EXPLAIN QUERY PLAN ${query}`)
.all(params)
.map(step => step.detail)
.join(', ');
const details = explain(db, template);
assert.equal(
details,
'SEARCH attachment_downloads USING INDEX attachment_downloads_active_receivedAt (active=?)'
@@ -136,7 +132,7 @@ describe('SQL/updateToSchemaVersion1200', () => {
it('uses correct index for standard query with sources', () => {
const now = Date.now();
// query with sources (e.g. when backup-import is paused)
const [query, params] = sql`
const template = sql`
SELECT * FROM attachment_downloads
WHERE
active IS 0
@@ -147,11 +143,7 @@ describe('SQL/updateToSchemaVersion1200', () => {
ORDER BY receivedAt DESC
LIMIT 3
`;
const details = db
.prepare(`EXPLAIN QUERY PLAN ${query}`)
.all(params)
.map(step => step.detail)
.join(', ');
const details = explain(db, template);
assert.equal(
details,
'SEARCH attachment_downloads USING INDEX attachment_downloads_active_source_receivedAt (active=? AND source=?)'
@@ -160,7 +152,7 @@ describe('SQL/updateToSchemaVersion1200', () => {
it('uses provided index for prioritized query with sources', () => {
// prioritize visible messages with sources (e.g. when backup-import is paused)
const [query, params] = sql`
const template = sql`
SELECT * FROM attachment_downloads
INDEXED BY attachment_downloads_active_messageId
WHERE
@@ -174,36 +166,30 @@ describe('SQL/updateToSchemaVersion1200', () => {
ORDER BY receivedAt ASC
LIMIT 3
`;
const [query, params] = template;
const result = db.prepare(query).all(params);
assert.strictEqual(result.length, 1);
assert.deepStrictEqual(result[0].messageId, 'message12');
const details = db
.prepare(`EXPLAIN QUERY PLAN ${query}`)
.all(params)
.map(step => step.detail)
.join(', ');
const details = explain(db, template);
assert.equal(
details,
'SEARCH attachment_downloads USING INDEX attachment_downloads_active_messageId (active=? AND messageId=?), USE TEMP B-TREE FOR ORDER BY'
'SEARCH attachment_downloads USING INDEX attachment_downloads_active_messageId (active=? AND messageId=?)\nUSE TEMP B-TREE FOR ORDER BY'
);
});
it('uses existing index to remove all backup jobs ', () => {
// prioritize visible messages with sources (e.g. when backup-import is paused)
const [query, params] = sql`
const template = sql`
DELETE FROM attachment_downloads
WHERE source = 'backup_import';
`;
const details = db
.prepare(`EXPLAIN QUERY PLAN ${query}`)
.all(params)
.map(step => step.detail)
.join(', ');
const details = explain(db, template);
assert.equal(
details,
'SEARCH attachment_downloads USING COVERING INDEX attachment_downloads_source_ciphertextSize (source=?)'
);
const [query, params] = template;
db.prepare(query).run(params);
assert.equal(
db.prepare('SELECT * FROM attachment_downloads').all().length,

View File

@@ -9,8 +9,9 @@ import {
saveSyncTasks,
incrementAllSyncTaskAttempts,
} from '../../sql/Server';
import { sql } from '../../sql/util';
import type { WritableDB } from '../../sql/Interface';
import { updateToVersion, createDB } from './helpers';
import { updateToVersion, createDB, explain } from './helpers';
import type { SyncTaskType } from '../../util/syncTasks';
@@ -27,17 +28,15 @@ describe('SQL/updateToSchemaVersion1330', () => {
describe('Sync Tasks task index', () => {
it('uses the task index for queries', () => {
const { detail } = db
.prepare(
`
EXPLAIN QUERY PLAN
const detail = explain(
db,
sql`
SELECT rowid, * FROM syncTasks
WHERE rowid > 0 AND type IN ('delete-converation', 'delete-local-conversation')
ORDER BY rowid ASC
LIMIT 10000
`
)
.get();
);
assert.include(detail, 'USING INDEX syncTasks_type');
});
});

View File

@@ -82,17 +82,37 @@ describe('SQL/updateToSchemaVersion87(cleanup)', () => {
}
function getCountOfKyberKeys(): number {
return db.prepare('SELECT count(*) FROM kyberPreKeys;').pluck(true).get();
return (
db
.prepare('SELECT count(*) FROM kyberPreKeys;', {
pluck: true,
})
.get<number>() ?? 0
);
}
function getCountOfPreKeys(): number {
return db.prepare('SELECT count(*) FROM preKeys;').pluck(true).get();
return (
db
.prepare('SELECT count(*) FROM preKeys;', {
pluck: true,
})
.get<number>() ?? 0
);
}
function getCountOfSignedKeys(): number {
return db.prepare('SELECT count(*) FROM signedPreKeys;').pluck(true).get();
return (
db
.prepare('SELECT count(*) FROM signedPreKeys;', {
pluck: true,
})
.get<number>() ?? 0
);
}
function getPragma(): number {
return db.prepare('PRAGMA user_version;').pluck(true).get();
return db.pragma('user_version', {
simple: true,
}) as number;
}
function generateKyberKey(

View File

@@ -435,7 +435,7 @@ describe('SQL/updateToSchemaVersion89', () => {
`;
return db
.prepare(query)
.all()
.all<{ json: string }>()
.map(row => {
return jsonToObject<MessageType>(row.json);
});

View File

@@ -4,7 +4,14 @@
import { assert } from 'chai';
import type { WritableDB } from '../../sql/Interface';
import { createDB, updateToVersion, insertData, getTableData } from './helpers';
import { sql } from '../../sql/util';
import {
createDB,
updateToVersion,
insertData,
getTableData,
explain,
} from './helpers';
describe('SQL/updateToSchemaVersion90', () => {
let db: WritableDB;
@@ -85,20 +92,16 @@ describe('SQL/updateToSchemaVersion90', () => {
it('should use storyId index', () => {
updateToVersion(db, 90);
const details = db
.prepare(
`
EXPLAIN QUERY PLAN
const details = explain(
db,
sql`
UPDATE messages
SET json = json_remove(json, '$.storyReplyContext.attachment.screenshotData')
WHERE isStory = 0
AND storyId > '0'
AND json->'storyReplyContext.attachment.screenshotData' IS NOT NULL;
`
)
.all()
.map(({ detail }) => detail)
.join('\n');
);
assert.include(details, 'USING INDEX messages_by_storyId');
assert.notInclude(details, 'SCAN');

View File

@@ -50,11 +50,19 @@ describe('SQL/updateToSchemaVersion91', () => {
}
function getCountOfKeys(): number {
return db.prepare('SELECT count(*) FROM preKeys;').pluck(true).get();
return (
db
.prepare('SELECT count(*) FROM preKeys;', {
pluck: true,
})
.get<number>() ?? 0
);
}
function getPragma(): number {
return db.prepare('PRAGMA user_version;').pluck(true).get();
return db.pragma('user_version', {
simple: true,
}) as number;
}
function generateKey(

View File

@@ -60,14 +60,28 @@ describe('SQL/updateToSchemaVersion92', () => {
}
function getCountOfKyberKeys(): number {
return db.prepare('SELECT count(*) FROM kyberPreKeys;').pluck(true).get();
return (
db
.prepare('SELECT count(*) FROM kyberPreKeys;', {
pluck: true,
})
.get<number>() ?? 0
);
}
function getCountOfSignedKeys(): number {
return db.prepare('SELECT count(*) FROM signedPreKeys;').pluck(true).get();
return (
db
.prepare('SELECT count(*) FROM signedPreKeys;', {
pluck: true,
})
.get<number>() ?? 0
);
}
function getPragma(): number {
return db.prepare('PRAGMA user_version;').pluck(true).get();
return db.pragma('user_version', {
simple: true,
}) as number;
}
function generateKyberKey(

File diff suppressed because it is too large Load Diff