-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdictum.sql
More file actions
418 lines (341 loc) · 10 KB
/
dictum.sql
File metadata and controls
418 lines (341 loc) · 10 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
CREATE DATABASE IF NOT EXISTS dictum CHARACTER SET utf8mb4;
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
provider VARCHAR(16) NOT NULL,
provider_id VARCHAR(128),
email VARCHAR(128) NOT NULL UNIQUE,
name VARCHAR(128),
avatar VARCHAR(256),
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_used TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY (provider, provider_id)
) CHARSET=utf8mb4 COLLATE utf8mb4_bin;
CREATE TABLE IF NOT EXISTS sessions (
id VARCHAR(48) NOT NULL PRIMARY KEY,
uid INT,
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_used TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (uid) REFERENCES users(id) ON DELETE CASCADE
) CHARSET=utf8mb4 COLLATE utf8mb4_bin;
CREATE TABLE IF NOT EXISTS words (
id INT AUTO_INCREMENT PRIMARY KEY,
word VARCHAR(128) NOT NULL UNIQUE,
kotus INT UNSIGNED,
freq INT NOT NULL DEFAULT 0,
KEY (kotus),
KEY (freq)
) CHARSET=utf8mb4 COLLATE utf8mb4_bin;
CREATE TABLE IF NOT EXISTS tags (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(16) NOT NULL UNIQUE
) CHARSET=utf8mb4 COLLATE utf8mb4_bin;
CREATE TABLE IF NOT EXISTS word_tags (
uid INT,
tid INT,
wid INT,
PRIMARY KEY (uid, tid, wid),
FOREIGN KEY (tid) REFERENCES tags(id) ON DELETE CASCADE,
FOREIGN KEY (wid) REFERENCES words(id) ON DELETE CASCADE
) CHARSET=utf8mb4 COLLATE utf8mb4_bin;
CREATE TABLE IF NOT EXISTS user_tags (
uid INT,
tid INT,
PRIMARY KEY (uid, tid),
FOREIGN KEY (tid) REFERENCES tags(id) ON DELETE CASCADE
) CHARSET=utf8mb4 COLLATE utf8mb4_bin;
CREATE TABLE IF NOT EXISTS word_data (
uid INT,
wid INT,
notes TEXT,
score INT DEFAULT 0,
PRIMARY KEY (uid, wid),
FOREIGN KEY (uid) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (wid) REFERENCES words(id) ON DELETE CASCADE
) CHARSET=utf8mb4 COLLATE utf8mb4_bin;
CREATE TABLE IF NOT EXISTS history (
uid INT,
wid INT,
ts TIMESTAMP,
PRIMARY KEY (uid, wid, ts),
FOREIGN KEY (uid) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (wid) REFERENCES words(id) ON DELETE CASCADE
) CHARSET=utf8mb4 COLLATE utf8mb4_bin;
-- Functions
DELIMITER //
DROP FUNCTION IF EXISTS FindTagID;
CREATE FUNCTION FindTagID(_name VARCHAR(16))
RETURNS INT
READS SQL DATA
BEGIN
SET @id = NULL;
SELECT id INTO @id FROM tags WHERE name = _name;
RETURN @id;
END //
DELIMITER ;
DELIMITER //
DROP FUNCTION IF EXISTS GetTagID;
CREATE FUNCTION GetTagID(_name VARCHAR(16))
RETURNS INT
READS SQL DATA
BEGIN
SET @id = FindTagId(_name);
IF ISNULL(@id) THEN
INSERT INTO tags (name) VALUES (_name);
SET @id = LAST_INSERT_ID();
END IF;
RETURN @id;
END //
DELIMITER ;
DELIMITER //
DROP FUNCTION IF EXISTS GetWordID;
CREATE FUNCTION GetWordID(_word VARCHAR(128))
RETURNS INT
READS SQL DATA
BEGIN
SET @id = NULL;
SELECT id INTO @id FROM words WHERE word = _word;
IF ISNULL(@id) THEN
SIGNAL SQLSTATE '02000' SET MESSAGE_TEXT = 'Word not found.';
END IF;
RETURN @id;
END //
DELIMITER ;
-- Words
DELIMITER //
DROP PROCEDURE IF EXISTS GetWord;
CREATE PROCEDURE GetWord(
IN _sid VARCHAR(48),
IN _word VARCHAR(128))
SQL SECURITY DEFINER
BEGIN
SET @uid = AuthSIDToUID(_sid);
SET @wid = GetWordID(_word);
-- Data
SET @notes = NULL;
SET @score = NULL;
SELECT notes, score INTO @notes, @score FROM word_data
WHERE uid = @uid AND wid = @wid;
-- Data
SELECT @notes notes, @score score, COUNT(*) visits, MAX(ts) last FROM history
WHERE uid = @uid AND wid = @wid;
-- Tags
SELECT t.name FROM word_tags wt
JOIN tags t ON t.id = wt.tid
WHERE (wt.uid = @uid OR wt.uid = 0) AND wt.wid = @wid
GROUP BY wt.tid;
-- History
START TRANSACTION;
SET @dayago = DATE_SUB(NOW(), INTERVAL 1 DAY);
DELETE FROM history WHERE uid = @uid AND wid = @wid AND @dayago < ts;
INSERT INTO history (uid, wid, ts) VALUES (@uid, @wid, NOW());
COMMIT;
END //
DELIMITER ;
-- Tags
DELIMITER //
DROP PROCEDURE IF EXISTS GetTag;
CREATE PROCEDURE GetTag(IN _sid VARCHAR(48), IN _uid INT, IN _tag VARCHAR(256))
SQL SECURITY DEFINER
BEGIN
SET @uid = AuthLookupSID(_sid);
SET @tid = FindTagID(_tag);
SET @tagUID = IFNULL(_uid, @uid);
SELECT w.word, w.freq, wd1.notes, wd2.score FROM word_tags wt
JOIN words w ON w.id = wt.wid
LEFT JOIN word_data wd1 ON wd1.wid = wt.wid AND wd1.uid = @tagUID
LEFT JOIN word_data wd2 ON wd2.wid = wt.wid AND wd2.uid = @uid
WHERE (wt.uid = @tagUID OR wt.uid = 0) AND wt.tid = @tid
ORDER BY w.freq DESC LIMIT 10000;
END //
DELIMITER ;
DELIMITER //
DROP PROCEDURE IF EXISTS TagWord;
CREATE PROCEDURE TagWord(
IN _sid VARCHAR(48),
IN _word VARCHAR(128),
IN _tag VARCHAR(32))
SQL SECURITY DEFINER
BEGIN
INSERT INTO word_tags (uid, wid, tid)
VALUES (AuthSIDToUID(_sid), GetWordID(_word), GetTagID(_tag))
ON DUPLICATE KEY UPDATE wid = VALUES(wid);
END //
DELIMITER ;
DELIMITER //
DROP PROCEDURE IF EXISTS UntagWord;
CREATE PROCEDURE UntagWord(
IN _sid VARCHAR(48),
IN _word VARCHAR(128),
IN _tag VARCHAR(32))
SQL SECURITY DEFINER
BEGIN
SET @uid = AuthSIDToUID(_sid);
SET @wid = GetWordID(_word);
SET @tid = FindTagID(_tag);
DELETE FROM word_tags WHERE uid = @uid AND tid = @tid AND wid = @wid;
END //
DELIMITER ;
DELIMITER //
DROP PROCEDURE IF EXISTS GetUserTags;
CREATE PROCEDURE GetUserTags(IN _sid VARCHAR(48))
SQL SECURITY DEFINER
BEGIN
SET @uid = AuthSIDToUID(_sid);
SELECT t.name tag FROM user_tags u
LEFT JOIN tags t ON u.tid = t.id
WHERE uid = @uid;
END //
DELIMITER ;
DELIMITER //
DROP PROCEDURE IF EXISTS AddUserTag;
CREATE PROCEDURE AddUserTag(IN _sid VARCHAR(48), IN _tag VARCHAR(32))
SQL SECURITY DEFINER
BEGIN
INSERT INTO user_tags (uid, tid)
VALUES (AuthSIDToUID(_sid), GetTagID(_tag))
ON DUPLICATE KEY UPDATE uid = uid;
END //
DELIMITER ;
DELIMITER //
DROP PROCEDURE IF EXISTS DeleteUserTag;
CREATE PROCEDURE DeleteUserTag(IN _sid VARCHAR(48), IN _tag VARCHAR(32))
SQL SECURITY DEFINER
BEGIN
SET @uid = AuthSIDToUID(_sid);
SET @tid = FindTagID(_tag);
DELETE FROM user_tags WHERE uid = @uid AND tid = @tid;
END //
DELIMITER ;
-- Word Data
DELIMITER //
DROP PROCEDURE IF EXISTS SetWordNotes;
CREATE PROCEDURE SetWordNotes(
IN _sid VARCHAR(48),
IN _word VARCHAR(255),
IN _notes TEXT)
SQL SECURITY DEFINER
BEGIN
INSERT INTO word_data (uid, wid, notes)
VALUES (AuthSIDToUID(_sid), GetWordID(_word), _notes)
ON DUPLICATE KEY UPDATE notes = VALUES(notes);
END //
DELIMITER ;
DELIMITER //
DROP PROCEDURE IF EXISTS SetWordScore;
CREATE PROCEDURE SetWordScore(
IN _sid VARCHAR(48),
IN _word VARCHAR(255),
IN _score INT)
SQL SECURITY DEFINER
BEGIN
INSERT INTO word_data (uid, wid, score)
VALUES (AuthSIDToUID(_sid), GetWordID(_word), _score)
ON DUPLICATE KEY UPDATE score = VALUES(score);
END //
DELIMITER ;
DELIMITER //
DROP PROCEDURE IF EXISTS GetTags;
CREATE PROCEDURE GetTags(IN _sid VARCHAR(48))
SQL SECURITY DEFINER
BEGIN
SET @uid = AuthLookupSID(_sid);
SELECT COUNT(wt.tid) count, t.name, wt.uid FROM word_tags wt
JOIN tags t on t.id = wt.tid
WHERE wt.uid = 0 OR wt.uid = @uid
GROUP BY wt.tid ORDER BY count DESC;
END //
DELIMITER ;
DELIMITER //
DROP PROCEDURE IF EXISTS GetUserHistory;
CREATE PROCEDURE GetUserHistory(IN _sid VARCHAR(48))
SQL SECURITY DEFINER
BEGIN
SET @uid = AuthSIDToUID(_sid);
SELECT w.word, d.notes, d.score, DATE_FORMAT(h.ts, '%Y-%m-%dT%TZ') as `time`
FROM history h
LEFT JOIN words w ON w.id = h.wid
LEFT JOIN word_data d ON d.uid = @uid AND d.wid = h.wid
WHERE h.uid = @uid
ORDER BY h.ts DESC LIMIT 10000;
END //
DELIMITER ;
-- Auth
DELIMITER //
DROP PROCEDURE IF EXISTS AuthLogin;
CREATE PROCEDURE AuthLogin(
IN _sid VARCHAR(48),
IN _provider VARCHAR(16),
IN _provider_id VARCHAR(128),
IN _email VARCHAR(128),
IN _name VARCHAR(128),
IN _avatar VARCHAR(256))
SQL SECURITY DEFINER
BEGIN
SET @@session.time_zone = '+00:00';
IF ISNULL(_name) OR LENGTH(_name) = 0 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'User name cannot be empty';
END IF;
-- Create or update user
INSERT INTO users (provider, provider_id, email, name, avatar)
VALUES (_provider, _provider_id, _email, _name, _avatar)
ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id), last_used = NOW();
SET @uid = LAST_INSERT_ID();
-- Create or update session
INSERT INTO sessions (id, uid) VALUES (_sid, @uid)
ON DUPLICATE KEY UPDATE last_used = NOW();
-- Delete all old sessions
DELETE FROM sessions WHERE last_used < (NOW() - INTERVAL 4 DAY);
END //
DELIMITER ;
DELIMITER //
DROP PROCEDURE IF EXISTS AuthLogout;
CREATE PROCEDURE AuthLogout(IN _sid VARCHAR(48))
SQL SECURITY DEFINER
BEGIN
SET @@session.time_zone = '+00:00';
DELETE FROM sessions WHERE id = _sid;
END //
DELIMITER ;
DELIMITER //
DROP PROCEDURE IF EXISTS AuthSession;
CREATE PROCEDURE AuthSession(IN _sid VARCHAR(48))
SQL SECURITY DEFINER
BEGIN
SET @@session.time_zone = '+00:00';
-- Delete old sessions
SET @timeout = 2592000;
DELETE FROM sessions WHERE last_used + INTERVAL @timeout SECOND < NOW();
-- Get session, if it exists
SELECT u.id uid, u.email user, u.name, u.avatar,
DATE_FORMAT(s.created, '%Y-%m-%dT%TZ') created,
DATE_FORMAT(s.last_used, '%Y-%m-%dT%TZ') last_used
FROM sessions s
JOIN users u ON s.id = _sid AND s.uid = u.id;
-- Update session last_used
UPDATE sessions SET last_used = NOW() WHERE id = _sid;
END //
DELIMITER ;
DELIMITER //
DROP FUNCTION IF EXISTS AuthLookupSID;
CREATE FUNCTION AuthLookupSID(_sid VARCHAR(48))
RETURNS INT
READS SQL DATA
BEGIN
SET @uid = NULL;
SELECT uid INTO @uid FROM sessions WHERE id = _sid;
RETURN @uid;
END //
DELIMITER ;
DELIMITER //
DROP FUNCTION IF EXISTS AuthSIDToUID;
CREATE FUNCTION AuthSIDToUID(_sid VARCHAR(48))
RETURNS INT
READS SQL DATA
BEGIN
SET @uid = AuthLookupSID(_sid);
IF ISNULL(@uid) THEN
SIGNAL SQLSTATE '02000' SET MESSAGE_TEXT = 'Session not found.';
END IF;
RETURN @uid;
END //
DELIMITER ;