fix PRE and RE query/insert

This commit is contained in:
Sandwich 2024-11-19 00:05:14 +01:00
parent f8f07a02bb
commit 048fdf463b

View File

@ -34,7 +34,7 @@ export class SqliteRelay extends EventEmitter<RelayHandlerEvents> implements Rel
await this.#open(path); await this.#open(path);
if (this.db) { if (this.db) {
await migrate(this); await migrate(this);
// dont await to avoid timeout // don't await to avoid timeout
runFixers(this); runFixers(this);
} }
} }
@ -128,69 +128,82 @@ export class SqliteRelay extends EventEmitter<RelayHandlerEvents> implements Rel
#insertEvent(db: Database, ev: NostrEvent) { #insertEvent(db: Database, ev: NostrEvent) {
if (this.#seenInserts.has(ev.id)) return false; if (this.#seenInserts.has(ev.id)) return false;
const legacyReplacable = [0, 3, 41]; const legacyReplaceableKinds = [0, 3, 41];
if (legacyReplacable.includes(ev.kind) || (ev.kind >= 10_000 && ev.kind < 20_000)) {
const oldEvents = db.selectValues("select id from events where kind = ? and pubkey = ? and created <= ?", [ // Handle legacy and standard replaceable events (kinds 0, 3, 41, 10000-19999)
ev.kind, if (legacyReplaceableKinds.includes(ev.kind) || (ev.kind >= 10_000 && ev.kind < 20_000)) {
ev.pubkey,
ev.created_at,
]) as Array<string>;
if (oldEvents.includes(ev.id)) {
// we already have this event, return
this.#seenInserts.add(ev.id);
if (oldEvents.length > 1) {
const toDelete = oldEvents.filter(a => a !== ev.id);
this.#deleteById(db, toDelete);
}
return false;
} else {
// delete older versions
this.#deleteById(db, oldEvents);
}
}
if (ev.kind >= 30_000 && ev.kind < 40_000) {
const dTag = ev.tags.find(a => a[0] === "d")![1];
const oldEvents = db.selectValues( const oldEvents = db.selectValues(
"select id from events where id in (select id from events, tags where events.id = tags.event_id and tags.key = ? and tags.value = ?)", `SELECT id FROM events WHERE kind = ? AND pubkey = ? AND created <= ?`,
["d", dTag], [ev.kind, ev.pubkey, ev.created_at]
) as Array<string>; ) as Array<string>;
if (oldEvents.includes(ev.id)) { if (oldEvents.includes(ev.id)) {
// we have this version // Already have this event
this.#seenInserts.add(ev.id); this.#seenInserts.add(ev.id);
if (oldEvents.length > 1) {
const toDelete = oldEvents.filter(a => a !== ev.id);
this.#deleteById(db, toDelete);
}
return false; return false;
} else { } else {
// delete older versions // Delete older events of the same kind and pubkey
this.#deleteById(db, oldEvents); this.#deleteById(db, oldEvents);
} }
} }
// remove relays from event json // Handle parameterized replaceable events (kinds 30000-39999)
const evInsert = { if (ev.kind >= 30_000 && ev.kind < 40_000) {
...ev, const dTag = ev.tags.find(a => a[0] === "d")?.[1] ?? "";
} as NostrEvent;
delete evInsert["relays"]; const oldEvents = db.selectValues(
`SELECT e.id
FROM events e
JOIN tags t ON e.id = t.event_id
WHERE e.kind = ? AND e.pubkey = ? AND t.key = ? AND t.value = ? AND created <= ?`,
[ev.kind, ev.pubkey, "d", dTag, ev.created_at]
) as Array<string>;
if (oldEvents.includes(ev.id)) {
// Already have this event
this.#seenInserts.add(ev.id);
return false;
} else {
// Delete older events with the same kind, pubkey, and d tag
this.#deleteById(db, oldEvents);
}
}
// Proceed to insert the new event
const evInsert = { ...ev };
delete evInsert["relays"]; // Remove non-DB fields
db.exec(
`INSERT OR IGNORE INTO events(id, pubkey, created, kind, json, relays)
VALUES(?,?,?,?,?,?)`,
{
bind: [
ev.id,
ev.pubkey,
ev.created_at,
ev.kind,
JSON.stringify(evInsert),
(ev.relays ?? []).join(","),
],
}
);
db.exec("insert or ignore into events(id, pubkey, created, kind, json, relays) values(?,?,?,?,?,?)", {
bind: [ev.id, ev.pubkey, ev.created_at, ev.kind, JSON.stringify(evInsert), (ev.relays ?? []).join(",")],
});
const insertedEvents = db.changes(); const insertedEvents = db.changes();
if (insertedEvents > 0) { if (insertedEvents > 0) {
// Insert tags
for (const t of ev.tags.filter(a => a[0].length === 1)) { for (const t of ev.tags.filter(a => a[0].length === 1)) {
db.exec("insert into tags(event_id, key, value) values(?, ?, ?)", { db.exec("INSERT INTO tags(event_id, key, value) VALUES(?, ?, ?)", {
bind: [ev.id, t[0], t[1]], bind: [ev.id, t[0], t[1]],
}); });
} }
this.insertIntoSearchIndex(db, ev); this.insertIntoSearchIndex(db, ev);
} else { } else {
this.#updateRelays(db, ev); this.#updateRelays(db, ev);
return 0; return false;
} }
this.#seenInserts.add(ev.id); this.#seenInserts.add(ev.id);
return insertedEvents; return true;
} }
/** /**
@ -332,15 +345,6 @@ export class SqliteRelay extends EventEmitter<RelayHandlerEvents> implements Rel
params.push(...vArray); params.push(...vArray);
tx++; tx++;
} }
const andTags = Object.entries(req).filter(([k]) => k.startsWith("&"));
for (const [key, values] of andTags) {
for (const value of values as Array<string>) {
sql += ` inner join tags t_${tx} on events.id = t_${tx}.event_id and t_${tx}.key = ? and t_${tx}.value = ?`;
params.push(key.slice(1));
params.push(value);
tx++;
}
}
if (req.search) { if (req.search) {
sql += " inner join search_content on search_content.id = events.id"; sql += " inner join search_content on search_content.id = events.id";
conditions.push("search_content match ?"); conditions.push("search_content match ?");