05 01 25
добавил таблицу connections_state и тригер который ведёт в ней актуальное состояние всех связей! (и всё рабоатет - тесты проходят)
This commit is contained in:
parent
7ba333bf6c
commit
eb922d918b
@ -96,6 +96,31 @@ toBchName — TEXT NULL — целевой блокчейн.
|
|||||||
toBlockGlobalNumber — INTEGER NULL — целевой глобальный номер.
|
toBlockGlobalNumber — INTEGER NULL — целевой глобальный номер.
|
||||||
toBlockHashe — TEXT NULL — хэш целевого блока.
|
toBlockHashe — TEXT NULL — хэш целевого блока.
|
||||||
|
|
||||||
|
connections_state ⭐
|
||||||
|
Текущее состояние связей пользователя.
|
||||||
|
login — TEXT NOT NULL — владелец связи.
|
||||||
|
relType — INTEGER NOT NULL — тип связи:
|
||||||
|
10 = FRIEND, 20 = CONTACT, 30 = FOLLOW.
|
||||||
|
to_login — TEXT NOT NULL — с кем связь.
|
||||||
|
toBchName — TEXT NOT NULL — блокчейн цели.
|
||||||
|
toBlockGlobalNumber — INTEGER NULL — последний известный номер блока цели.
|
||||||
|
toBlockHashe — TEXT NULL — последний известный хэш блока цели.
|
||||||
|
Ограничение:
|
||||||
|
UNIQUE(login, relType, to_login) — одно актуальное состояние связи.
|
||||||
|
|
||||||
|
3) Триггер логики связей
|
||||||
|
|
||||||
|
Триггер trg_blocks_connection_state_ai срабатывает AFTER INSERT ON blocks:
|
||||||
|
если msgType = 3 (ConnectionBody)
|
||||||
|
msgSubType IN (10,20,30) →
|
||||||
|
добавить или обновить запись в connections_state
|
||||||
|
msgSubType IN (11,21,31) →
|
||||||
|
удалить соответствующую связь (10/20/30)
|
||||||
|
повторные добавления и удаления не вызывают ошибок
|
||||||
|
Таким образом:
|
||||||
|
blocks — журнал событий
|
||||||
|
connections_state — всегда актуальное состояние
|
||||||
|
|
||||||
Индексы (кратко, чтобы было понятно зачем)
|
Индексы (кратко, чтобы было понятно зачем)
|
||||||
idx_solana_users_login(login) — быстрый поиск по логину.
|
idx_solana_users_login(login) — быстрый поиск по логину.
|
||||||
idx_active_sessions_login(login) — быстро получить сессии пользователя.
|
idx_active_sessions_login(login) — быстро получить сессии пользователя.
|
||||||
|
|||||||
@ -15,16 +15,14 @@ import java.sql.Statement;
|
|||||||
* DatabaseInitializer — создание новой SQLite-БД по схеме SHiNE.
|
* DatabaseInitializer — создание новой SQLite-БД по схеме SHiNE.
|
||||||
*
|
*
|
||||||
* Таблицы:
|
* Таблицы:
|
||||||
* - solana_users (login TEXT PK, deviceKey TEXT, solanaKey TEXT)
|
* - solana_users
|
||||||
* - active_sessions (login TEXT FK)
|
* - active_sessions
|
||||||
* - users_params (login TEXT FK, UNIQUE(login,param))
|
* - users_params
|
||||||
* - ip_geo_cache
|
* - ip_geo_cache
|
||||||
* - blockchain_state (MVP)
|
* - blockchain_state
|
||||||
* - blocks (login TEXT, bchName TEXT, PK убран)
|
* - blocks
|
||||||
|
* - connections_state (текущее состояние связей)
|
||||||
*
|
*
|
||||||
* ОБНОВЛЕНО:
|
|
||||||
* - blocks: добавлено поле msgSubType (сразу после msgType)
|
|
||||||
* - blocks: поля to* остаются nullable
|
|
||||||
*/
|
*/
|
||||||
public class DatabaseInitializer {
|
public class DatabaseInitializer {
|
||||||
|
|
||||||
@ -153,7 +151,7 @@ public class DatabaseInitializer {
|
|||||||
ON ip_geo_cache (updated_at_ms);
|
ON ip_geo_cache (updated_at_ms);
|
||||||
""");
|
""");
|
||||||
|
|
||||||
// 5. blockchain_state (MVP) — теперь PK blockchainName + поле login
|
// 5. blockchain_state
|
||||||
st.executeUpdate("""
|
st.executeUpdate("""
|
||||||
CREATE TABLE IF NOT EXISTS blockchain_state (
|
CREATE TABLE IF NOT EXISTS blockchain_state (
|
||||||
blockchainName TEXT NOT NULL PRIMARY KEY,
|
blockchainName TEXT NOT NULL PRIMARY KEY,
|
||||||
@ -198,7 +196,7 @@ public class DatabaseInitializer {
|
|||||||
ON blockchain_state (updated_at_ms);
|
ON blockchain_state (updated_at_ms);
|
||||||
""");
|
""");
|
||||||
|
|
||||||
// 6. blocks — PK удалён полностью, to* теперь nullable, добавлен msgSubType
|
// 6. blocks
|
||||||
st.executeUpdate("""
|
st.executeUpdate("""
|
||||||
CREATE TABLE IF NOT EXISTS blocks (
|
CREATE TABLE IF NOT EXISTS blocks (
|
||||||
login TEXT NOT NULL,
|
login TEXT NOT NULL,
|
||||||
@ -234,6 +232,93 @@ public class DatabaseInitializer {
|
|||||||
CREATE INDEX IF NOT EXISTS idx_blocks_to_target
|
CREATE INDEX IF NOT EXISTS idx_blocks_to_target
|
||||||
ON blocks (to_login, toBchName, toBlockGlobalNumber);
|
ON blocks (to_login, toBchName, toBlockGlobalNumber);
|
||||||
""");
|
""");
|
||||||
|
|
||||||
|
// =====================================================================
|
||||||
|
// 7) connections_state — текущее состояние "кто с кем и какая связь"
|
||||||
|
// =====================================================================
|
||||||
|
st.executeUpdate("""
|
||||||
|
CREATE TABLE IF NOT EXISTS connections_state (
|
||||||
|
login TEXT NOT NULL,
|
||||||
|
relType INTEGER NOT NULL, -- 10/20/30 (FRIEND/CONTACT/FOLLOW)
|
||||||
|
to_login TEXT NOT NULL,
|
||||||
|
toBchName TEXT NOT NULL,
|
||||||
|
toBlockGlobalNumber INTEGER,
|
||||||
|
toBlockHashe TEXT,
|
||||||
|
|
||||||
|
FOREIGN KEY (login) REFERENCES solana_users(login),
|
||||||
|
|
||||||
|
-- состояние уникально по пользователю, типу связи и цели
|
||||||
|
UNIQUE (login, relType, to_login)
|
||||||
|
);
|
||||||
|
""");
|
||||||
|
|
||||||
|
st.executeUpdate("""
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_connections_state_login
|
||||||
|
ON connections_state (login);
|
||||||
|
""");
|
||||||
|
|
||||||
|
st.executeUpdate("""
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_connections_state_to_login
|
||||||
|
ON connections_state (to_login);
|
||||||
|
""");
|
||||||
|
|
||||||
|
st.executeUpdate("""
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_connections_state_pair
|
||||||
|
ON connections_state (login, to_login);
|
||||||
|
""");
|
||||||
|
|
||||||
|
// =====================================================================
|
||||||
|
// 8) Trigger: при вставке connection-блоков в blocks — обновлять connections_state
|
||||||
|
//
|
||||||
|
// Правило:
|
||||||
|
// - msgType=3 (ConnectionBody)
|
||||||
|
// - subType 10/20/30 => добавить/обновить запись состояния
|
||||||
|
// - subType 11/21/31 => удалить запись состояния (без ошибок, даже если её нет)
|
||||||
|
//
|
||||||
|
// Примечание:
|
||||||
|
// - "повторное добавление" не должно падать => используем UPSERT (DO UPDATE)
|
||||||
|
// - "удаление того, чего нет" не падает => обычный DELETE
|
||||||
|
// =====================================================================
|
||||||
|
st.executeUpdate("""
|
||||||
|
CREATE TRIGGER IF NOT EXISTS trg_blocks_connection_state_ai
|
||||||
|
AFTER INSERT ON blocks
|
||||||
|
WHEN NEW.msgType = 3
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
-- ADD / UPDATE: 10/20/30
|
||||||
|
INSERT INTO connections_state (
|
||||||
|
login, relType, to_login, toBchName, toBlockGlobalNumber, toBlockHashe
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
NEW.login,
|
||||||
|
NEW.msgSubType,
|
||||||
|
NEW.to_login,
|
||||||
|
NEW.toBchName,
|
||||||
|
NEW.toBlockGlobalNumber,
|
||||||
|
NEW.toBlockHashe
|
||||||
|
WHERE NEW.msgSubType IN (10, 20, 30)
|
||||||
|
AND NEW.to_login IS NOT NULL
|
||||||
|
AND NEW.toBchName IS NOT NULL
|
||||||
|
ON CONFLICT(login, relType, to_login)
|
||||||
|
DO UPDATE SET
|
||||||
|
toBchName = excluded.toBchName,
|
||||||
|
toBlockGlobalNumber = excluded.toBlockGlobalNumber,
|
||||||
|
toBlockHashe = excluded.toBlockHashe;
|
||||||
|
|
||||||
|
-- DELETE: 11/21/31 => удалить соответствующую "положительную" связь (10/20/30)
|
||||||
|
DELETE FROM connections_state
|
||||||
|
WHERE login = NEW.login
|
||||||
|
AND to_login = NEW.to_login
|
||||||
|
AND relType = CASE NEW.msgSubType
|
||||||
|
WHEN 11 THEN 10
|
||||||
|
WHEN 21 THEN 20
|
||||||
|
WHEN 31 THEN 30
|
||||||
|
ELSE relType
|
||||||
|
END
|
||||||
|
AND NEW.msgSubType IN (11, 21, 31);
|
||||||
|
|
||||||
|
END;
|
||||||
|
""");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user