feat: Improve Tag search NIP-12
Build and Push Docker Image / build_docker_image (push) Failing after 15m2s

modified:   Cargo.lock
modified:   Cargo.toml
modified:   src/database.rs
modified:   src/nostr/event.rs
modified:   src/nostr/filter.rs
This commit is contained in:
2025-12-02 18:47:41 +09:00
parent d70fdbd037
commit 6cc7346522
5 changed files with 44 additions and 19 deletions
Generated
+1 -1
View File
@@ -891,7 +891,7 @@ dependencies = [
[[package]]
name = "nostr-relay"
version = "1.0.0"
version = "1.0.1"
dependencies = [
"anyhow",
"env_logger",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nostr-relay"
version = "1.0.0"
version = "1.0.1"
edition = "2024"
[dependencies]
+9
View File
@@ -28,6 +28,14 @@ pub async fn init_database(pool: &SqlitePool) -> Result<()> {
d_tag TEXT,
deleted_at INTEGER DEFAULT (unixepoch())
);
CREATE TABLE IF NOT EXISTS event_tags (
event_id TEXT NOT NULL,
tag_name TEXT NOT NULL,
tag_value TEXT NOT NULL,
created_at INTEGER NOT NULL,
FOREIGN KEY(event_id) REFERENCES events(id) ON DELETE CASCADE
);
"#;
let create_indexes = vec![
@@ -39,6 +47,7 @@ pub async fn init_database(pool: &SqlitePool) -> Result<()> {
"CREATE INDEX IF NOT EXISTS idx_events_pubkey_kind_d_tag ON events(pubkey, kind, d_tag);",
"CREATE INDEX IF NOT EXISTS idx_deleted_events_pubkey ON deleted_events(pubkey, event_id);",
"CREATE INDEX IF NOT EXISTS idx_deleted_events_kind_d_tag ON deleted_events(kind, pubkey, d_tag);",
"CREATE INDEX IF NOT EXISTS idx_event_tags_name_value_created ON event_tags(tag_name, tag_value, created_at DESC);",
];
query(create_events_table).execute(pool).await?;
+30 -13
View File
@@ -182,6 +182,7 @@ impl NostrEventExt for NostrEvent {
// 保存事件到数据库,并处理可替换事件和删除事件
async fn save(&self, pool: &SqlitePool) -> Result<(), anyhow::Error> {
let tags_json = serde_json::to_string(&self.tags).unwrap();
let mut tx = pool.begin().await?;
// 提取 d_tag
let d_tag = self
@@ -206,7 +207,7 @@ impl NostrEventExt for NostrEvent {
sqlx::query("DELETE FROM events WHERE id = ? AND pubkey = ?")
.bind(event_id_to_delete)
.bind(&self.pubkey)
.execute(pool)
.execute(&mut *tx)
.await?;
if result.rows_affected() > 0 {
info!(
@@ -219,7 +220,7 @@ impl NostrEventExt for NostrEvent {
.bind(event_id_to_delete)
.bind(&self.pubkey)
.bind(self.created_at as i64)
.execute(pool)
.execute(&mut *tx)
.await?;
if result.rows_affected() > 0 {
info!(
@@ -252,7 +253,7 @@ impl NostrEventExt for NostrEvent {
.bind(&self.pubkey)
.bind(tag_d_vector[2])
.bind(self.created_at as i64)
.execute(pool)
.execute(&mut *tx)
.await?;
if result.rows_affected() > 0 {
info!(
@@ -266,7 +267,7 @@ impl NostrEventExt for NostrEvent {
.bind(&self.pubkey)
.bind(tag_d_vector[2])
.bind(self.created_at as i64)
.execute(pool)
.execute(&mut *tx)
.await?;
if result.rows_affected() > 0 {
info!(
@@ -303,7 +304,7 @@ impl NostrEventExt for NostrEvent {
.bind(&self.pubkey)
.bind(self.kind)
.bind(self.created_at as i64)
.fetch_optional(pool)
.fetch_optional(&mut *tx)
.await?;
if is_deleted.is_some() {
@@ -313,7 +314,7 @@ impl NostrEventExt for NostrEvent {
let created_at: Option<u64> = sqlx::query_scalar(sql)
.bind(&self.pubkey)
.bind(self.kind)
.fetch_optional(pool)
.fetch_optional(&mut *tx)
.await?;
if let Some(prev_created_at) = created_at {
@@ -322,7 +323,7 @@ impl NostrEventExt for NostrEvent {
sqlx::query(sql)
.bind(&self.pubkey)
.bind(self.kind)
.execute(pool)
.execute(&mut *tx)
.await?;
debug!(
"Deleted previous replaceable event for pubkey: {}, kind: {}",
@@ -351,7 +352,7 @@ impl NostrEventExt for NostrEvent {
.bind(self.kind)
.bind(&d_tag)
.bind(self.created_at as i64)
.fetch_optional(pool)
.fetch_optional(&mut *tx)
.await?;
if let Some(_) = result {
debug!(
@@ -365,7 +366,7 @@ impl NostrEventExt for NostrEvent {
.bind(&self.pubkey)
.bind(self.kind)
.bind(&d_tag)
.fetch_optional(pool)
.fetch_optional(&mut *tx)
.await?;
if let Some(prev_created_at) = created_at {
@@ -375,7 +376,7 @@ impl NostrEventExt for NostrEvent {
.bind(&self.pubkey)
.bind(self.kind)
.bind(&d_tag)
.execute(pool)
.execute(&mut *tx)
.await?;
debug!(
"Deleted previous parameterized replaceable event for pubkey: {}, kind: {}, d_tag: {}",
@@ -401,7 +402,7 @@ impl NostrEventExt for NostrEvent {
sqlx::query("SELECT * FROM deleted_events WHERE event_id = ? AND pubkey = ?")
.bind(&self.id)
.bind(&self.pubkey)
.fetch_optional(pool)
.fetch_optional(&mut *tx)
.await?;
if let Some(_) = result {
debug!(
@@ -420,10 +421,26 @@ impl NostrEventExt for NostrEvent {
.bind(&self.content)
.bind(&self.sig)
.bind(&d_tag)
.execute(pool)
.execute(&mut *tx)
.await?;
for tag in &self.tags {
if tag.len() >= 2 {
let tag_name = &tag[0];
let tag_value = &tag[1];
if tag_name.len() == 1 {
sqlx::query("INSERT INTO event_tags (event_id, tag_name, tag_value, created_at) VALUES (?, ?, ?, ?)")
.bind(&self.id)
.bind(tag_name)
.bind(tag_value)
.bind(self.created_at as i64)
.execute(&mut *tx)
.await?;
return Ok(());
}
}
}
}
tx.commit().await?;
Ok(())
}
+3 -4
View File
@@ -91,11 +91,10 @@ impl FilterExt for Filter {
if tag_name.starts_with('#') && !tag_values.is_empty() {
let tag_letter = &tag_name[1..]; // 提取标签字母 (e.g., 'e', 'p', 'd')
// 使用 JSON 函数查询 tags 数组
// SELECT 1 FROM json_each(tags) AS tag_arr WHERE tag_arr.value->>0 = 'p' AND tag_arr.value->>1 IN ('...', '...')
sql.push(" AND EXISTS (SELECT 1 FROM json_each(tags) AS tag_arr WHERE json_array_length(tag_arr.value) > 1 AND json_extract(tag_arr.value, '$[0]') = ");
// 使用 event_tags 表查询
sql.push(" AND EXISTS (SELECT 1 FROM event_tags WHERE event_id = events.id AND tag_name = ");
sql.push_bind(tag_letter);
sql.push(" AND json_extract(tag_arr.value, '$[1]') IN (");
sql.push(" AND tag_value IN (");
let mut separated = sql.separated(",");
for value in tag_values {
separated.push_bind(value);