mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-23 17:28:29 +02:00
Embed migrations into Rust binary
This commit is contained in:
@@ -7,6 +7,8 @@ publish = false
|
||||
|
||||
[dependencies]
|
||||
chrono = { version = "0.4.38", features = ["serde"] }
|
||||
hex = "0.4.3"
|
||||
include_dir = "0.7"
|
||||
log = "0.4.22"
|
||||
nanoid = "0.4.0"
|
||||
r2d2 = "0.8.10"
|
||||
@@ -22,7 +24,6 @@ tauri-plugin-dialog = { workspace = true }
|
||||
thiserror = "2.0.11"
|
||||
tokio = { workspace = true }
|
||||
ts-rs = { workspace = true, features = ["chrono-impl", "serde-json-impl"] }
|
||||
hex = "0.4.3"
|
||||
|
||||
[build-dependencies]
|
||||
tauri-plugin = { workspace = true, features = ["build"] }
|
||||
|
||||
65
src-tauri/yaak-models/migrations/20230225181302_init.sql
Normal file
65
src-tauri/yaak-models/migrations/20230225181302_init.sql
Normal file
@@ -0,0 +1,65 @@
|
||||
CREATE TABLE key_values
|
||||
(
|
||||
model TEXT DEFAULT 'key_value' NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
deleted_at DATETIME,
|
||||
namespace TEXT NOT NULL,
|
||||
key TEXT NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
PRIMARY KEY (namespace, key)
|
||||
);
|
||||
|
||||
CREATE TABLE workspaces
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'workspace' NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
deleted_at DATETIME,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE http_requests
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'http_request' NOT NULL,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
deleted_at DATETIME,
|
||||
name TEXT NOT NULL,
|
||||
url TEXT NOT NULL,
|
||||
method TEXT NOT NULL,
|
||||
headers TEXT NOT NULL,
|
||||
body TEXT,
|
||||
body_type TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE http_responses
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'http_response' NOT NULL,
|
||||
request_id TEXT NOT NULL
|
||||
REFERENCES http_requests
|
||||
ON DELETE CASCADE,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
deleted_at DATETIME,
|
||||
elapsed INTEGER NOT NULL,
|
||||
status INTEGER NOT NULL,
|
||||
status_reason TEXT,
|
||||
url TEXT NOT NULL,
|
||||
body TEXT NOT NULL,
|
||||
headers TEXT NOT NULL,
|
||||
error TEXT
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE main.http_requests ADD COLUMN sort_priority REAL NOT NULL DEFAULT 0;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE http_requests ADD COLUMN authentication TEXT NOT NULL DEFAULT '{}';
|
||||
ALTER TABLE http_requests ADD COLUMN authentication_type TEXT;
|
||||
@@ -0,0 +1,5 @@
|
||||
DELETE FROM main.http_responses;
|
||||
ALTER TABLE http_responses DROP COLUMN body;
|
||||
ALTER TABLE http_responses ADD COLUMN body BLOB;
|
||||
ALTER TABLE http_responses ADD COLUMN body_path TEXT;
|
||||
ALTER TABLE http_responses ADD COLUMN content_length INTEGER;
|
||||
@@ -0,0 +1,15 @@
|
||||
CREATE TABLE environments
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'workspace' NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
deleted_at DATETIME,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
data TEXT NOT NULL
|
||||
DEFAULT '{}'
|
||||
);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE environments DROP COLUMN data;
|
||||
ALTER TABLE environments ADD COLUMN variables DEFAULT '[]' NOT NULL;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE workspaces ADD COLUMN variables DEFAULT '[]' NOT NULL;
|
||||
19
src-tauri/yaak-models/migrations/20231103142807_folders.sql
Normal file
19
src-tauri/yaak-models/migrations/20231103142807_folders.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
CREATE TABLE folders
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'folder' NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
deleted_at DATETIME,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
folder_id TEXT NULL
|
||||
REFERENCES folders
|
||||
ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
sort_priority REAL DEFAULT 0 NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE http_requests ADD COLUMN folder_id TEXT REFERENCES folders(id) ON DELETE CASCADE;
|
||||
@@ -0,0 +1,16 @@
|
||||
-- Rename old column to backup name
|
||||
ALTER TABLE http_requests
|
||||
RENAME COLUMN body TO body_old;
|
||||
|
||||
-- Create desired new body column
|
||||
ALTER TABLE http_requests
|
||||
ADD COLUMN body TEXT NOT NULL DEFAULT '{}';
|
||||
|
||||
-- Copy data from old to new body, in new JSON format
|
||||
UPDATE http_requests
|
||||
SET body = CASE WHEN body_old IS NULL THEN '{}' ELSE JSON_OBJECT('text', body_old) END
|
||||
WHERE TRUE;
|
||||
|
||||
-- Drop old column
|
||||
ALTER TABLE http_requests
|
||||
DROP COLUMN body_old;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE http_requests
|
||||
ADD COLUMN url_parameters TEXT NOT NULL DEFAULT '[]';
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE http_responses DROP COLUMN body;
|
||||
13
src-tauri/yaak-models/migrations/20240111221224_settings.sql
Normal file
13
src-tauri/yaak-models/migrations/20240111221224_settings.sql
Normal file
@@ -0,0 +1,13 @@
|
||||
CREATE TABLE settings
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'settings' NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
follow_redirects BOOLEAN DEFAULT TRUE NOT NULL,
|
||||
validate_certificates BOOLEAN DEFAULT TRUE NOT NULL,
|
||||
request_timeout INTEGER DEFAULT 0 NOT NULL,
|
||||
theme TEXT DEFAULT 'default' NOT NULL,
|
||||
appearance TEXT DEFAULT 'system' NOT NULL
|
||||
);
|
||||
@@ -0,0 +1,9 @@
|
||||
-- Add existing request-related settings to workspace
|
||||
ALTER TABLE workspaces ADD COLUMN setting_request_timeout INTEGER DEFAULT '0' NOT NULL;
|
||||
ALTER TABLE workspaces ADD COLUMN setting_validate_certificates BOOLEAN DEFAULT TRUE NOT NULL;
|
||||
ALTER TABLE workspaces ADD COLUMN setting_follow_redirects BOOLEAN DEFAULT TRUE NOT NULL;
|
||||
|
||||
-- Remove old settings that used to be global
|
||||
ALTER TABLE settings DROP COLUMN request_timeout;
|
||||
ALTER TABLE settings DROP COLUMN follow_redirects;
|
||||
ALTER TABLE settings DROP COLUMN validate_certificates;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE settings ADD COLUMN update_channel TEXT DEFAULT 'stable' NOT NULL;
|
||||
10
src-tauri/yaak-models/migrations/20240127013915_cookies.sql
Normal file
10
src-tauri/yaak-models/migrations/20240127013915_cookies.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
CREATE TABLE cookie_jars
|
||||
(
|
||||
id TEXT NOT NULL PRIMARY KEY,
|
||||
model TEXT DEFAULT 'cookie_jar' NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
cookies TEXT DEFAULT '[]' NOT NULL,
|
||||
workspace_id TEXT NOT NULL
|
||||
);
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE http_responses ADD COLUMN elapsed_headers INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE http_responses ADD COLUMN remote_addr TEXT;
|
||||
ALTER TABLE http_responses ADD COLUMN version TEXT;
|
||||
68
src-tauri/yaak-models/migrations/20240203164833_grpc.sql
Normal file
68
src-tauri/yaak-models/migrations/20240203164833_grpc.sql
Normal file
@@ -0,0 +1,68 @@
|
||||
CREATE TABLE grpc_requests
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'grpc_request' NOT NULL,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
folder_id TEXT NULL
|
||||
REFERENCES folders
|
||||
ON DELETE CASCADE,
|
||||
created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL,
|
||||
updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
sort_priority REAL NOT NULL,
|
||||
url TEXT NOT NULL,
|
||||
service TEXT NULL,
|
||||
method TEXT NULL,
|
||||
message TEXT NOT NULL,
|
||||
authentication TEXT DEFAULT '{}' NOT NULL,
|
||||
authentication_type TEXT NULL,
|
||||
metadata TEXT DEFAULT '[]' NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE grpc_connections
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'grpc_connection' NOT NULL,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
request_id TEXT NOT NULL
|
||||
REFERENCES grpc_requests
|
||||
ON DELETE CASCADE,
|
||||
created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL,
|
||||
updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL,
|
||||
url TEXT NOT NULL,
|
||||
service TEXT NOT NULL,
|
||||
method TEXT NOT NULL,
|
||||
status INTEGER DEFAULT -1 NOT NULL,
|
||||
error TEXT NULL,
|
||||
elapsed INTEGER DEFAULT 0 NOT NULL,
|
||||
trailers TEXT DEFAULT '{}' NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE grpc_events
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'grpc_event' NOT NULL,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
request_id TEXT NOT NULL
|
||||
REFERENCES grpc_requests
|
||||
ON DELETE CASCADE,
|
||||
connection_id TEXT NOT NULL
|
||||
REFERENCES grpc_connections
|
||||
ON DELETE CASCADE,
|
||||
created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL,
|
||||
updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL,
|
||||
metadata TEXT DEFAULT '{}' NOT NULL,
|
||||
event_type TEXT NOT NULL,
|
||||
status INTEGER NULL,
|
||||
error TEXT NULL,
|
||||
content TEXT NOT NULL
|
||||
);
|
||||
@@ -0,0 +1,4 @@
|
||||
ALTER TABLE settings
|
||||
ADD COLUMN theme_dark TEXT DEFAULT 'yaak-dark' NOT NULL;
|
||||
ALTER TABLE settings
|
||||
ADD COLUMN theme_light TEXT DEFAULT 'yaak-light' NOT NULL;
|
||||
@@ -0,0 +1,4 @@
|
||||
ALTER TABLE settings ADD COLUMN interface_font_size INTEGER DEFAULT 15 NOT NULL;
|
||||
ALTER TABLE settings ADD COLUMN interface_scale INTEGER DEFAULT 1 NOT NULL;
|
||||
ALTER TABLE settings ADD COLUMN editor_font_size INTEGER DEFAULT 13 NOT NULL;
|
||||
ALTER TABLE settings ADD COLUMN editor_soft_wrap BOOLEAN DEFAULT 1 NOT NULL;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE settings ADD COLUMN open_workspace_new_window BOOLEAN NULL DEFAULT NULL;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE environments DROP COLUMN model;
|
||||
ALTER TABLE environments ADD COLUMN model TEXT DEFAULT 'environment';
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE settings ADD COLUMN telemetry BOOLEAN DEFAULT TRUE;
|
||||
12
src-tauri/yaak-models/migrations/20240829131004_plugins.sql
Normal file
12
src-tauri/yaak-models/migrations/20240829131004_plugins.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
CREATE TABLE plugins
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'plugin' NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
checked_at DATETIME NULL,
|
||||
enabled BOOLEAN NOT NULL,
|
||||
directory TEXT NULL NOT NULL,
|
||||
url TEXT NULL
|
||||
);
|
||||
@@ -0,0 +1,5 @@
|
||||
ALTER TABLE http_responses
|
||||
ADD COLUMN state TEXT DEFAULT 'closed' NOT NULL;
|
||||
|
||||
ALTER TABLE grpc_connections
|
||||
ADD COLUMN state TEXT DEFAULT 'closed' NOT NULL;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE settings ADD COLUMN proxy TEXT;
|
||||
8
src-tauri/yaak-models/migrations/20241217204951_docs.sql
Normal file
8
src-tauri/yaak-models/migrations/20241217204951_docs.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
ALTER TABLE http_requests
|
||||
ADD COLUMN description TEXT DEFAULT '' NOT NULL;
|
||||
|
||||
ALTER TABLE grpc_requests
|
||||
ADD COLUMN description TEXT DEFAULT '' NOT NULL;
|
||||
|
||||
ALTER TABLE folders
|
||||
ADD COLUMN description TEXT DEFAULT '' NOT NULL;
|
||||
@@ -0,0 +1,45 @@
|
||||
-- Add the new field
|
||||
ALTER TABLE environments
|
||||
ADD COLUMN environment_id TEXT REFERENCES environments (id) ON DELETE CASCADE;
|
||||
|
||||
-- Create temporary column so we know which rows are meant to be base environments. We'll use this to update
|
||||
-- child environments to point to them.
|
||||
ALTER TABLE environments
|
||||
ADD COLUMN migrated_base_env BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
|
||||
-- Create a base environment for each workspace
|
||||
INSERT INTO environments (id, workspace_id, name, variables, migrated_base_env)
|
||||
SELECT (
|
||||
-- This is the best way to generate a random string in SQLite, apparently
|
||||
'ev_' || SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1)
|
||||
),
|
||||
workspaces.id,
|
||||
'Global Variables',
|
||||
variables,
|
||||
TRUE
|
||||
FROM workspaces;
|
||||
|
||||
-- Update all non-base environments to point to newly created base environments
|
||||
UPDATE environments
|
||||
SET environment_id = ( SELECT base_env.id
|
||||
FROM environments AS base_env
|
||||
WHERE base_env.workspace_id = environments.workspace_id
|
||||
AND base_env.migrated_base_env IS TRUE )
|
||||
WHERE migrated_base_env IS FALSE;
|
||||
|
||||
-- Drop temporary column
|
||||
ALTER TABLE environments
|
||||
DROP COLUMN migrated_base_env;
|
||||
|
||||
-- Drop the old variables column
|
||||
-- IMPORTANT: Skip to give the user the option to roll back to a previous app version. We can drop it once the migration working in the real world
|
||||
-- ALTER TABLE workspaces DROP COLUMN variables;
|
||||
21
src-tauri/yaak-models/migrations/20250102141937_sync.sql
Normal file
21
src-tauri/yaak-models/migrations/20250102141937_sync.sql
Normal file
@@ -0,0 +1,21 @@
|
||||
ALTER TABLE workspaces
|
||||
ADD COLUMN setting_sync_dir TEXT;
|
||||
|
||||
CREATE TABLE sync_states
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'sync_state' NOT NULL,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
flushed_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
checksum TEXT NOT NULL,
|
||||
model_id TEXT NOT NULL,
|
||||
sync_dir TEXT NOT NULL,
|
||||
rel_path TEXT NOT NULL,
|
||||
|
||||
UNIQUE (workspace_id, model_id)
|
||||
);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE settings
|
||||
ADD COLUMN editor_keymap TEXT DEFAULT 'codemirror' NOT NULL;
|
||||
@@ -0,0 +1,11 @@
|
||||
CREATE TABLE workspace_metas
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'workspace_meta' NOT NULL,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces ON DELETE CASCADE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
setting_sync_dir TEXT
|
||||
);
|
||||
@@ -0,0 +1,2 @@
|
||||
-- This setting was moved to the new workspace_metas table
|
||||
ALTER TABLE workspaces DROP COLUMN setting_sync_dir;
|
||||
@@ -0,0 +1,11 @@
|
||||
CREATE TABLE plugin_key_values
|
||||
(
|
||||
model TEXT DEFAULT 'plugin_key_value' NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
deleted_at DATETIME,
|
||||
plugin_name TEXT NOT NULL,
|
||||
key TEXT NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
PRIMARY KEY (plugin_name, key)
|
||||
);
|
||||
@@ -0,0 +1,66 @@
|
||||
CREATE TABLE websocket_requests
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'websocket_request' NOT NULL,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
folder_id TEXT
|
||||
REFERENCES folders
|
||||
ON DELETE CASCADE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
deleted_at DATETIME,
|
||||
authentication TEXT DEFAULT '{}' NOT NULL,
|
||||
authentication_type TEXT,
|
||||
description TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
url TEXT NOT NULL,
|
||||
headers TEXT NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
sort_priority REAL NOT NULL,
|
||||
url_parameters TEXT DEFAULT '[]' NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE websocket_connections
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'websocket_connection' NOT NULL,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
request_id TEXT NOT NULL
|
||||
REFERENCES websocket_requests
|
||||
ON DELETE CASCADE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
url TEXT NOT NULL,
|
||||
state TEXT NOT NULL,
|
||||
status INTEGER DEFAULT -1 NOT NULL,
|
||||
error TEXT NULL,
|
||||
elapsed INTEGER DEFAULT 0 NOT NULL,
|
||||
headers TEXT DEFAULT '{}' NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE websocket_events
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'websocket_event' NOT NULL,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
request_id TEXT NOT NULL
|
||||
REFERENCES websocket_requests
|
||||
ON DELETE CASCADE,
|
||||
connection_id TEXT NOT NULL
|
||||
REFERENCES websocket_connections
|
||||
ON DELETE CASCADE,
|
||||
created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL,
|
||||
updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL,
|
||||
is_server BOOLEAN NOT NULL,
|
||||
message_type TEXT NOT NULL,
|
||||
message BLOB NOT NULL
|
||||
);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE settings
|
||||
ADD COLUMN hide_window_controls BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
@@ -0,0 +1,43 @@
|
||||
-- 1. Create the new table with `id` as the primary key
|
||||
CREATE TABLE key_values_new
|
||||
(
|
||||
id TEXT PRIMARY KEY,
|
||||
model TEXT DEFAULT 'key_value' NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
deleted_at DATETIME,
|
||||
namespace TEXT NOT NULL,
|
||||
key TEXT NOT NULL,
|
||||
value TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- 2. Copy data from the old table
|
||||
INSERT INTO key_values_new (id, model, created_at, updated_at, deleted_at, namespace, key, value)
|
||||
SELECT (
|
||||
-- This is the best way to generate a random string in SQLite, apparently
|
||||
'kv_' || SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1) ||
|
||||
SUBSTR('abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23457789', (ABS(RANDOM()) % 57) + 1, 1)
|
||||
) AS id,
|
||||
model,
|
||||
created_at,
|
||||
updated_at,
|
||||
deleted_at,
|
||||
namespace,
|
||||
key,
|
||||
value
|
||||
FROM key_values;
|
||||
|
||||
-- 3. Drop the old table
|
||||
DROP TABLE key_values;
|
||||
|
||||
-- 4. Rename the new table
|
||||
ALTER TABLE key_values_new
|
||||
RENAME TO key_values;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE workspace_metas ADD COLUMN encryption_key TEXT NULL DEFAULT NULL;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE workspaces ADD COLUMN encryption_key_challenge TEXT NULL;
|
||||
243
src-tauri/yaak-models/migrations/20250424152740_remove-fks.sql
Normal file
243
src-tauri/yaak-models/migrations/20250424152740_remove-fks.sql
Normal file
@@ -0,0 +1,243 @@
|
||||
-- NOTE: SQLite does not support dropping foreign keys, so we need to create new
|
||||
-- tables and copy data instead. To prevent cascade deletes from wrecking stuff,
|
||||
-- we start with the leaf tables and finish with the parent tables (eg. folder).
|
||||
|
||||
----------------------------
|
||||
-- Remove http request FK --
|
||||
----------------------------
|
||||
|
||||
CREATE TABLE http_requests_dg_tmp
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'http_request' NOT NULL,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
deleted_at DATETIME,
|
||||
name TEXT NOT NULL,
|
||||
url TEXT NOT NULL,
|
||||
method TEXT NOT NULL,
|
||||
headers TEXT NOT NULL,
|
||||
body_type TEXT,
|
||||
sort_priority REAL DEFAULT 0 NOT NULL,
|
||||
authentication TEXT DEFAULT '{}' NOT NULL,
|
||||
authentication_type TEXT,
|
||||
folder_id TEXT,
|
||||
body TEXT DEFAULT '{}' NOT NULL,
|
||||
url_parameters TEXT DEFAULT '[]' NOT NULL,
|
||||
description TEXT DEFAULT '' NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO http_requests_dg_tmp(id, model, workspace_id, created_at, updated_at, deleted_at, name, url, method,
|
||||
headers, body_type, sort_priority, authentication, authentication_type, folder_id,
|
||||
body, url_parameters, description)
|
||||
SELECT id,
|
||||
model,
|
||||
workspace_id,
|
||||
created_at,
|
||||
updated_at,
|
||||
deleted_at,
|
||||
name,
|
||||
url,
|
||||
method,
|
||||
headers,
|
||||
body_type,
|
||||
sort_priority,
|
||||
authentication,
|
||||
authentication_type,
|
||||
folder_id,
|
||||
body,
|
||||
url_parameters,
|
||||
description
|
||||
FROM http_requests;
|
||||
|
||||
DROP TABLE http_requests;
|
||||
|
||||
ALTER TABLE http_requests_dg_tmp
|
||||
RENAME TO http_requests;
|
||||
|
||||
----------------------------
|
||||
-- Remove grpc request FK --
|
||||
----------------------------
|
||||
|
||||
CREATE TABLE grpc_requests_dg_tmp
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'grpc_request' NOT NULL,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
folder_id TEXT,
|
||||
created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL,
|
||||
updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
sort_priority REAL NOT NULL,
|
||||
url TEXT NOT NULL,
|
||||
service TEXT,
|
||||
method TEXT,
|
||||
message TEXT NOT NULL,
|
||||
authentication TEXT DEFAULT '{}' NOT NULL,
|
||||
authentication_type TEXT,
|
||||
metadata TEXT DEFAULT '[]' NOT NULL,
|
||||
description TEXT DEFAULT '' NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO grpc_requests_dg_tmp(id, model, workspace_id, folder_id, created_at, updated_at, name, sort_priority, url,
|
||||
service, method, message, authentication, authentication_type, metadata, description)
|
||||
SELECT id,
|
||||
model,
|
||||
workspace_id,
|
||||
folder_id,
|
||||
created_at,
|
||||
updated_at,
|
||||
name,
|
||||
sort_priority,
|
||||
url,
|
||||
service,
|
||||
method,
|
||||
message,
|
||||
authentication,
|
||||
authentication_type,
|
||||
metadata,
|
||||
description
|
||||
FROM grpc_requests;
|
||||
|
||||
DROP TABLE grpc_requests;
|
||||
|
||||
ALTER TABLE grpc_requests_dg_tmp
|
||||
RENAME TO grpc_requests;
|
||||
|
||||
---------------------------------
|
||||
-- Remove websocket request FK --
|
||||
---------------------------------
|
||||
|
||||
CREATE TABLE websocket_requests_dg_tmp
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'websocket_request' NOT NULL,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
folder_id TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
deleted_at DATETIME,
|
||||
authentication TEXT DEFAULT '{}' NOT NULL,
|
||||
authentication_type TEXT,
|
||||
description TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
url TEXT NOT NULL,
|
||||
headers TEXT NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
sort_priority REAL NOT NULL,
|
||||
url_parameters TEXT DEFAULT '[]' NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO websocket_requests_dg_tmp(id, model, workspace_id, folder_id, created_at, updated_at, deleted_at,
|
||||
authentication, authentication_type, description, name, url, headers, message,
|
||||
sort_priority, url_parameters)
|
||||
SELECT id,
|
||||
model,
|
||||
workspace_id,
|
||||
folder_id,
|
||||
created_at,
|
||||
updated_at,
|
||||
deleted_at,
|
||||
authentication,
|
||||
authentication_type,
|
||||
description,
|
||||
name,
|
||||
url,
|
||||
headers,
|
||||
message,
|
||||
sort_priority,
|
||||
url_parameters
|
||||
FROM websocket_requests;
|
||||
|
||||
DROP TABLE websocket_requests;
|
||||
|
||||
ALTER TABLE websocket_requests_dg_tmp
|
||||
RENAME TO websocket_requests;
|
||||
|
||||
---------------------------
|
||||
-- Remove environment FK --
|
||||
---------------------------
|
||||
|
||||
CREATE TABLE environments_dg_tmp
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
deleted_at DATETIME,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
variables DEFAULT '[]' NOT NULL,
|
||||
model TEXT DEFAULT 'environment',
|
||||
environment_id TEXT
|
||||
);
|
||||
|
||||
INSERT INTO environments_dg_tmp(id, created_at, updated_at, deleted_at, workspace_id, name, variables, model,
|
||||
environment_id)
|
||||
SELECT id,
|
||||
created_at,
|
||||
updated_at,
|
||||
deleted_at,
|
||||
workspace_id,
|
||||
name,
|
||||
variables,
|
||||
model,
|
||||
environment_id
|
||||
FROM environments;
|
||||
|
||||
DROP TABLE environments;
|
||||
|
||||
ALTER TABLE environments_dg_tmp
|
||||
RENAME TO environments;
|
||||
|
||||
----------------------
|
||||
-- Remove folder FK --
|
||||
----------------------
|
||||
|
||||
CREATE TABLE folders_dg_tmp
|
||||
(
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'folder' NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
deleted_at DATETIME,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
folder_id TEXT,
|
||||
name TEXT NOT NULL,
|
||||
sort_priority REAL DEFAULT 0 NOT NULL,
|
||||
description TEXT DEFAULT '' NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO folders_dg_tmp(id, model, created_at, updated_at, deleted_at, workspace_id, folder_id, name, sort_priority,
|
||||
description)
|
||||
SELECT id,
|
||||
model,
|
||||
created_at,
|
||||
updated_at,
|
||||
deleted_at,
|
||||
workspace_id,
|
||||
folder_id,
|
||||
name,
|
||||
sort_priority,
|
||||
description
|
||||
FROM folders;
|
||||
|
||||
DROP TABLE folders;
|
||||
|
||||
ALTER TABLE folders_dg_tmp
|
||||
RENAME TO folders;
|
||||
@@ -0,0 +1,11 @@
|
||||
-- There used to be sync code that skipped over environments because we didn't
|
||||
-- want to sync potentially insecure data. With encryption, it is now possible
|
||||
-- to sync environments securely. However, there were already sync states in the
|
||||
-- DB that marked environments as "Synced". Running the sync code on these envs
|
||||
-- would mark them as deleted by FS (exist in SyncState but not on FS).
|
||||
--
|
||||
-- To undo this mess, we have this migration to delete all environment-related
|
||||
-- sync states so we can sync from a clean slate.
|
||||
DELETE
|
||||
FROM sync_states
|
||||
WHERE model_id LIKE 'ev_%';
|
||||
@@ -0,0 +1,20 @@
|
||||
-- Add a public column to represent whether an environment can be shared or exported
|
||||
ALTER TABLE environments
|
||||
ADD COLUMN public BOOLEAN DEFAULT FALSE;
|
||||
|
||||
-- Add a base column to represent whether an environment is a base or sub environment. We used to
|
||||
-- do this with environment_id, but we need a more flexible solution now that envs can be optionally
|
||||
-- synced. E.g., it's now possible to only import a sub environment from a different client without
|
||||
-- its base environment "parent."
|
||||
ALTER TABLE environments
|
||||
ADD COLUMN base BOOLEAN DEFAULT FALSE;
|
||||
|
||||
-- SQLite doesn't support dynamic default values, so we update `base` based on the value of
|
||||
-- environment_id.
|
||||
UPDATE environments
|
||||
SET base = TRUE
|
||||
WHERE environment_id IS NULL;
|
||||
|
||||
-- Finally, we drop the old `environment_id` column that will no longer be used
|
||||
ALTER TABLE environments
|
||||
DROP COLUMN environment_id;
|
||||
@@ -0,0 +1,15 @@
|
||||
-- Auth
|
||||
ALTER TABLE workspaces
|
||||
ADD COLUMN authentication TEXT NOT NULL DEFAULT '{}';
|
||||
ALTER TABLE folders
|
||||
ADD COLUMN authentication TEXT NOT NULL DEFAULT '{}';
|
||||
ALTER TABLE workspaces
|
||||
ADD COLUMN authentication_type TEXT;
|
||||
ALTER TABLE folders
|
||||
ADD COLUMN authentication_type TEXT;
|
||||
|
||||
-- Headers
|
||||
ALTER TABLE workspaces
|
||||
ADD COLUMN headers TEXT NOT NULL DEFAULT '[]';
|
||||
ALTER TABLE folders
|
||||
ADD COLUMN headers TEXT NOT NULL DEFAULT '[]';
|
||||
@@ -0,0 +1,21 @@
|
||||
-- Clean up old key/values that are no longer used
|
||||
DELETE
|
||||
FROM key_values
|
||||
WHERE key LIKE 'graphql_introspection::%';
|
||||
|
||||
CREATE TABLE graphql_introspections
|
||||
(
|
||||
|
||||
id TEXT NOT NULL
|
||||
PRIMARY KEY,
|
||||
model TEXT DEFAULT 'graphql_introspection' NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces
|
||||
ON DELETE CASCADE,
|
||||
request_id TEXT NULL
|
||||
REFERENCES http_requests
|
||||
ON DELETE CASCADE,
|
||||
content TEXT NULL
|
||||
);
|
||||
@@ -0,0 +1,43 @@
|
||||
-- Add sync_dir to the unique index, or else it will fail if the user disables sync
|
||||
-- and re-enables it for a different directory.
|
||||
|
||||
-- Step 1: Rename the existing table
|
||||
ALTER TABLE sync_states
|
||||
RENAME TO sync_states_old;
|
||||
|
||||
-- Step 2: Create the new table with the updated unique constraint
|
||||
CREATE TABLE sync_states
|
||||
(
|
||||
id TEXT NOT NULL PRIMARY KEY,
|
||||
model TEXT DEFAULT 'sync_state' NOT NULL,
|
||||
workspace_id TEXT NOT NULL
|
||||
REFERENCES workspaces ON DELETE CASCADE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
flushed_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
checksum TEXT NOT NULL,
|
||||
model_id TEXT NOT NULL,
|
||||
sync_dir TEXT NOT NULL,
|
||||
rel_path TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX idx_sync_states_unique
|
||||
ON sync_states (workspace_id, model_id, sync_dir);
|
||||
|
||||
-- Step 3: Copy the data
|
||||
INSERT INTO sync_states (id, model, workspace_id, created_at, updated_at,
|
||||
flushed_at, checksum, model_id, sync_dir, rel_path)
|
||||
SELECT id,
|
||||
model,
|
||||
workspace_id,
|
||||
created_at,
|
||||
updated_at,
|
||||
flushed_at,
|
||||
checksum,
|
||||
model_id,
|
||||
sync_dir,
|
||||
rel_path
|
||||
FROM sync_states_old;
|
||||
|
||||
-- Step 4: Drop the old table
|
||||
DROP TABLE sync_states_old;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE settings
|
||||
ADD COLUMN colored_methods BOOLEAN DEFAULT FALSE;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE environments ADD COLUMN color TEXT;
|
||||
@@ -59,7 +59,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
.build(manager)
|
||||
.unwrap();
|
||||
|
||||
if let Err(e) = migrate_db(app_handle.app_handle(), &pool) {
|
||||
if let Err(e) = migrate_db(&pool) {
|
||||
error!("Failed to run database migration {e:?}");
|
||||
app_handle
|
||||
.dialog()
|
||||
|
||||
@@ -1,26 +1,16 @@
|
||||
use crate::error::Error::MigrationError;
|
||||
use crate::error::Result;
|
||||
use log::info;
|
||||
use include_dir::{include_dir, Dir, DirEntry};
|
||||
use log::{debug, info};
|
||||
use r2d2::Pool;
|
||||
use r2d2_sqlite::SqliteConnectionManager;
|
||||
use rusqlite::{OptionalExtension, TransactionBehavior, params};
|
||||
use rusqlite::{params, OptionalExtension, TransactionBehavior};
|
||||
use sha2::{Digest, Sha384};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::result::Result as StdResult;
|
||||
use tauri::path::BaseDirectory;
|
||||
use tauri::{AppHandle, Manager, Runtime};
|
||||
|
||||
pub(crate) fn migrate_db<R: Runtime>(
|
||||
app_handle: &AppHandle<R>,
|
||||
pool: &Pool<SqliteConnectionManager>,
|
||||
) -> Result<()> {
|
||||
let migrations_dir = app_handle
|
||||
.path()
|
||||
.resolve("migrations", BaseDirectory::Resource)
|
||||
.expect("failed to resolve resource");
|
||||
static MIGRATIONS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/migrations");
|
||||
|
||||
info!("Running database migrations from: {:?}", migrations_dir);
|
||||
pub(crate) fn migrate_db(pool: &Pool<SqliteConnectionManager>) -> Result<()> {
|
||||
info!("Running database migrations");
|
||||
|
||||
// Ensure the table exists
|
||||
// NOTE: Yaak used to use sqlx for migrations, so we need to mirror that table structure. We
|
||||
@@ -39,20 +29,22 @@ pub(crate) fn migrate_db<R: Runtime>(
|
||||
)?;
|
||||
|
||||
// Read and sort all .sql files
|
||||
let mut entries = fs::read_dir(migrations_dir)
|
||||
.expect("Failed to find migrations directory")
|
||||
.filter_map(StdResult::ok)
|
||||
let mut entries = MIGRATIONS_DIR
|
||||
.entries()
|
||||
.into_iter()
|
||||
.filter(|e| e.path().extension().map(|ext| ext == "sql").unwrap_or(false))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Ensure they're in the correct order
|
||||
entries.sort_by_key(|e| e.file_name());
|
||||
entries.sort_by_key(|e| e.path());
|
||||
|
||||
// Run each migration in a transaction
|
||||
let mut num_migrations = 0;
|
||||
for entry in entries {
|
||||
num_migrations += 1;
|
||||
let mut conn = pool.get()?;
|
||||
let mut tx = conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
|
||||
match run_migration(entry.path().as_path(), &mut tx) {
|
||||
match run_migration(entry, &mut tx) {
|
||||
Ok(_) => tx.commit()?,
|
||||
Err(e) => {
|
||||
let msg = format!(
|
||||
@@ -66,16 +58,15 @@ pub(crate) fn migrate_db<R: Runtime>(
|
||||
};
|
||||
}
|
||||
|
||||
info!("Finished running migrations");
|
||||
info!("Finished running {} migrations", num_migrations);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_migration(migration_path: &Path, tx: &mut rusqlite::Transaction) -> Result<bool> {
|
||||
fn run_migration(migration_path: &DirEntry, tx: &mut rusqlite::Transaction) -> Result<bool> {
|
||||
let start = std::time::Instant::now();
|
||||
let (version, description) =
|
||||
split_migration_filename(migration_path.file_name().unwrap().to_str().unwrap())
|
||||
.expect("Failed to parse migration filename");
|
||||
let (version, description) = split_migration_filename(migration_path.path().to_str().unwrap())
|
||||
.expect("Failed to parse migration filename");
|
||||
|
||||
// Skip if already applied
|
||||
let row: Option<i64> = tx
|
||||
@@ -85,11 +76,13 @@ fn run_migration(migration_path: &Path, tx: &mut rusqlite::Transaction) -> Resul
|
||||
.optional()?;
|
||||
|
||||
if row.is_some() {
|
||||
debug!("Skipping migration {description}");
|
||||
// Migration was already run
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let sql = fs::read_to_string(migration_path).expect("Failed to read migration file");
|
||||
let sql =
|
||||
migration_path.as_file().unwrap().contents_utf8().expect("Failed to read migration file");
|
||||
info!("Applying migration {description}");
|
||||
|
||||
// Split on `;`? → optional depending on how your SQL is structured
|
||||
|
||||
Reference in New Issue
Block a user