diff --git a/src/db.ts b/src/db.ts index a5f52af..e371ac9 100644 --- a/src/db.ts +++ b/src/db.ts @@ -29,9 +29,7 @@ interface EventFTSRow { interface TagRow { tag: string; - value_1: string | null; - value_2: string | null; - value_3: string | null; + value: string; event_id: string; } diff --git a/src/db/events.ts b/src/db/events.ts index efb5afc..fdca7ca 100644 --- a/src/db/events.ts +++ b/src/db/events.ts @@ -34,17 +34,14 @@ function insertEvent(event: Event): Promise { } const tagCounts: Record = {}; - const tags = event.tags.reduce[]>((results, tag) => { - const tagName = tag[0]; - tagCounts[tagName] = (tagCounts[tagName] || 0) + 1; + const tags = event.tags.reduce[]>((results, [name, value]) => { + tagCounts[name] = (tagCounts[name] || 0) + 1; - if (tagConditions[tagName]?.({ event, count: tagCounts[tagName] - 1 })) { + if (value && tagConditions[name]?.({ event, count: tagCounts[name] - 1 })) { results.push({ event_id: event.id, - tag: tagName, - value_1: tag[1] || null, - value_2: tag[2] || null, - value_3: tag[3] || null, + tag: name, + value, }); } @@ -111,7 +108,7 @@ function getFilterQuery(filter: DittoFilter) { query = query .leftJoin('tags', 'tags.event_id', 'events.id') .where('tags.tag', '=', tag) - .where('tags.value_1', 'in', value) as typeof query; + .where('tags.value', 'in', value) as typeof query; } } @@ -157,19 +154,11 @@ async function getFilters( /** Delete events based on filters from the database. */ function deleteFilters(filters: DittoFilter[]) { if (!filters.length) return Promise.resolve([]); + const query = getFiltersQuery(filters); - return db.transaction().execute(async (trx) => { - const query = getFiltersQuery(filters).clearSelect().select('id'); - - await trx.deleteFrom('tags') - .where('event_id', 'in', () => query) - .where('tag', 'not in', ['d', 'proxy']) - .execute(); - - return trx.deleteFrom('events') - .where('id', 'in', () => query) - .execute(); - }); + return db.deleteFrom('events') + .where('id', 'in', () => query.clearSelect().select('id')) + .execute(); } /** Get number of events that would be returned by filters. */ diff --git a/src/db/migrations/005_rework_tags.ts b/src/db/migrations/005_rework_tags.ts new file mode 100644 index 0000000..f274670 --- /dev/null +++ b/src/db/migrations/005_rework_tags.ts @@ -0,0 +1,68 @@ +import { Kysely, sql } from '@/deps.ts'; + +export async function up(db: Kysely): Promise { + await db.schema + .createTable('tags_new') + .addColumn('tag', 'text', (col) => col.notNull()) + .addColumn('value', 'text', (col) => col.notNull()) + .addColumn('event_id', 'text', (col) => col.references('events.id').onDelete('cascade')) + .execute(); + + await sql` + INSERT INTO tags_new (tag, value, event_id) + SELECT tag, value_1 as value, event_id + FROM tags + WHERE value_1 IS NOT NULL + `.execute(db); + + await db.schema + .dropTable('tags') + .execute(); + + await db.schema + .alterTable('tags_new') + .renameTo('tags').execute(); + + await db.schema + .createIndex('idx_tags_tag') + .on('tags') + .column('tag') + .execute(); + + await db.schema + .createIndex('idx_tags_value') + .on('tags') + .column('value') + .execute(); + + await db.schema + .createIndex('idx_tags_event_id') + .on('tags') + .column('event_id') + .execute(); +} + +export async function down(db: Kysely): Promise { + await db.schema.dropTable('tags').execute(); + + await db.schema + .createTable('tags') + .addColumn('tag', 'text', (col) => col.notNull()) + .addColumn('value_1', 'text') + .addColumn('value_2', 'text') + .addColumn('value_3', 'text') + .addColumn('event_id', 'text', (col) => col.notNull()) + .execute(); + + await db.schema + .createIndex('idx_tags_tag') + .on('tags') + .column('tag') + .execute(); + + await db.schema + .createIndex('idx_tags_value_1') + .on('tags') + .column('value_1') + .execute(); +}