mirror of
https://gitlab.com/soapbox-pub/ditto.git
synced 2025-12-06 11:29:46 +00:00
feat: add mime_type column in nostr_events, add the following NIP 50 search extensions:
exact_mime_type, example: 'exact_mime_type:image/png' (uses hash index) partial_mime_type, example 'partial_mime_type:image' (uses b-tree index) only_media, example 'only_media:true' (sometimes uses index)
This commit is contained in:
parent
51fc0c9cc9
commit
b037be44a4
4 changed files with 86 additions and 0 deletions
|
|
@ -14,6 +14,7 @@ export interface DittoTables extends NPostgresSchema {
|
||||||
|
|
||||||
type NostrEventsRow = NPostgresSchema['nostr_events'] & {
|
type NostrEventsRow = NPostgresSchema['nostr_events'] & {
|
||||||
language: string | null;
|
language: string | null;
|
||||||
|
mime_type: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface AuthorStatsRow {
|
interface AuthorStatsRow {
|
||||||
|
|
|
||||||
40
src/db/migrations/042_add_mime_type.ts
Normal file
40
src/db/migrations/042_add_mime_type.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { Kysely, sql } from 'kysely';
|
||||||
|
|
||||||
|
export async function up(db: Kysely<any>): Promise<void> {
|
||||||
|
await db.schema
|
||||||
|
.alterTable('nostr_events')
|
||||||
|
.addColumn('mime_type', 'text').execute();
|
||||||
|
|
||||||
|
await db.schema
|
||||||
|
.createIndex('nostr_events_mime_type_prefix_idx')
|
||||||
|
.on('nostr_events')
|
||||||
|
.expression(sql`split_part(mime_type, '/', 1)`)
|
||||||
|
.column('mime_type')
|
||||||
|
.ifNotExists()
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
await db.schema
|
||||||
|
.createIndex('nostr_events_mime_type_hash_idx')
|
||||||
|
.on('nostr_events')
|
||||||
|
.column('mime_type')
|
||||||
|
.using('hash')
|
||||||
|
.ifNotExists()
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(db: Kysely<any>): Promise<void> {
|
||||||
|
await db.schema
|
||||||
|
.alterTable('nostr_events')
|
||||||
|
.dropColumn('mime_type')
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
await db.schema
|
||||||
|
.dropIndex('nostr_events_mime_type_prefix_idx')
|
||||||
|
.on('nostr_events')
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
await db.schema
|
||||||
|
.dropIndex('nostr_events_mime_type_hash_idx')
|
||||||
|
.on('nostr_events')
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
@ -103,6 +103,7 @@ async function handleEvent(event: DittoEvent, signal: AbortSignal): Promise<void
|
||||||
handleZaps(kysely, event),
|
handleZaps(kysely, event),
|
||||||
parseMetadata(event, signal),
|
parseMetadata(event, signal),
|
||||||
setLanguage(event),
|
setLanguage(event),
|
||||||
|
setMimeType(event),
|
||||||
generateSetEvents(event),
|
generateSetEvents(event),
|
||||||
])
|
])
|
||||||
.then(() =>
|
.then(() =>
|
||||||
|
|
@ -248,6 +249,25 @@ async function setLanguage(event: NostrEvent): Promise<void> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Update the event in the database and set its MIME type. */
|
||||||
|
async function setMimeType(event: NostrEvent): Promise<void> {
|
||||||
|
const imeta = event.tags.find(([value]) => value === 'imeta');
|
||||||
|
if (!imeta) return;
|
||||||
|
|
||||||
|
const mime_type = imeta.find((value) => value?.split(' ')[0] === 'm')?.split(' ')[1];
|
||||||
|
if (!mime_type) return;
|
||||||
|
|
||||||
|
const kysely = await Storages.kysely();
|
||||||
|
try {
|
||||||
|
await kysely.updateTable('nostr_events')
|
||||||
|
.set('mime_type', mime_type)
|
||||||
|
.where('id', '=', event.id)
|
||||||
|
.execute();
|
||||||
|
} catch {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Determine if the event is being received in a timely manner. */
|
/** Determine if the event is being received in a timely manner. */
|
||||||
function isFresh(event: NostrEvent): boolean {
|
function isFresh(event: NostrEvent): boolean {
|
||||||
return eventAge(event) < Time.minutes(1);
|
return eventAge(event) < Time.minutes(1);
|
||||||
|
|
|
||||||
|
|
@ -158,16 +158,41 @@ class EventsDB extends NPostgres {
|
||||||
}) as SelectQueryBuilder<DittoTables, 'nostr_events', DittoTables['nostr_events']>;
|
}) as SelectQueryBuilder<DittoTables, 'nostr_events', DittoTables['nostr_events']>;
|
||||||
|
|
||||||
const languages = new Set<string>();
|
const languages = new Set<string>();
|
||||||
|
let exact_mime_type: string | undefined;
|
||||||
|
let partial_mime_type: string | undefined;
|
||||||
|
let only_media: boolean | undefined;
|
||||||
|
|
||||||
for (const token of tokens) {
|
for (const token of tokens) {
|
||||||
if (typeof token === 'object' && token.key === 'language') {
|
if (typeof token === 'object' && token.key === 'language') {
|
||||||
languages.add(token.value);
|
languages.add(token.value);
|
||||||
}
|
}
|
||||||
|
if (typeof token === 'object' && token.key === 'exact_mime_type') {
|
||||||
|
exact_mime_type = token.value;
|
||||||
|
}
|
||||||
|
if (typeof token === 'object' && token.key === 'partial_mime_type') {
|
||||||
|
partial_mime_type = token.value;
|
||||||
|
}
|
||||||
|
if (typeof token === 'object' && token.key === 'only_media') {
|
||||||
|
if (token.value === 'true') only_media = true;
|
||||||
|
if (token.value === 'false') only_media = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (languages.size) {
|
if (languages.size) {
|
||||||
query = query.where('language', 'in', [...languages]);
|
query = query.where('language', 'in', [...languages]);
|
||||||
}
|
}
|
||||||
|
if (exact_mime_type) {
|
||||||
|
query = query.where('mime_type', '=', exact_mime_type);
|
||||||
|
}
|
||||||
|
if (partial_mime_type) {
|
||||||
|
query = query.where(
|
||||||
|
(eb) => eb.fn('split_part', [eb.ref('mime_type'), eb.val('/'), eb.val(1)]),
|
||||||
|
'=',
|
||||||
|
partial_mime_type,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (only_media) query = query.where('mime_type', 'is not', null);
|
||||||
|
if (only_media === false) query = query.where('mime_type', 'is', null);
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue