2023-09-18 23:57:18 +00:00
|
|
|
PRAGMA foreign_keys = ON;
|
2023-09-23 02:12:36 +00:00
|
|
|
PRAGMA journal_mode = WAL;
|
2023-09-18 23:57:18 +00:00
|
|
|
|
|
|
|
-- Authentication
|
|
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
|
|
id TEXT NOT NULL PRIMARY KEY,
|
|
|
|
|
|
|
|
pass TEXT NOT NULL,
|
|
|
|
admin BOOLEAN NOT NULL DEFAULT 0 CHECK (admin IN (0, 1)),
|
2023-09-21 00:35:01 +00:00
|
|
|
time_offset TEXT NOT NULL DEFAULT '0 hours',
|
2023-09-18 23:57:18 +00:00
|
|
|
|
|
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
|
|
);
|
|
|
|
|
|
|
|
-- Books / Documents
|
|
|
|
CREATE TABLE IF NOT EXISTS documents (
|
|
|
|
id TEXT NOT NULL PRIMARY KEY,
|
|
|
|
|
|
|
|
md5 TEXT,
|
|
|
|
filepath TEXT,
|
2023-09-23 18:14:57 +00:00
|
|
|
coverfile TEXT,
|
2023-09-18 23:57:18 +00:00
|
|
|
title TEXT,
|
|
|
|
author TEXT,
|
|
|
|
series TEXT,
|
|
|
|
series_index INTEGER,
|
|
|
|
lang TEXT,
|
|
|
|
description TEXT,
|
2023-10-01 23:17:22 +00:00
|
|
|
words INTEGER,
|
2023-09-23 18:14:57 +00:00
|
|
|
|
|
|
|
gbid TEXT,
|
2023-09-18 23:57:18 +00:00
|
|
|
olid TEXT,
|
2023-09-23 18:14:57 +00:00
|
|
|
isbn10 TEXT,
|
|
|
|
isbn13 TEXT,
|
|
|
|
|
2023-09-18 23:57:18 +00:00
|
|
|
synced BOOLEAN NOT NULL DEFAULT 0 CHECK (synced IN (0, 1)),
|
|
|
|
deleted BOOLEAN NOT NULL DEFAULT 0 CHECK (deleted IN (0, 1)),
|
|
|
|
|
|
|
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
|
|
);
|
|
|
|
|
2023-09-23 18:14:57 +00:00
|
|
|
-- Metadata
|
|
|
|
CREATE TABLE IF NOT EXISTS metadata (
|
|
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
|
|
|
|
|
document_id TEXT NOT NULL,
|
|
|
|
|
|
|
|
title TEXT,
|
|
|
|
author TEXT,
|
|
|
|
description TEXT,
|
|
|
|
gbid TEXT,
|
|
|
|
olid TEXT,
|
|
|
|
isbn10 TEXT,
|
|
|
|
isbn13 TEXT,
|
|
|
|
|
|
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
|
|
FOREIGN KEY (document_id) REFERENCES documents (id)
|
|
|
|
);
|
|
|
|
|
2023-09-18 23:57:18 +00:00
|
|
|
-- Devices
|
|
|
|
CREATE TABLE IF NOT EXISTS devices (
|
|
|
|
id TEXT NOT NULL PRIMARY KEY,
|
|
|
|
user_id TEXT NOT NULL,
|
|
|
|
|
|
|
|
device_name TEXT NOT NULL,
|
|
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
sync BOOLEAN NOT NULL DEFAULT 1 CHECK (sync IN (0, 1)),
|
|
|
|
|
|
|
|
FOREIGN KEY (user_id) REFERENCES users (id)
|
|
|
|
);
|
|
|
|
|
|
|
|
-- Document Device Sync
|
|
|
|
CREATE TABLE IF NOT EXISTS document_device_sync (
|
|
|
|
user_id TEXT NOT NULL,
|
|
|
|
document_id TEXT NOT NULL,
|
|
|
|
device_id TEXT NOT NULL,
|
|
|
|
|
|
|
|
last_synced DATETIME NOT NULL,
|
|
|
|
sync BOOLEAN NOT NULL DEFAULT 1 CHECK (sync IN (0, 1)),
|
|
|
|
|
|
|
|
FOREIGN KEY (user_id) REFERENCES users (id),
|
|
|
|
FOREIGN KEY (document_id) REFERENCES documents (id),
|
|
|
|
FOREIGN KEY (device_id) REFERENCES devices (id),
|
|
|
|
PRIMARY KEY (user_id, document_id, device_id)
|
|
|
|
);
|
|
|
|
|
|
|
|
-- User Document Progress
|
|
|
|
CREATE TABLE IF NOT EXISTS document_progress (
|
|
|
|
user_id TEXT NOT NULL,
|
|
|
|
document_id TEXT NOT NULL,
|
|
|
|
device_id TEXT NOT NULL,
|
|
|
|
|
|
|
|
percentage REAL NOT NULL,
|
|
|
|
progress TEXT NOT NULL,
|
|
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
|
|
FOREIGN KEY (user_id) REFERENCES users (id),
|
|
|
|
FOREIGN KEY (document_id) REFERENCES documents (id),
|
|
|
|
FOREIGN KEY (device_id) REFERENCES devices (id),
|
|
|
|
PRIMARY KEY (user_id, document_id, device_id)
|
|
|
|
);
|
|
|
|
|
|
|
|
-- Read Activity
|
|
|
|
CREATE TABLE IF NOT EXISTS activity (
|
|
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
|
user_id TEXT NOT NULL,
|
|
|
|
document_id TEXT NOT NULL,
|
|
|
|
device_id TEXT NOT NULL,
|
|
|
|
|
|
|
|
start_time DATETIME NOT NULL,
|
|
|
|
duration INTEGER NOT NULL,
|
2023-10-03 11:37:14 +00:00
|
|
|
page INTEGER NOT NULL,
|
|
|
|
pages INTEGER NOT NULL,
|
2023-09-18 23:57:18 +00:00
|
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
|
|
FOREIGN KEY (user_id) REFERENCES users (id),
|
|
|
|
FOREIGN KEY (document_id) REFERENCES documents (id),
|
|
|
|
FOREIGN KEY (device_id) REFERENCES devices (id)
|
|
|
|
);
|
|
|
|
|
2023-10-03 11:37:14 +00:00
|
|
|
-- Indexes
|
|
|
|
CREATE INDEX IF NOT EXISTS activity_start_time ON activity (start_time);
|
|
|
|
CREATE INDEX IF NOT EXISTS activity_user_id_document_id ON activity (
|
|
|
|
user_id,
|
|
|
|
document_id
|
|
|
|
);
|
|
|
|
|
2023-09-18 23:57:18 +00:00
|
|
|
-- Update Trigger
|
|
|
|
CREATE TRIGGER IF NOT EXISTS update_documents_updated_at
|
|
|
|
BEFORE UPDATE ON documents BEGIN
|
|
|
|
UPDATE documents
|
|
|
|
SET updated_at = CURRENT_TIMESTAMP
|
|
|
|
WHERE id = old.id;
|
|
|
|
END;
|
|
|
|
|
|
|
|
-- Rescaled Activity View (Adapted from KOReader)
|
|
|
|
CREATE VIEW IF NOT EXISTS rescaled_activity AS
|
|
|
|
|
2023-10-03 11:37:14 +00:00
|
|
|
WITH RECURSIVE nums (idx) AS (
|
2023-09-18 23:57:18 +00:00
|
|
|
SELECT 1 AS idx
|
|
|
|
UNION ALL
|
|
|
|
SELECT idx + 1
|
2023-10-03 11:37:14 +00:00
|
|
|
FROM nums
|
2023-09-18 23:57:18 +00:00
|
|
|
LIMIT 1000
|
|
|
|
),
|
|
|
|
|
2023-10-03 11:37:14 +00:00
|
|
|
current_pages AS (
|
2023-09-18 23:57:18 +00:00
|
|
|
SELECT
|
|
|
|
document_id,
|
2023-10-03 11:37:14 +00:00
|
|
|
user_id,
|
|
|
|
pages
|
2023-09-18 23:57:18 +00:00
|
|
|
FROM activity
|
2023-10-03 11:37:14 +00:00
|
|
|
GROUP BY document_id, user_id
|
2023-09-18 23:57:18 +00:00
|
|
|
HAVING MAX(start_time)
|
|
|
|
ORDER BY start_time DESC
|
|
|
|
),
|
|
|
|
|
|
|
|
intermediate AS (
|
|
|
|
SELECT
|
|
|
|
activity.document_id,
|
|
|
|
activity.device_id,
|
|
|
|
activity.user_id,
|
|
|
|
activity.start_time,
|
|
|
|
activity.duration,
|
2023-10-03 11:37:14 +00:00
|
|
|
activity.page,
|
|
|
|
current_pages.pages,
|
|
|
|
|
|
|
|
-- Derive first page
|
|
|
|
((activity.page - 1) * current_pages.pages) / activity.pages
|
2023-09-18 23:57:18 +00:00
|
|
|
+ 1 AS first_page,
|
2023-10-03 11:37:14 +00:00
|
|
|
|
|
|
|
-- Derive last page
|
2023-09-18 23:57:18 +00:00
|
|
|
MAX(
|
2023-10-03 11:37:14 +00:00
|
|
|
((activity.page - 1) * current_pages.pages)
|
|
|
|
/ activity.pages
|
2023-09-18 23:57:18 +00:00
|
|
|
+ 1,
|
2023-10-03 11:37:14 +00:00
|
|
|
(activity.page * current_pages.pages) / activity.pages
|
2023-09-18 23:57:18 +00:00
|
|
|
) AS last_page
|
2023-10-03 11:37:14 +00:00
|
|
|
|
2023-09-18 23:57:18 +00:00
|
|
|
FROM activity
|
2023-10-03 11:37:14 +00:00
|
|
|
INNER JOIN current_pages ON
|
|
|
|
current_pages.document_id = activity.document_id
|
|
|
|
AND current_pages.user_id = activity.user_id
|
|
|
|
),
|
|
|
|
|
|
|
|
-- Improves performance
|
|
|
|
num_limit AS (
|
|
|
|
SELECT * FROM nums
|
|
|
|
LIMIT (SELECT MAX(last_page - first_page + 1) FROM intermediate)
|
|
|
|
),
|
|
|
|
|
|
|
|
rescaled_raw AS (
|
|
|
|
SELECT
|
|
|
|
document_id,
|
|
|
|
device_id,
|
|
|
|
user_id,
|
|
|
|
start_time,
|
|
|
|
last_page,
|
|
|
|
pages,
|
|
|
|
first_page + num_limit.idx - 1 AS page,
|
|
|
|
duration / (
|
|
|
|
last_page - first_page + 1.0
|
|
|
|
) AS duration
|
|
|
|
FROM intermediate
|
|
|
|
JOIN num_limit ON
|
|
|
|
num_limit.idx <= (last_page - first_page + 1)
|
2023-09-18 23:57:18 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
SELECT
|
|
|
|
document_id,
|
|
|
|
device_id,
|
|
|
|
user_id,
|
|
|
|
start_time,
|
2023-10-03 11:37:14 +00:00
|
|
|
pages,
|
|
|
|
page,
|
|
|
|
|
|
|
|
-- Round up if last page (maintains total duration)
|
|
|
|
CAST(CASE
|
|
|
|
WHEN page = last_page AND duration != CAST(duration AS INTEGER)
|
|
|
|
THEN duration + 1
|
|
|
|
ELSE duration
|
|
|
|
END AS INTEGER) AS duration
|
|
|
|
FROM rescaled_raw;
|