core: use strict tables (#6535)

* core: use strict tables

* fix field types

* change encodings to match schema types; migrate sqlite tables to strict mode

* stabilize postgres client tests, remove slow handshake tests

* update simplexmq

* fix test

* change call_state type to text

* fix directory service queries

* update local_alias for existing schemas

* change types before strict
This commit is contained in:
Evgeny
2026-01-05 08:53:26 +00:00
committed by GitHub
parent f0467aee00
commit 87e8a10f1e
19 changed files with 220 additions and 121 deletions
+4 -3
View File
@@ -5,11 +5,12 @@ module Simplex.Chat.Store.AppSettings where
import Control.Monad (join)
import Control.Monad.IO.Class (liftIO)
import qualified Data.Aeson as J
import Data.Maybe (fromMaybe)
import Simplex.Chat.AppSettings (AppSettings (..), combineAppSettings, defaultAppSettings, defaultParseAppSettings)
import Simplex.Messaging.Agent.Store.AgentStore (maybeFirstRow)
import qualified Simplex.Messaging.Agent.Store.DB as DB
import Simplex.Messaging.Util (decodeJSON, encodeJSON)
#if defined(dbPostgres)
import Database.PostgreSQL.Simple (Only (..))
#else
@@ -19,9 +20,9 @@ import Database.SQLite.Simple (Only (..))
saveAppSettings :: DB.Connection -> AppSettings -> IO ()
saveAppSettings db appSettings = do
DB.execute_ db "DELETE FROM app_settings"
DB.execute db "INSERT INTO app_settings (app_settings) VALUES (?)" (Only $ J.encode appSettings)
DB.execute db "INSERT INTO app_settings (app_settings) VALUES (?)" (Only $ encodeJSON appSettings)
getAppSettings :: DB.Connection -> Maybe AppSettings -> IO AppSettings
getAppSettings db platformDefaults = do
stored_ <- join <$> liftIO (maybeFirstRow (J.decodeStrict . fromOnly) $ DB.query_ db "SELECT app_settings FROM app_settings")
stored_ <- join <$> liftIO (maybeFirstRow (decodeJSON . fromOnly) $ DB.query_ db "SELECT app_settings FROM app_settings")
pure $ combineAppSettings (fromMaybe defaultAppSettings platformDefaults) (fromMaybe defaultParseAppSettings stored_)
@@ -23,6 +23,7 @@ import Simplex.Chat.Store.Postgres.Migrations.M20251007_connections_sync
import Simplex.Chat.Store.Postgres.Migrations.M20251017_chat_tags_cascade
import Simplex.Chat.Store.Postgres.Migrations.M20251117_member_relations_vector
import Simplex.Chat.Store.Postgres.Migrations.M20251128_migrate_member_relations
import Simplex.Chat.Store.Postgres.Migrations.M20251230_strict_tables
import Simplex.Messaging.Agent.Store.Shared (Migration (..))
schemaMigrations :: [(String, Text, Maybe Text)]
@@ -45,7 +46,8 @@ schemaMigrations =
("20251007_connections_sync", m20251007_connections_sync, Just down_m20251007_connections_sync),
("20251017_chat_tags_cascade", m20251017_chat_tags_cascade, Just down_m20251017_chat_tags_cascade),
("20251117_member_relations_vector", m20251117_member_relations_vector, Just down_m20251117_member_relations_vector),
("20251128_migrate_member_relations", m20251128_migrate_member_relations, Just down_m20251128_migrate_member_relations)
("20251128_migrate_member_relations", m20251128_migrate_member_relations, Just down_m20251128_migrate_member_relations),
("20251230_strict_tables", m20251230_strict_tables, Just down_m20251230_strict_tables)
]
-- | The list of migrations in ascending order by date
@@ -0,0 +1,26 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
module Simplex.Chat.Store.Postgres.Migrations.M20251230_strict_tables where
import Data.Text (Text)
import Text.RawString.QQ (r)
import Simplex.Messaging.Agent.Store.Postgres.Migrations.M20251230_strict_tables (isValidText)
m20251230_strict_tables :: Text
m20251230_strict_tables =
isValidText
<> [r|
DELETE FROM calls
WHERE NOT simplex_is_valid_text(call_state);
ALTER TABLE calls ALTER COLUMN call_state TYPE TEXT USING call_state::TEXT;
DROP FUNCTION simplex_is_valid_text(BYTEA);
|]
down_m20251230_strict_tables :: Text
down_m20251230_strict_tables =
[r|
ALTER TABLE calls ALTER COLUMN call_state TYPE BYTEA USING call_state::BYTEA;
|]
@@ -173,7 +173,7 @@ CREATE TABLE test_chat_schema.calls (
contact_id bigint NOT NULL,
shared_call_id bytea NOT NULL,
chat_item_id bigint NOT NULL,
call_state bytea NOT NULL,
call_state text NOT NULL,
call_ts timestamp with time zone NOT NULL,
user_id bigint NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
+3 -1
View File
@@ -146,6 +146,7 @@ import Simplex.Chat.Store.SQLite.Migrations.M20251007_connections_sync
import Simplex.Chat.Store.SQLite.Migrations.M20251017_chat_tags_cascade
import Simplex.Chat.Store.SQLite.Migrations.M20251117_member_relations_vector
import Simplex.Chat.Store.SQLite.Migrations.M20251128_migrate_member_relations
import Simplex.Chat.Store.SQLite.Migrations.M20251230_strict_tables
import Simplex.Messaging.Agent.Store.Shared (Migration (..))
schemaMigrations :: [(String, Query, Maybe Query)]
@@ -291,7 +292,8 @@ schemaMigrations =
("20251007_connections_sync", m20251007_connections_sync, Just down_m20251007_connections_sync),
("20251017_chat_tags_cascade", m20251017_chat_tags_cascade, Just down_m20251017_chat_tags_cascade),
("20251117_member_relations_vector", m20251117_member_relations_vector, Just down_m20251117_member_relations_vector),
("20251128_migrate_member_relations", m20251128_migrate_member_relations, Just down_m20251128_migrate_member_relations)
("20251128_migrate_member_relations", m20251128_migrate_member_relations, Just down_m20251128_migrate_member_relations),
("20251230_strict_tables", m20251230_strict_tables, Just down_m20251230_strict_tables)
]
-- | The list of migrations in ascending order by date
@@ -0,0 +1,70 @@
{-# LANGUAGE QuasiQuotes #-}
module Simplex.Chat.Store.SQLite.Migrations.M20251230_strict_tables where
import Database.SQLite.Simple (Query)
import Database.SQLite.Simple.QQ (sql)
m20251230_strict_tables :: Query
m20251230_strict_tables =
[sql|
UPDATE group_members
SET member_role = CAST(member_role as TEXT),
member_restriction = CAST(member_restriction as TEXT);
UPDATE user_contact_links SET group_link_member_role = CAST(group_link_member_role as TEXT);
UPDATE app_settings SET app_settings = CAST(app_settings as TEXT);
PRAGMA writable_schema=1;
UPDATE sqlite_master
SET sql = replace(sql, 'call_state BLOB NOT NULL', 'call_state TEXT NOT NULL')
WHERE type = 'table' AND name = 'calls';
UPDATE sqlite_master
SET sql = replace(sql, 'local_alias DEFAULT', 'local_alias TEXT DEFAULT')
WHERE type = 'table' AND name = 'connections';
UPDATE sqlite_master
SET sql = CASE
WHEN LOWER(SUBSTR(sql, -15)) = ') without rowid' THEN sql || ', STRICT'
WHEN SUBSTR(sql, -1) = ')' THEN sql || ' STRICT'
ELSE sql
END
WHERE type = 'table' AND name != 'sqlite_sequence';
PRAGMA writable_schema=0;
|]
down_m20251230_strict_tables :: Query
down_m20251230_strict_tables =
[sql|
PRAGMA writable_schema=1;
UPDATE sqlite_master
SET sql = CASE
WHEN LOWER(SUBSTR(sql, -8)) = ', strict' THEN SUBSTR(sql, 1, LENGTH(sql) - 8)
WHEN LOWER(SUBSTR(sql, -7)) = ' strict' THEN SUBSTR(sql, 1, LENGTH(sql) - 7)
ELSE sql
END
WHERE type = 'table' AND name != 'sqlite_sequence';
UPDATE sqlite_master
SET sql = replace(sql, 'call_state TEXT NOT NULL', 'call_state BLOB NOT NULL')
WHERE type = 'table' AND name = 'calls';
UPDATE sqlite_master
SET sql = replace(sql, 'local_alias TEXT DEFAULT', 'local_alias DEFAULT')
WHERE type = 'table' AND name = 'connections';
PRAGMA writable_schema=0;
UPDATE group_members
SET member_role = CAST(member_role as BLOB),
member_restriction = CAST(member_restriction as BLOB);
UPDATE user_contact_links SET group_link_member_role = CAST(group_link_member_role as BLOB);
UPDATE app_settings SET app_settings = CAST(app_settings as BLOB);
|]
@@ -1255,10 +1255,6 @@ Query: UPDATE snd_file_chunk_replicas SET replica_status = ?, updated_at = ? WHE
Plan:
SEARCH snd_file_chunk_replicas USING INTEGER PRIMARY KEY (rowid=?)
Query: UPDATE snd_files SET deleted = 1, updated_at = ? WHERE snd_file_id = ?
Plan:
SEARCH snd_files USING INTEGER PRIMARY KEY (rowid=?)
Query: UPDATE snd_files SET prefix_path = NULL, status = ?, updated_at = ? WHERE snd_file_id = ?
Plan:
SEARCH snd_files USING INTEGER PRIMARY KEY (rowid=?)
@@ -2,7 +2,7 @@ CREATE TABLE migrations(
name TEXT NOT NULL PRIMARY KEY,
ts TEXT NOT NULL,
down TEXT
);
) STRICT;
CREATE TABLE contact_profiles(
-- remote user profile
contact_profile_id INTEGER PRIMARY KEY,
@@ -20,7 +20,7 @@ CREATE TABLE contact_profiles(
contact_link BLOB,
short_descr TEXT,
chat_peer_type TEXT
);
) STRICT;
CREATE TABLE users(
user_id INTEGER PRIMARY KEY,
contact_id INTEGER NOT NULL UNIQUE REFERENCES contacts ON DELETE RESTRICT
@@ -44,7 +44,7 @@ CREATE TABLE users(
ON DELETE RESTRICT
ON UPDATE CASCADE
DEFERRABLE INITIALLY DEFERRED
);
) STRICT;
CREATE TABLE display_names(
user_id INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
local_display_name TEXT NOT NULL,
@@ -54,7 +54,7 @@ CREATE TABLE display_names(
updated_at TEXT CHECK(updated_at NOT NULL),
PRIMARY KEY(user_id, local_display_name) ON CONFLICT FAIL,
UNIQUE(user_id, ldn_base, ldn_suffix) ON CONFLICT FAIL
) WITHOUT ROWID;
) WITHOUT ROWID, STRICT;
CREATE TABLE contacts(
contact_id INTEGER PRIMARY KEY,
contact_profile_id INTEGER REFERENCES contact_profiles ON DELETE SET NULL,
@@ -96,7 +96,7 @@ CREATE TABLE contacts(
ON UPDATE CASCADE,
UNIQUE(user_id, local_display_name),
UNIQUE(user_id, contact_profile_id)
);
) STRICT;
CREATE TABLE known_servers(
server_id INTEGER PRIMARY KEY,
host TEXT NOT NULL,
@@ -106,7 +106,7 @@ CREATE TABLE known_servers(
created_at TEXT CHECK(created_at NOT NULL),
updated_at TEXT CHECK(updated_at NOT NULL),
UNIQUE(user_id, host, port)
) WITHOUT ROWID;
) WITHOUT ROWID, STRICT;
CREATE TABLE group_profiles(
-- shared group profiles
group_profile_id INTEGER PRIMARY KEY,
@@ -122,7 +122,7 @@ CREATE TABLE group_profiles(
description TEXT NULL,
member_admission TEXT,
short_descr TEXT
);
) STRICT;
CREATE TABLE groups(
group_id INTEGER PRIMARY KEY, -- local group ID
user_id INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
@@ -163,7 +163,7 @@ CREATE TABLE groups(
ON UPDATE CASCADE,
UNIQUE(user_id, local_display_name),
UNIQUE(user_id, group_profile_id)
);
) STRICT;
CREATE TABLE group_members(
-- group members, excluding the local user
group_member_id INTEGER PRIMARY KEY,
@@ -203,7 +203,7 @@ CREATE TABLE group_members(
ON DELETE CASCADE
ON UPDATE CASCADE,
UNIQUE(group_id, member_id)
);
) STRICT;
CREATE TABLE group_member_intros(
group_member_intro_id INTEGER PRIMARY KEY,
re_group_member_id INTEGER NOT NULL REFERENCES group_members(group_member_id) ON DELETE CASCADE,
@@ -215,7 +215,7 @@ CREATE TABLE group_member_intros(
updated_at TEXT CHECK(updated_at NOT NULL),
intro_chat_protocol_version INTEGER NOT NULL DEFAULT 3, -- see GroupMemberIntroStatus
UNIQUE(re_group_member_id, to_group_member_id)
);
) STRICT;
CREATE TABLE files(
file_id INTEGER PRIMARY KEY,
contact_id INTEGER REFERENCES contacts ON DELETE CASCADE,
@@ -240,7 +240,7 @@ CREATE TABLE files(
file_crypto_nonce BLOB,
note_folder_id INTEGER DEFAULT NULL REFERENCES note_folders ON DELETE CASCADE,
redirect_file_id INTEGER REFERENCES files ON DELETE CASCADE
);
) STRICT;
CREATE TABLE snd_files(
file_id INTEGER NOT NULL REFERENCES files ON DELETE CASCADE,
connection_id INTEGER NOT NULL REFERENCES connections ON DELETE CASCADE,
@@ -253,7 +253,7 @@ CREATE TABLE snd_files(
file_descr_id INTEGER NULL
REFERENCES xftp_file_descriptions ON DELETE SET NULL,
PRIMARY KEY(file_id, connection_id)
) WITHOUT ROWID;
) WITHOUT ROWID, STRICT;
CREATE TABLE rcv_files(
file_id INTEGER PRIMARY KEY REFERENCES files ON DELETE CASCADE,
file_status TEXT NOT NULL, -- new, accepted, connected, completed
@@ -270,7 +270,7 @@ CREATE TABLE rcv_files(
agent_rcv_file_deleted INTEGER DEFAULT 0 CHECK(agent_rcv_file_deleted NOT NULL),
to_receive INTEGER,
user_approved_relays INTEGER NOT NULL DEFAULT 0
);
) STRICT;
CREATE TABLE rcv_file_chunks(
file_id INTEGER NOT NULL REFERENCES rcv_files ON DELETE CASCADE,
chunk_number INTEGER NOT NULL,
@@ -279,7 +279,7 @@ CREATE TABLE rcv_file_chunks(
created_at TEXT CHECK(created_at NOT NULL),
updated_at TEXT CHECK(updated_at NOT NULL), -- 0(received), 1(appended to file)
PRIMARY KEY(file_id, chunk_number)
) WITHOUT ROWID;
) WITHOUT ROWID, STRICT;
CREATE TABLE connections(
-- all SMP agent connections
connection_id INTEGER PRIMARY KEY,
@@ -302,7 +302,7 @@ CREATE TABLE connections(
REFERENCES user_contact_links(user_contact_link_id) ON DELETE SET NULL,
custom_user_profile_id INTEGER REFERENCES contact_profiles ON DELETE SET NULL,
conn_req_inv BLOB,
local_alias DEFAULT '' CHECK(local_alias NOT NULL),
local_alias TEXT DEFAULT '' CHECK(local_alias NOT NULL),
via_group_link INTEGER DEFAULT 0 CHECK(via_group_link NOT NULL),
group_link_id BLOB,
security_code TEXT NULL,
@@ -325,7 +325,7 @@ CREATE TABLE connections(
REFERENCES snd_files(file_id, connection_id)
ON DELETE CASCADE
DEFERRABLE INITIALLY DEFERRED
);
) STRICT;
CREATE TABLE user_contact_links(
user_contact_link_id INTEGER PRIMARY KEY,
conn_req_contact BLOB NOT NULL,
@@ -344,7 +344,7 @@ CREATE TABLE user_contact_links(
short_link_data_set INTEGER NOT NULL DEFAULT 0,
short_link_large_data_set INTEGER NOT NULL DEFAULT 0,
UNIQUE(user_id, local_display_name)
);
) STRICT;
CREATE TABLE contact_requests(
contact_request_id INTEGER PRIMARY KEY,
user_contact_link_id INTEGER REFERENCES user_contact_links
@@ -372,7 +372,7 @@ CREATE TABLE contact_requests(
DEFERRABLE INITIALLY DEFERRED,
UNIQUE(user_id, local_display_name),
UNIQUE(user_id, contact_profile_id)
);
) STRICT;
CREATE TABLE messages(
message_id INTEGER PRIMARY KEY,
msg_sent INTEGER NOT NULL, -- 0 for received, 1 for sent
@@ -388,14 +388,14 @@ CREATE TABLE messages(
author_group_member_id INTEGER REFERENCES group_members ON DELETE SET NULL,
forwarded_by_group_member_id INTEGER REFERENCES group_members ON DELETE SET NULL,
broker_ts TEXT
);
) STRICT;
CREATE TABLE pending_group_messages(
pending_group_message_id INTEGER PRIMARY KEY,
group_member_id INTEGER NOT NULL REFERENCES group_members ON DELETE CASCADE,
message_id INTEGER NOT NULL REFERENCES messages ON DELETE CASCADE,
created_at TEXT NOT NULL DEFAULT(datetime('now')),
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
);
) STRICT;
CREATE TABLE chat_items(
chat_item_id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
@@ -441,7 +441,7 @@ CREATE TABLE chat_items(
group_scope_tag TEXT,
group_scope_group_member_id INTEGER REFERENCES group_members(group_member_id) ON DELETE CASCADE,
show_group_as_sender INTEGER NOT NULL DEFAULT 0
);
) STRICT;
CREATE TABLE sqlite_sequence(name,seq);
CREATE TABLE chat_item_messages(
chat_item_id INTEGER NOT NULL REFERENCES chat_items ON DELETE CASCADE,
@@ -449,21 +449,21 @@ CREATE TABLE chat_item_messages(
created_at TEXT NOT NULL DEFAULT(datetime('now')),
updated_at TEXT NOT NULL DEFAULT(datetime('now')),
UNIQUE(chat_item_id, message_id)
);
) STRICT;
CREATE TABLE calls(
-- stores call invitations state for communicating state between NSE and app when call notification comes
call_id INTEGER PRIMARY KEY,
contact_id INTEGER NOT NULL REFERENCES contacts ON DELETE CASCADE,
shared_call_id BLOB NOT NULL,
chat_item_id INTEGER NOT NULL REFERENCES chat_items ON DELETE CASCADE,
call_state BLOB NOT NULL,
call_state TEXT NOT NULL,
call_ts TEXT NOT NULL,
user_id INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
created_at TEXT NOT NULL DEFAULT(datetime('now')),
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
,
call_uuid TEXT NOT NULL DEFAULT ""
);
) STRICT;
CREATE TABLE commands(
command_id INTEGER PRIMARY KEY AUTOINCREMENT, -- used as ACorrId
connection_id INTEGER REFERENCES connections ON DELETE CASCADE,
@@ -472,14 +472,14 @@ CREATE TABLE commands(
user_id INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
created_at TEXT NOT NULL DEFAULT(datetime('now')),
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
);
) STRICT;
CREATE TABLE settings(
settings_id INTEGER PRIMARY KEY,
chat_item_ttl INTEGER,
user_id INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
created_at TEXT NOT NULL DEFAULT(datetime('now')),
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
);
) STRICT;
CREATE TABLE IF NOT EXISTS "protocol_servers"(
smp_server_id INTEGER PRIMARY KEY,
host TEXT NOT NULL,
@@ -494,7 +494,7 @@ CREATE TABLE IF NOT EXISTS "protocol_servers"(
updated_at TEXT NOT NULL DEFAULT(datetime('now')),
protocol TEXT NOT NULL DEFAULT 'smp',
UNIQUE(user_id, host, port)
);
) STRICT;
CREATE TABLE xftp_file_descriptions(
file_descr_id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
@@ -503,7 +503,7 @@ CREATE TABLE xftp_file_descriptions(
file_descr_complete INTEGER NOT NULL DEFAULT(0),
created_at TEXT NOT NULL DEFAULT(datetime('now')),
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
);
) STRICT;
CREATE TABLE extra_xftp_file_descriptions(
extra_file_descr_id INTEGER PRIMARY KEY,
file_id INTEGER NOT NULL REFERENCES files ON DELETE CASCADE,
@@ -511,7 +511,7 @@ CREATE TABLE extra_xftp_file_descriptions(
file_descr_text TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT(datetime('now')),
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
);
) STRICT;
CREATE TABLE chat_item_versions(
-- contains versions only for edited chat items, including current version
chat_item_version_id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -520,7 +520,7 @@ CREATE TABLE chat_item_versions(
item_version_ts TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT(datetime('now')),
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
);
) STRICT;
CREATE TABLE chat_item_reactions(
chat_item_reaction_id INTEGER PRIMARY KEY AUTOINCREMENT,
item_member_id BLOB, -- member that created item, NULL for items in direct chats
@@ -534,7 +534,7 @@ CREATE TABLE chat_item_reactions(
reaction_ts TEXT NOT NULL, -- broker_ts of creating message for received, created_at for sent
created_at TEXT NOT NULL DEFAULT(datetime('now')),
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
);
) STRICT;
CREATE TABLE chat_item_moderations(
chat_item_moderation_id INTEGER PRIMARY KEY,
group_id INTEGER NOT NULL REFERENCES groups ON DELETE CASCADE,
@@ -545,7 +545,7 @@ CREATE TABLE chat_item_moderations(
moderated_at TEXT NOT NULL, -- broker_ts of creating message
created_at TEXT NOT NULL DEFAULT(datetime('now')),
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
);
) STRICT;
CREATE TABLE group_snd_item_statuses(
group_snd_item_status_id INTEGER PRIMARY KEY,
chat_item_id INTEGER NOT NULL REFERENCES chat_items ON DELETE CASCADE,
@@ -555,7 +555,7 @@ CREATE TABLE group_snd_item_statuses(
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
,
via_proxy INTEGER
);
) STRICT;
CREATE TABLE IF NOT EXISTS "sent_probes"(
sent_probe_id INTEGER PRIMARY KEY,
contact_id INTEGER REFERENCES contacts ON DELETE CASCADE,
@@ -565,7 +565,7 @@ CREATE TABLE IF NOT EXISTS "sent_probes"(
created_at TEXT CHECK(created_at NOT NULL),
updated_at TEXT CHECK(updated_at NOT NULL),
UNIQUE(user_id, probe)
);
) STRICT;
CREATE TABLE IF NOT EXISTS "sent_probe_hashes"(
sent_probe_hash_id INTEGER PRIMARY KEY,
sent_probe_id INTEGER NOT NULL REFERENCES "sent_probes" ON DELETE CASCADE,
@@ -574,7 +574,7 @@ CREATE TABLE IF NOT EXISTS "sent_probe_hashes"(
user_id INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
created_at TEXT CHECK(created_at NOT NULL),
updated_at TEXT CHECK(updated_at NOT NULL)
);
) STRICT;
CREATE TABLE IF NOT EXISTS "received_probes"(
received_probe_id INTEGER PRIMARY KEY,
contact_id INTEGER REFERENCES contacts ON DELETE CASCADE,
@@ -584,7 +584,7 @@ CREATE TABLE IF NOT EXISTS "received_probes"(
user_id INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
created_at TEXT CHECK(created_at NOT NULL),
updated_at TEXT CHECK(updated_at NOT NULL)
);
) STRICT;
CREATE TABLE remote_hosts(
-- e.g., mobiles known to a desktop app
remote_host_id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -599,7 +599,7 @@ CREATE TABLE remote_hosts(
bind_addr TEXT,
bind_iface TEXT,
bind_port INTEGER
);
) STRICT;
CREATE TABLE remote_controllers(
-- e.g., desktops known to a mobile app
remote_ctrl_id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -610,7 +610,7 @@ CREATE TABLE remote_controllers(
id_pub BLOB NOT NULL, -- remote controller long-term/identity key to verify signatures
dh_priv_key BLOB NOT NULL, -- last session DH key
prev_dh_priv_key BLOB -- previous session DH key
);
) STRICT;
CREATE TABLE IF NOT EXISTS "msg_deliveries"(
msg_delivery_id INTEGER PRIMARY KEY,
message_id INTEGER NOT NULL REFERENCES messages ON DELETE CASCADE, -- non UNIQUE for group messages and for batched messages
@@ -621,7 +621,7 @@ CREATE TABLE IF NOT EXISTS "msg_deliveries"(
created_at TEXT CHECK(created_at NOT NULL),
updated_at TEXT CHECK(updated_at NOT NULL),
delivery_status TEXT -- MsgDeliveryStatus
);
) STRICT;
CREATE TABLE note_folders(
note_folder_id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
@@ -630,8 +630,8 @@ CREATE TABLE note_folders(
chat_ts TEXT NOT NULL DEFAULT(datetime('now')),
favorite INTEGER NOT NULL DEFAULT 0,
unread_chat INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE app_settings(app_settings TEXT NOT NULL);
) STRICT;
CREATE TABLE app_settings(app_settings TEXT NOT NULL) STRICT;
CREATE TABLE server_operators(
server_operator_id INTEGER PRIMARY KEY AUTOINCREMENT,
server_operator_tag TEXT,
@@ -645,14 +645,14 @@ CREATE TABLE server_operators(
xftp_role_proxy INTEGER NOT NULL DEFAULT 1,
created_at TEXT NOT NULL DEFAULT(datetime('now')),
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
);
) STRICT;
CREATE TABLE usage_conditions(
usage_conditions_id INTEGER PRIMARY KEY AUTOINCREMENT,
conditions_commit TEXT NOT NULL UNIQUE,
notified_at TEXT,
created_at TEXT NOT NULL DEFAULT(datetime('now')),
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
);
) STRICT;
CREATE TABLE operator_usage_conditions(
operator_usage_conditions_id INTEGER PRIMARY KEY AUTOINCREMENT,
server_operator_id INTEGER REFERENCES server_operators(server_operator_id) ON DELETE SET NULL ON UPDATE CASCADE,
@@ -662,26 +662,26 @@ CREATE TABLE operator_usage_conditions(
created_at TEXT NOT NULL DEFAULT(datetime('now'))
,
auto_accepted INTEGER DEFAULT 0
);
) STRICT;
CREATE TABLE chat_tags(
chat_tag_id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER REFERENCES users ON DELETE CASCADE,
chat_tag_text TEXT NOT NULL,
chat_tag_emoji TEXT,
tag_order INTEGER NOT NULL
);
) STRICT;
CREATE TABLE chat_tags_chats(
contact_id INTEGER REFERENCES contacts ON DELETE CASCADE,
group_id INTEGER REFERENCES groups ON DELETE CASCADE,
chat_tag_id INTEGER NOT NULL REFERENCES chat_tags ON DELETE CASCADE
);
) STRICT;
CREATE TABLE chat_item_mentions(
chat_item_mention_id INTEGER PRIMARY KEY AUTOINCREMENT,
group_id INTEGER NOT NULL REFERENCES groups ON DELETE CASCADE,
member_id BLOB NOT NULL,
chat_item_id INTEGER NOT NULL REFERENCES chat_items ON DELETE CASCADE,
display_name TEXT NOT NULL
);
) STRICT;
CREATE TABLE delivery_tasks(
delivery_task_id INTEGER PRIMARY KEY AUTOINCREMENT,
group_id INTEGER NOT NULL REFERENCES groups ON DELETE CASCADE,
@@ -697,7 +697,7 @@ CREATE TABLE delivery_tasks(
failed INTEGER DEFAULT 0,
created_at TEXT NOT NULL DEFAULT(datetime('now')),
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
);
) STRICT;
CREATE TABLE delivery_jobs(
delivery_job_id INTEGER PRIMARY KEY AUTOINCREMENT,
group_id INTEGER NOT NULL REFERENCES groups ON DELETE CASCADE,
@@ -713,16 +713,16 @@ CREATE TABLE delivery_jobs(
failed INTEGER DEFAULT 0,
created_at TEXT NOT NULL DEFAULT(datetime('now')),
updated_at TEXT NOT NULL DEFAULT(datetime('now'))
);
) STRICT;
CREATE TABLE group_member_status_predicates(
member_status TEXT NOT NULL PRIMARY KEY,
current_member INTEGER NOT NULL DEFAULT 0
);
) STRICT;
CREATE TABLE connections_sync(
connections_sync_id INTEGER PRIMARY KEY AUTOINCREMENT,
should_sync INTEGER NOT NULL DEFAULT 0,
last_sync_ts TEXT
);
) STRICT;
CREATE INDEX contact_profiles_index ON contact_profiles(
display_name,
full_name