Use new DittoDB module, rename old interface to DittoTables
This commit is contained in:
parent
4085443e45
commit
3753648f99
91
src/db.ts
91
src/db.ts
|
@ -1,93 +1,10 @@
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
|
||||||
import { FileMigrationProvider, Kysely, Migrator, PolySqliteDialect } from '@/deps.ts';
|
import { DittoDB } from '@/db/DittoDB.ts';
|
||||||
import { Conf } from '@/config.ts';
|
import { FileMigrationProvider, Migrator } from '@/deps.ts';
|
||||||
import { setPragma } from '@/pragma.ts';
|
|
||||||
import SqliteWorker from '@/workers/sqlite.ts';
|
|
||||||
|
|
||||||
interface DittoDB {
|
const db = await DittoDB.getInstance();
|
||||||
events: EventRow;
|
|
||||||
events_fts: EventFTSRow;
|
|
||||||
tags: TagRow;
|
|
||||||
relays: RelayRow;
|
|
||||||
unattached_media: UnattachedMediaRow;
|
|
||||||
author_stats: AuthorStatsRow;
|
|
||||||
event_stats: EventStatsRow;
|
|
||||||
pubkey_domains: PubkeyDomainRow;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AuthorStatsRow {
|
|
||||||
pubkey: string;
|
|
||||||
followers_count: number;
|
|
||||||
following_count: number;
|
|
||||||
notes_count: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface EventStatsRow {
|
|
||||||
event_id: string;
|
|
||||||
replies_count: number;
|
|
||||||
reposts_count: number;
|
|
||||||
reactions_count: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface EventRow {
|
|
||||||
id: string;
|
|
||||||
kind: number;
|
|
||||||
pubkey: string;
|
|
||||||
content: string;
|
|
||||||
created_at: number;
|
|
||||||
tags: string;
|
|
||||||
sig: string;
|
|
||||||
deleted_at: number | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface EventFTSRow {
|
|
||||||
id: string;
|
|
||||||
content: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TagRow {
|
|
||||||
tag: string;
|
|
||||||
value: string;
|
|
||||||
event_id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface RelayRow {
|
|
||||||
url: string;
|
|
||||||
domain: string;
|
|
||||||
active: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface UnattachedMediaRow {
|
|
||||||
id: string;
|
|
||||||
pubkey: string;
|
|
||||||
url: string;
|
|
||||||
data: string;
|
|
||||||
uploaded_at: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PubkeyDomainRow {
|
|
||||||
pubkey: string;
|
|
||||||
domain: string;
|
|
||||||
last_updated_at: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sqliteWorker = new SqliteWorker();
|
|
||||||
await sqliteWorker.open(Conf.dbPath);
|
|
||||||
|
|
||||||
const db = new Kysely<DittoDB>({
|
|
||||||
dialect: new PolySqliteDialect({
|
|
||||||
database: sqliteWorker,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set PRAGMA values.
|
|
||||||
await Promise.all([
|
|
||||||
setPragma(db, 'synchronous', 'normal'),
|
|
||||||
setPragma(db, 'temp_store', 'memory'),
|
|
||||||
setPragma(db, 'mmap_size', Conf.sqlite.mmapSize),
|
|
||||||
]);
|
|
||||||
|
|
||||||
const migrator = new Migrator({
|
const migrator = new Migrator({
|
||||||
db,
|
db,
|
||||||
|
@ -120,4 +37,4 @@ async function migrate() {
|
||||||
|
|
||||||
await migrate();
|
await migrate();
|
||||||
|
|
||||||
export { type AuthorStatsRow, db, type DittoDB, type EventRow, type EventStatsRow, type TagRow };
|
export { db };
|
||||||
|
|
|
@ -14,4 +14,4 @@ export class DittoDB {
|
||||||
throw new Error('Unsupported database URL.');
|
throw new Error('Unsupported database URL.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
17
src/stats.ts
17
src/stats.ts
|
@ -1,10 +1,11 @@
|
||||||
import { type AuthorStatsRow, db, type DittoDB, type EventStatsRow } from '@/db.ts';
|
import { db } from '@/db.ts';
|
||||||
|
import { DittoTables } from '@/db/DittoTables.ts';
|
||||||
import { Debug, type InsertQueryBuilder, type NostrEvent } from '@/deps.ts';
|
import { Debug, type InsertQueryBuilder, type NostrEvent } from '@/deps.ts';
|
||||||
import { eventsDB } from '@/storages.ts';
|
import { eventsDB } from '@/storages.ts';
|
||||||
import { findReplyTag } from '@/tags.ts';
|
import { findReplyTag } from '@/tags.ts';
|
||||||
|
|
||||||
type AuthorStat = keyof Omit<AuthorStatsRow, 'pubkey'>;
|
type AuthorStat = keyof Omit<DittoTables['author_stats'], 'pubkey'>;
|
||||||
type EventStat = keyof Omit<EventStatsRow, 'event_id'>;
|
type EventStat = keyof Omit<DittoTables['event_stats'], 'event_id'>;
|
||||||
|
|
||||||
type AuthorStatDiff = ['author_stats', pubkey: string, stat: AuthorStat, diff: number];
|
type AuthorStatDiff = ['author_stats', pubkey: string, stat: AuthorStat, diff: number];
|
||||||
type EventStatDiff = ['event_stats', eventId: string, stat: EventStat, diff: number];
|
type EventStatDiff = ['event_stats', eventId: string, stat: EventStat, diff: number];
|
||||||
|
@ -15,7 +16,7 @@ const debug = Debug('ditto:stats');
|
||||||
/** Store stats for the event in LMDB. */
|
/** Store stats for the event in LMDB. */
|
||||||
async function updateStats(event: NostrEvent) {
|
async function updateStats(event: NostrEvent) {
|
||||||
let prev: NostrEvent | undefined;
|
let prev: NostrEvent | undefined;
|
||||||
const queries: InsertQueryBuilder<DittoDB, any, unknown>[] = [];
|
const queries: InsertQueryBuilder<DittoTables, any, unknown>[] = [];
|
||||||
|
|
||||||
// Kind 3 is a special case - replace the count with the new list.
|
// Kind 3 is a special case - replace the count with the new list.
|
||||||
if (event.kind === 3) {
|
if (event.kind === 3) {
|
||||||
|
@ -98,8 +99,8 @@ async function getStatsDiff(event: NostrEvent, prev: NostrEvent | undefined): Pr
|
||||||
|
|
||||||
/** Create an author stats query from the list of diffs. */
|
/** Create an author stats query from the list of diffs. */
|
||||||
function authorStatsQuery(diffs: AuthorStatDiff[]) {
|
function authorStatsQuery(diffs: AuthorStatDiff[]) {
|
||||||
const values: AuthorStatsRow[] = diffs.map(([_, pubkey, stat, diff]) => {
|
const values: DittoTables['author_stats'][] = diffs.map(([_, pubkey, stat, diff]) => {
|
||||||
const row: AuthorStatsRow = {
|
const row: DittoTables['author_stats'] = {
|
||||||
pubkey,
|
pubkey,
|
||||||
followers_count: 0,
|
followers_count: 0,
|
||||||
following_count: 0,
|
following_count: 0,
|
||||||
|
@ -124,8 +125,8 @@ function authorStatsQuery(diffs: AuthorStatDiff[]) {
|
||||||
|
|
||||||
/** Create an event stats query from the list of diffs. */
|
/** Create an event stats query from the list of diffs. */
|
||||||
function eventStatsQuery(diffs: EventStatDiff[]) {
|
function eventStatsQuery(diffs: EventStatDiff[]) {
|
||||||
const values: EventStatsRow[] = diffs.map(([_, event_id, stat, diff]) => {
|
const values: DittoTables['event_stats'][] = diffs.map(([_, event_id, stat, diff]) => {
|
||||||
const row: EventStatsRow = {
|
const row: DittoTables['event_stats'] = {
|
||||||
event_id,
|
event_id,
|
||||||
replies_count: 0,
|
replies_count: 0,
|
||||||
reposts_count: 0,
|
reposts_count: 0,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { NIP50, NostrFilter } from '@soapbox/nspec';
|
import { NIP50, NostrFilter } from '@soapbox/nspec';
|
||||||
import { Conf } from '@/config.ts';
|
import { Conf } from '@/config.ts';
|
||||||
import { type DittoDB } from '@/db.ts';
|
import { DittoTables } from '@/db/DittoTables.ts';
|
||||||
import { Debug, Kysely, type NostrEvent, type NStore, type NStoreOpts, type SelectQueryBuilder } from '@/deps.ts';
|
import { Debug, Kysely, type NostrEvent, type NStore, type NStoreOpts, type SelectQueryBuilder } from '@/deps.ts';
|
||||||
import { normalizeFilters } from '@/filter.ts';
|
import { normalizeFilters } from '@/filter.ts';
|
||||||
import { DittoEvent } from '@/interfaces/DittoEvent.ts';
|
import { DittoEvent } from '@/interfaces/DittoEvent.ts';
|
||||||
|
@ -33,7 +33,7 @@ const tagConditions: Record<string, TagCondition> = {
|
||||||
'role': ({ event, count }) => event.kind === 30361 && count === 0,
|
'role': ({ event, count }) => event.kind === 30361 && count === 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
type EventQuery = SelectQueryBuilder<DittoDB, 'events', {
|
type EventQuery = SelectQueryBuilder<DittoTables, 'events', {
|
||||||
id: string;
|
id: string;
|
||||||
tags: string;
|
tags: string;
|
||||||
kind: number;
|
kind: number;
|
||||||
|
@ -58,10 +58,10 @@ type EventQuery = SelectQueryBuilder<DittoDB, 'events', {
|
||||||
|
|
||||||
/** SQLite database storage adapter for Nostr events. */
|
/** SQLite database storage adapter for Nostr events. */
|
||||||
class EventsDB implements NStore {
|
class EventsDB implements NStore {
|
||||||
#db: Kysely<DittoDB>;
|
#db: Kysely<DittoTables>;
|
||||||
#debug = Debug('ditto:db:events');
|
#debug = Debug('ditto:db:events');
|
||||||
|
|
||||||
constructor(db: Kysely<DittoDB>) {
|
constructor(db: Kysely<DittoTables>) {
|
||||||
this.#db = db;
|
this.#db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ class EventsDB implements NStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Build the query for a filter. */
|
/** Build the query for a filter. */
|
||||||
getFilterQuery(db: Kysely<DittoDB>, filter: NostrFilter): EventQuery {
|
getFilterQuery(db: Kysely<DittoTables>, filter: NostrFilter): EventQuery {
|
||||||
let query = db
|
let query = db
|
||||||
.selectFrom('events')
|
.selectFrom('events')
|
||||||
.select([
|
.select([
|
||||||
|
@ -315,7 +315,7 @@ class EventsDB implements NStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Delete events from each table. Should be run in a transaction! */
|
/** Delete events from each table. Should be run in a transaction! */
|
||||||
async deleteEventsTrx(db: Kysely<DittoDB>, filters: NostrFilter[]) {
|
async deleteEventsTrx(db: Kysely<DittoTables>, filters: NostrFilter[]) {
|
||||||
if (!filters.length) return Promise.resolve();
|
if (!filters.length) return Promise.resolve();
|
||||||
this.#debug('DELETE', JSON.stringify(filters));
|
this.#debug('DELETE', JSON.stringify(filters));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue