Adds created_at to tags to speed up tag-ordered queries
This commit is contained in:
+2
-2
@@ -227,8 +227,8 @@ class DeletionTest {
|
|||||||
ON event_headers.row_id = event_tags.event_header_row_id
|
ON event_headers.row_id = event_tags.event_header_row_id
|
||||||
WHERE
|
WHERE
|
||||||
event_tags.tag_hash IN (3221122, 223322) AND
|
event_tags.tag_hash IN (3221122, 223322) AND
|
||||||
|
event_tags.created_at >= 1766686500 AND
|
||||||
event_headers.kind = 5 AND
|
event_headers.kind = 5 AND
|
||||||
event_headers.created_at >= 1766686500 AND
|
|
||||||
event_headers.pubkey_owner_hash = 22332323
|
event_headers.pubkey_owner_hash = 22332323
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
@@ -238,7 +238,7 @@ class DeletionTest {
|
|||||||
TestCase.assertEquals(
|
TestCase.assertEquals(
|
||||||
"""
|
"""
|
||||||
${sql.replace("\n","\n ")}
|
${sql.replace("\n","\n ")}
|
||||||
├── SEARCH event_tags USING COVERING INDEX query_by_tags_hash (tag_hash=?)
|
├── SEARCH event_tags USING INDEX query_by_tags_hash (tag_hash=? AND created_at>?)
|
||||||
└── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
└── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
explainer,
|
explainer,
|
||||||
|
|||||||
+25
-24
@@ -31,7 +31,7 @@ import org.junit.Before
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class QueryAssemblerTest {
|
class QueryAssemblerTest {
|
||||||
val hasher = TagNameValueHasher(0L)
|
val hasher = TagNameValueHasher(0)
|
||||||
val builder = EventIndexesModule(FullTextSearchModule(), { hasher })
|
val builder = EventIndexesModule(FullTextSearchModule(), { hasher })
|
||||||
|
|
||||||
val key1 = "7c5eb72a4584fdaaeaa145b25c92ea9917704224951219dbd43acef9e91fb88d"
|
val key1 = "7c5eb72a4584fdaaeaa145b25c92ea9917704224951219dbd43acef9e91fb88d"
|
||||||
@@ -81,13 +81,14 @@ class QueryAssemblerTest {
|
|||||||
"""
|
"""
|
||||||
SELECT id, pubkey, created_at, kind, tags, content, sig FROM event_headers
|
SELECT id, pubkey, created_at, kind, tags, content, sig FROM event_headers
|
||||||
INNER JOIN (
|
INNER JOIN (
|
||||||
SELECT DISTINCT(event_tags.event_header_row_id) as row_id FROM event_tags INNER JOIN event_headers ON event_headers.row_id = event_tags.event_header_row_id WHERE (event_headers.created_at >= "1750889190") AND (event_tags.tag_hash = "2657743813502222172") AND (event_headers.kind = "5") AND (event_headers.pubkey = "7c5eb72a4584fdaaeaa145b25c92ea9917704224951219dbd43acef9e91fb88d")
|
SELECT DISTINCT(event_tags.event_header_row_id) as row_id FROM event_tags INNER JOIN event_headers ON event_headers.row_id = event_tags.event_header_row_id WHERE (event_tags.tag_hash = "2657743813502222172") AND (event_tags.created_at >= "1750889190") AND (event_headers.kind = "5") AND (event_headers.pubkey = "7c5eb72a4584fdaaeaa145b25c92ea9917704224951219dbd43acef9e91fb88d")
|
||||||
) AS filtered
|
) AS filtered
|
||||||
ON event_headers.row_id = filtered.row_id
|
ON event_headers.row_id = filtered.row_id
|
||||||
ORDER BY created_at DESC, id
|
ORDER BY created_at DESC, id
|
||||||
├── CO-ROUTINE filtered
|
├── CO-ROUTINE filtered
|
||||||
│ ├── SEARCH event_tags USING COVERING INDEX query_by_tags_hash (tag_hash=?)
|
│ ├── SEARCH event_tags USING INDEX query_by_tags_hash (tag_hash=? AND created_at>?)
|
||||||
│ └── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
│ ├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
||||||
|
│ └── USE TEMP B-TREE FOR DISTINCT
|
||||||
├── SCAN filtered
|
├── SCAN filtered
|
||||||
├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
||||||
└── USE TEMP B-TREE FOR ORDER BY
|
└── USE TEMP B-TREE FOR ORDER BY
|
||||||
@@ -278,14 +279,14 @@ class QueryAssemblerTest {
|
|||||||
"""
|
"""
|
||||||
SELECT id, pubkey, created_at, kind, tags, content, sig FROM event_headers
|
SELECT id, pubkey, created_at, kind, tags, content, sig FROM event_headers
|
||||||
INNER JOIN (
|
INNER JOIN (
|
||||||
SELECT DISTINCT(event_tags.event_header_row_id) as row_id FROM event_tags INNER JOIN event_headers ON event_headers.row_id = event_tags.event_header_row_id WHERE (event_tags.tag_hash = "-4551135004136952885") AND (event_headers.kind = "3") ORDER BY event_headers.created_at DESC, event_headers.id ASC LIMIT 30
|
SELECT DISTINCT(event_tags.event_header_row_id) as row_id FROM event_tags INNER JOIN event_headers ON event_headers.row_id = event_tags.event_header_row_id WHERE (event_tags.tag_hash = "-4551135004136952885") AND (event_headers.kind = "3") ORDER BY event_tags.created_at DESC LIMIT 30
|
||||||
) AS filtered
|
) AS filtered
|
||||||
ON event_headers.row_id = filtered.row_id
|
ON event_headers.row_id = filtered.row_id
|
||||||
ORDER BY created_at DESC, id
|
ORDER BY created_at DESC, id
|
||||||
├── CO-ROUTINE filtered
|
├── CO-ROUTINE filtered
|
||||||
│ ├── SEARCH event_tags USING COVERING INDEX query_by_tags_hash (tag_hash=?)
|
│ ├── SEARCH event_tags USING INDEX query_by_tags_hash (tag_hash=?)
|
||||||
│ ├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
│ ├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
||||||
│ └── USE TEMP B-TREE FOR ORDER BY
|
│ └── USE TEMP B-TREE FOR DISTINCT
|
||||||
├── SCAN filtered
|
├── SCAN filtered
|
||||||
├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
||||||
└── USE TEMP B-TREE FOR ORDER BY
|
└── USE TEMP B-TREE FOR ORDER BY
|
||||||
@@ -309,14 +310,13 @@ class QueryAssemblerTest {
|
|||||||
"""
|
"""
|
||||||
SELECT id, pubkey, created_at, kind, tags, content, sig FROM event_headers
|
SELECT id, pubkey, created_at, kind, tags, content, sig FROM event_headers
|
||||||
INNER JOIN (
|
INNER JOIN (
|
||||||
SELECT DISTINCT(event_tags.event_header_row_id) as row_id FROM event_tags INNER JOIN event_headers ON event_headers.row_id = event_tags.event_header_row_id WHERE event_tags.tag_hash = "-4551135004136952885" ORDER BY event_headers.created_at DESC, event_headers.id ASC LIMIT 30
|
SELECT DISTINCT(event_tags.event_header_row_id) as row_id FROM event_tags WHERE event_tags.tag_hash = "-4551135004136952885" ORDER BY event_tags.created_at DESC LIMIT 30
|
||||||
) AS filtered
|
) AS filtered
|
||||||
ON event_headers.row_id = filtered.row_id
|
ON event_headers.row_id = filtered.row_id
|
||||||
ORDER BY created_at DESC, id
|
ORDER BY created_at DESC, id
|
||||||
├── CO-ROUTINE filtered
|
├── CO-ROUTINE filtered
|
||||||
│ ├── SEARCH event_tags USING COVERING INDEX query_by_tags_hash (tag_hash=?)
|
│ ├── SEARCH event_tags USING INDEX query_by_tags_hash (tag_hash=?)
|
||||||
│ ├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
│ └── USE TEMP B-TREE FOR DISTINCT
|
||||||
│ └── USE TEMP B-TREE FOR ORDER BY
|
|
||||||
├── SCAN filtered
|
├── SCAN filtered
|
||||||
├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
||||||
└── USE TEMP B-TREE FOR ORDER BY
|
└── USE TEMP B-TREE FOR ORDER BY
|
||||||
@@ -344,14 +344,14 @@ class QueryAssemblerTest {
|
|||||||
"""
|
"""
|
||||||
SELECT id, pubkey, created_at, kind, tags, content, sig FROM event_headers
|
SELECT id, pubkey, created_at, kind, tags, content, sig FROM event_headers
|
||||||
INNER JOIN (
|
INNER JOIN (
|
||||||
SELECT DISTINCT(event_tags.event_header_row_id) as row_id FROM event_tags INNER JOIN event_headers ON event_headers.row_id = event_tags.event_header_row_id WHERE (event_tags.tag_hash = "-4551135004136952885") AND (event_headers.kind = "3") ORDER BY event_headers.created_at DESC, event_headers.id ASC LIMIT 30
|
SELECT DISTINCT(event_tags.event_header_row_id) as row_id FROM event_tags INNER JOIN event_headers ON event_headers.row_id = event_tags.event_header_row_id WHERE (event_tags.tag_hash = "-4551135004136952885") AND (event_headers.kind = "3") ORDER BY event_tags.created_at DESC LIMIT 30
|
||||||
) AS filtered
|
) AS filtered
|
||||||
ON event_headers.row_id = filtered.row_id
|
ON event_headers.row_id = filtered.row_id
|
||||||
ORDER BY created_at DESC, id
|
ORDER BY created_at DESC, id
|
||||||
├── CO-ROUTINE filtered
|
├── CO-ROUTINE filtered
|
||||||
│ ├── SEARCH event_tags USING COVERING INDEX query_by_tags_hash (tag_hash=?)
|
│ ├── SEARCH event_tags USING INDEX query_by_tags_hash (tag_hash=?)
|
||||||
│ ├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
│ ├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
||||||
│ └── USE TEMP B-TREE FOR ORDER BY
|
│ └── USE TEMP B-TREE FOR DISTINCT
|
||||||
├── SCAN filtered
|
├── SCAN filtered
|
||||||
├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
||||||
└── USE TEMP B-TREE FOR ORDER BY
|
└── USE TEMP B-TREE FOR ORDER BY
|
||||||
@@ -376,14 +376,14 @@ class QueryAssemblerTest {
|
|||||||
"""
|
"""
|
||||||
SELECT id, pubkey, created_at, kind, tags, content, sig FROM event_headers
|
SELECT id, pubkey, created_at, kind, tags, content, sig FROM event_headers
|
||||||
INNER JOIN (
|
INNER JOIN (
|
||||||
SELECT DISTINCT(event_tags.event_header_row_id) as row_id FROM event_tags INNER JOIN event_headers ON event_headers.row_id = event_tags.event_header_row_id WHERE (event_tags.tag_hash = "-4551135004136952885") AND (event_headers.pubkey = "7c5eb72a4584fdaaeaa145b25c92ea9917704224951219dbd43acef9e91fb88d") ORDER BY event_headers.created_at DESC, event_headers.id ASC LIMIT 30
|
SELECT DISTINCT(event_tags.event_header_row_id) as row_id FROM event_tags INNER JOIN event_headers ON event_headers.row_id = event_tags.event_header_row_id WHERE (event_tags.tag_hash = "-4551135004136952885") AND (event_headers.pubkey = "7c5eb72a4584fdaaeaa145b25c92ea9917704224951219dbd43acef9e91fb88d") ORDER BY event_tags.created_at DESC LIMIT 30
|
||||||
) AS filtered
|
) AS filtered
|
||||||
ON event_headers.row_id = filtered.row_id
|
ON event_headers.row_id = filtered.row_id
|
||||||
ORDER BY created_at DESC, id
|
ORDER BY created_at DESC, id
|
||||||
├── CO-ROUTINE filtered
|
├── CO-ROUTINE filtered
|
||||||
│ ├── SEARCH event_tags USING COVERING INDEX query_by_tags_hash (tag_hash=?)
|
│ ├── SEARCH event_tags USING INDEX query_by_tags_hash (tag_hash=?)
|
||||||
│ ├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
│ ├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
||||||
│ └── USE TEMP B-TREE FOR ORDER BY
|
│ └── USE TEMP B-TREE FOR DISTINCT
|
||||||
├── SCAN filtered
|
├── SCAN filtered
|
||||||
├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
||||||
└── USE TEMP B-TREE FOR ORDER BY
|
└── USE TEMP B-TREE FOR ORDER BY
|
||||||
@@ -412,15 +412,15 @@ class QueryAssemblerTest {
|
|||||||
"""
|
"""
|
||||||
SELECT id, pubkey, created_at, kind, tags, content, sig FROM event_headers
|
SELECT id, pubkey, created_at, kind, tags, content, sig FROM event_headers
|
||||||
INNER JOIN (
|
INNER JOIN (
|
||||||
SELECT DISTINCT(event_tags.event_header_row_id) as row_id FROM event_tags INNER JOIN event_tags as event_tagsIn1 ON event_tagsIn1.event_header_row_id = event_tags.event_header_row_id INNER JOIN event_headers ON event_headers.row_id = event_tags.event_header_row_id WHERE (event_tags.tag_hash = "-4551135004136952885") AND (event_tagsIn1.tag_hash = "-6379614208644810021") AND (event_headers.kind = "1") ORDER BY event_headers.created_at DESC, event_headers.id ASC LIMIT 30
|
SELECT DISTINCT(event_tags.event_header_row_id) as row_id FROM event_tags INNER JOIN event_tags as event_tagsIn1 ON event_tagsIn1.event_header_row_id = event_tags.event_header_row_id AND event_tagsIn1.created_at = event_tags.created_at INNER JOIN event_headers ON event_headers.row_id = event_tags.event_header_row_id WHERE (event_tags.tag_hash = "-4551135004136952885") AND (event_tagsIn1.tag_hash = "-6379614208644810021") AND (event_headers.kind = "1") ORDER BY event_tags.created_at DESC LIMIT 30
|
||||||
) AS filtered
|
) AS filtered
|
||||||
ON event_headers.row_id = filtered.row_id
|
ON event_headers.row_id = filtered.row_id
|
||||||
ORDER BY created_at DESC, id
|
ORDER BY created_at DESC, id
|
||||||
├── CO-ROUTINE filtered
|
├── CO-ROUTINE filtered
|
||||||
│ ├── SEARCH event_tags USING COVERING INDEX query_by_tags_hash (tag_hash=?)
|
│ ├── SEARCH event_tags USING INDEX query_by_tags_hash (tag_hash=?)
|
||||||
│ ├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
│ ├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
||||||
│ ├── SEARCH event_tagsIn1 USING COVERING INDEX query_by_tags_hash (tag_hash=? AND event_header_row_id=?)
|
│ ├── SEARCH event_tagsIn1 USING INDEX query_by_tags_hash (tag_hash=? AND event_header_row_id=?)
|
||||||
│ └── USE TEMP B-TREE FOR ORDER BY
|
│ └── USE TEMP B-TREE FOR DISTINCT
|
||||||
├── SCAN filtered
|
├── SCAN filtered
|
||||||
├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
||||||
└── USE TEMP B-TREE FOR ORDER BY
|
└── USE TEMP B-TREE FOR ORDER BY
|
||||||
@@ -517,13 +517,14 @@ class QueryAssemblerTest {
|
|||||||
"""
|
"""
|
||||||
SELECT id, pubkey, created_at, kind, tags, content, sig FROM event_headers
|
SELECT id, pubkey, created_at, kind, tags, content, sig FROM event_headers
|
||||||
INNER JOIN (
|
INNER JOIN (
|
||||||
SELECT DISTINCT(event_tags.event_header_row_id) as row_id FROM event_tags INNER JOIN event_tags as event_tagsAll0_1 ON event_tagsAll0_1.event_header_row_id = event_tags.event_header_row_id WHERE (event_tags.tag_hash = "884286737453847614") AND (event_tagsAll0_1.tag_hash = "-4988851810256311323")
|
SELECT DISTINCT(event_tags.event_header_row_id) as row_id FROM event_tags INNER JOIN event_tags as event_tagsAll0_1 ON event_tagsAll0_1.event_header_row_id = event_tags.event_header_row_id AND event_tagsAll0_1.created_at = event_tags.created_at WHERE (event_tags.tag_hash = "884286737453847614") AND (event_tagsAll0_1.tag_hash = "-4988851810256311323")
|
||||||
) AS filtered
|
) AS filtered
|
||||||
ON event_headers.row_id = filtered.row_id
|
ON event_headers.row_id = filtered.row_id
|
||||||
ORDER BY created_at DESC, id
|
ORDER BY created_at DESC, id
|
||||||
├── CO-ROUTINE filtered
|
├── CO-ROUTINE filtered
|
||||||
│ ├── SEARCH event_tags USING COVERING INDEX query_by_tags_hash (tag_hash=?)
|
│ ├── SEARCH event_tags USING INDEX query_by_tags_hash (tag_hash=?)
|
||||||
│ └── SEARCH event_tagsAll0_1 USING COVERING INDEX query_by_tags_hash (tag_hash=? AND event_header_row_id=?)
|
│ ├── SEARCH event_tagsAll0_1 USING INDEX query_by_tags_hash (tag_hash=? AND created_at=?)
|
||||||
|
│ └── USE TEMP B-TREE FOR DISTINCT
|
||||||
├── SCAN filtered
|
├── SCAN filtered
|
||||||
├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
├── SEARCH event_headers USING INTEGER PRIMARY KEY (rowid=?)
|
||||||
└── USE TEMP B-TREE FOR ORDER BY
|
└── USE TEMP B-TREE FOR ORDER BY
|
||||||
|
|||||||
+7
-3
@@ -43,7 +43,11 @@ class DeletionRequestModule(
|
|||||||
BEFORE INSERT ON event_headers
|
BEFORE INSERT ON event_headers
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
BEGIN
|
BEGIN
|
||||||
-- Check for ID-based deletion record
|
-- Checks if this event hasn't already been deleted. If so, reject it.
|
||||||
|
|
||||||
|
-- Highly optimized using hash + created_at (duplicated in tags) index:
|
||||||
|
---- Expects tag_hash to be non-existant for new events (quick exit)
|
||||||
|
---- Expects created-at >= event's to not exist (quick exit)
|
||||||
SELECT RAISE(ABORT, 'blocked: a deletion event exists')
|
SELECT RAISE(ABORT, 'blocked: a deletion event exists')
|
||||||
WHERE EXISTS (
|
WHERE EXISTS (
|
||||||
SELECT 1 FROM event_tags
|
SELECT 1 FROM event_tags
|
||||||
@@ -51,9 +55,9 @@ class DeletionRequestModule(
|
|||||||
ON event_headers.row_id = event_tags.event_header_row_id
|
ON event_headers.row_id = event_tags.event_header_row_id
|
||||||
WHERE
|
WHERE
|
||||||
event_tags.tag_hash IN (NEW.etag_hash, NEW.atag_hash) AND
|
event_tags.tag_hash IN (NEW.etag_hash, NEW.atag_hash) AND
|
||||||
|
event_tags.created_at >= NEW.created_at AND
|
||||||
event_headers.kind = 5 AND
|
event_headers.kind = 5 AND
|
||||||
event_headers.pubkey_owner_hash = NEW.pubkey_owner_hash AND
|
event_headers.pubkey_owner_hash = NEW.pubkey_owner_hash
|
||||||
event_headers.created_at >= NEW.created_at
|
|
||||||
);
|
);
|
||||||
END;
|
END;
|
||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
|
|||||||
+38
-14
@@ -63,6 +63,7 @@ class EventIndexesModule(
|
|||||||
CREATE TABLE event_tags (
|
CREATE TABLE event_tags (
|
||||||
event_header_row_id INTEGER NOT NULL,
|
event_header_row_id INTEGER NOT NULL,
|
||||||
tag_hash INTEGER NOT NULL,
|
tag_hash INTEGER NOT NULL,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
FOREIGN KEY (event_header_row_id) REFERENCES event_headers(row_id) ON DELETE CASCADE
|
FOREIGN KEY (event_header_row_id) REFERENCES event_headers(row_id) ON DELETE CASCADE
|
||||||
)
|
)
|
||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
@@ -70,12 +71,15 @@ class EventIndexesModule(
|
|||||||
|
|
||||||
db.execSQL("CREATE UNIQUE INDEX event_headers_id ON event_headers (id)")
|
db.execSQL("CREATE UNIQUE INDEX event_headers_id ON event_headers (id)")
|
||||||
db.execSQL("CREATE INDEX query_by_kind_pubkey_dtag_idx ON event_headers (kind, pubkey, d_tag)")
|
db.execSQL("CREATE INDEX query_by_kind_pubkey_dtag_idx ON event_headers (kind, pubkey, d_tag)")
|
||||||
db.execSQL("CREATE INDEX query_by_created_at_id ON event_headers (created_at desc, id)")
|
db.execSQL("CREATE INDEX query_by_created_at_id ON event_headers (created_at DESC, id)")
|
||||||
|
|
||||||
// need to check if this is actually needed.
|
// need to check if this is actually needed.
|
||||||
db.execSQL("CREATE INDEX query_by_created_at_kind_key ON event_headers (created_at desc, kind, pubkey)")
|
db.execSQL("CREATE INDEX query_by_created_at_kind_key ON event_headers (created_at DESC, kind, pubkey)")
|
||||||
|
|
||||||
db.execSQL("CREATE INDEX fk_event_tags_header_id ON event_tags (event_header_row_id)")
|
db.execSQL("CREATE INDEX fk_event_tags_header_id ON event_tags (event_header_row_id)")
|
||||||
db.execSQL("CREATE INDEX query_by_tags_hash ON event_tags (tag_hash, event_header_row_id)")
|
|
||||||
|
// This is a very slow index to build (half the insert time goes here) but it is extremely effective.
|
||||||
|
db.execSQL("CREATE INDEX query_by_tags_hash ON event_tags (tag_hash, created_at DESC)")
|
||||||
|
|
||||||
// Prevent updates to maintain immutability
|
// Prevent updates to maintain immutability
|
||||||
db.execSQL(
|
db.execSQL(
|
||||||
@@ -117,9 +121,9 @@ class EventIndexesModule(
|
|||||||
val sqlInsertTags =
|
val sqlInsertTags =
|
||||||
"""
|
"""
|
||||||
INSERT OR ROLLBACK INTO event_tags
|
INSERT OR ROLLBACK INTO event_tags
|
||||||
(event_header_row_id, tag_hash)
|
(event_header_row_id, tag_hash, created_at)
|
||||||
VALUES
|
VALUES
|
||||||
(?,?)
|
(?,?,?)
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
fun insert(
|
fun insert(
|
||||||
@@ -177,6 +181,7 @@ class EventIndexesModule(
|
|||||||
indexableTags.forEach {
|
indexableTags.forEach {
|
||||||
stmtTags.bindLong(1, headerId)
|
stmtTags.bindLong(1, headerId)
|
||||||
stmtTags.bindLong(2, it)
|
stmtTags.bindLong(2, it)
|
||||||
|
stmtTags.bindLong(3, event.createdAt)
|
||||||
stmtTags.executeInsert()
|
stmtTags.executeInsert()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,6 +467,16 @@ class EventIndexesModule(
|
|||||||
|
|
||||||
val nonDTagsAll = filter.tagsAll?.filter { it.key != "d" } ?: emptyMap()
|
val nonDTagsAll = filter.tagsAll?.filter { it.key != "d" } ?: emptyMap()
|
||||||
|
|
||||||
|
val reverseLookup = nonDTagsIn.isNotEmpty() || nonDTagsAll.isNotEmpty()
|
||||||
|
|
||||||
|
val needHeaders =
|
||||||
|
with(filter) {
|
||||||
|
(ids != null) ||
|
||||||
|
(authors != null && authors.isNotEmpty()) ||
|
||||||
|
(kinds != null && kinds.isNotEmpty()) ||
|
||||||
|
(tags != null && tags.containsKey("d"))
|
||||||
|
}
|
||||||
|
|
||||||
val hasHeaders =
|
val hasHeaders =
|
||||||
with(filter) {
|
with(filter) {
|
||||||
(ids != null) ||
|
(ids != null) ||
|
||||||
@@ -478,13 +493,13 @@ class EventIndexesModule(
|
|||||||
val projection =
|
val projection =
|
||||||
buildString {
|
buildString {
|
||||||
// always do tags if there are any
|
// always do tags if there are any
|
||||||
if (nonDTagsIn.isNotEmpty() || nonDTagsAll.isNotEmpty()) {
|
if (reverseLookup) {
|
||||||
append("SELECT DISTINCT(event_tags.event_header_row_id) as row_id FROM event_tags ")
|
append("SELECT DISTINCT(event_tags.event_header_row_id) as row_id FROM event_tags ")
|
||||||
|
|
||||||
// it's quite rare to have 2 tags in the filter, but possible
|
// it's quite rare to have 2 tags in the filter, but possible
|
||||||
nonDTagsIn.keys.forEachIndexed { index, tagName ->
|
nonDTagsIn.keys.forEachIndexed { index, tagName ->
|
||||||
if (defaultTagKey != null) {
|
if (defaultTagKey != null) {
|
||||||
append("INNER JOIN event_tags as event_tagsIn$index ON event_tagsIn$index.event_header_row_id = event_tags.event_header_row_id ")
|
append("INNER JOIN event_tags as event_tagsIn$index ON event_tagsIn$index.event_header_row_id = event_tags.event_header_row_id AND event_tagsIn$index.created_at = event_tags.created_at ")
|
||||||
} else {
|
} else {
|
||||||
defaultTagKey = TagNameForQuery.InTags(tagName)
|
defaultTagKey = TagNameForQuery.InTags(tagName)
|
||||||
}
|
}
|
||||||
@@ -493,14 +508,14 @@ class EventIndexesModule(
|
|||||||
nonDTagsAll.keys.forEachIndexed { index, tagName ->
|
nonDTagsAll.keys.forEachIndexed { index, tagName ->
|
||||||
nonDTagsAll[tagName]!!.forEachIndexed { valueIndex, tagValue ->
|
nonDTagsAll[tagName]!!.forEachIndexed { valueIndex, tagValue ->
|
||||||
if (defaultTagKey != null) {
|
if (defaultTagKey != null) {
|
||||||
append("INNER JOIN event_tags as event_tagsAll${index}_$valueIndex ON event_tagsAll${index}_$valueIndex.event_header_row_id = event_tags.event_header_row_id ")
|
append("INNER JOIN event_tags as event_tagsAll${index}_$valueIndex ON event_tagsAll${index}_$valueIndex.event_header_row_id = event_tags.event_header_row_id AND event_tagsAll${index}_$valueIndex.created_at = event_tags.created_at ")
|
||||||
} else {
|
} else {
|
||||||
defaultTagKey = TagNameForQuery.AllTags(tagName, valueIndex)
|
defaultTagKey = TagNameForQuery.AllTags(tagName, valueIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasHeaders) {
|
if (needHeaders) {
|
||||||
append("INNER JOIN event_headers ON event_headers.row_id = event_tags.event_header_row_id ")
|
append("INNER JOIN event_headers ON event_headers.row_id = event_tags.event_header_row_id ")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -525,10 +540,6 @@ class EventIndexesModule(
|
|||||||
// ids reduce the filter the most
|
// ids reduce the filter the most
|
||||||
filter.ids?.let { equalsOrIn("event_headers.id", it) }
|
filter.ids?.let { equalsOrIn("event_headers.id", it) }
|
||||||
|
|
||||||
// range search is bad but most of the time these are up the top with few elements.
|
|
||||||
filter.since?.let { greaterThanOrEquals("event_headers.created_at", it) }
|
|
||||||
filter.until?.let { lessThanOrEquals("event_headers.created_at", it) }
|
|
||||||
|
|
||||||
// it's quite rare to have 2 tags in the filter, but possible
|
// it's quite rare to have 2 tags in the filter, but possible
|
||||||
nonDTagsIn.keys.forEachIndexed { index, tagName ->
|
nonDTagsIn.keys.forEachIndexed { index, tagName ->
|
||||||
val column =
|
val column =
|
||||||
@@ -560,6 +571,15 @@ class EventIndexesModule(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// range search is bad but most of the time these are up the top with few elements.
|
||||||
|
if (reverseLookup) {
|
||||||
|
filter.since?.let { greaterThanOrEquals("event_tags.created_at", it) }
|
||||||
|
filter.until?.let { lessThanOrEquals("event_tags.created_at", it) }
|
||||||
|
} else {
|
||||||
|
filter.since?.let { greaterThanOrEquals("event_headers.created_at", it) }
|
||||||
|
filter.until?.let { lessThanOrEquals("event_headers.created_at", it) }
|
||||||
|
}
|
||||||
|
|
||||||
filter.kinds?.let { equalsOrIn("event_headers.kind", it) }
|
filter.kinds?.let { equalsOrIn("event_headers.kind", it) }
|
||||||
filter.authors?.let { equalsOrIn("event_headers.pubkey", it) }
|
filter.authors?.let { equalsOrIn("event_headers.pubkey", it) }
|
||||||
|
|
||||||
@@ -580,7 +600,11 @@ class EventIndexesModule(
|
|||||||
|
|
||||||
val whereClause =
|
val whereClause =
|
||||||
if (filter.limit != null) {
|
if (filter.limit != null) {
|
||||||
"${clause.conditions} ORDER BY event_headers.created_at DESC, event_headers.id ASC LIMIT ${filter.limit}"
|
if (reverseLookup) {
|
||||||
|
"${clause.conditions} ORDER BY event_tags.created_at DESC LIMIT ${filter.limit}"
|
||||||
|
} else {
|
||||||
|
"${clause.conditions} ORDER BY event_headers.created_at DESC, event_headers.id ASC LIMIT ${filter.limit}"
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
clause.conditions
|
clause.conditions
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user