aboutsummaryrefslogtreecommitdiff
path: root/src/database.nim
blob: 3cf1e405ca580882f95b996489617926aa7e1a92 (plain)
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
import std / [options, times]

import tiny_sqlite

import dbUtils

const migrations = [
  """
  CREATE TABLE schema_version (
    version INTEGER NOT NULL
  );
  CREATE TABLE url (
    id INTEGER PRIMARY KEY,
    token TEXT NOT NULL UNIQUE,
    title TEXT NOT NULL,
    url TEXT,
    created DATE,
    expires DATE
  );
  CREATE UNIQUE INDEX idx_url_token ON url(token);
  """,
  """
  CREATE TABLE url2 (
    id INTEGER PRIMARY KEY,
    token TEXT NOT NULL UNIQUE,
    title TEXT NOT NULL,
    url TEXT NOT NULL,
    created DATE NOT NULL,
    expires DATE NOT NULL
  );
  INSERT INTO url2(id, token, title, url, created, expires)
  SELECT id, token, title, url, created, expires FROM url;
  DROP TABLE url;
  ALTER TABLE url2 RENAME TO url;
  CREATE UNIQUE INDEX idx_url_token ON url(token);
  """
]
const latestVersion = migrations.len

proc Migrate*(db: DbConn): bool {.raises: [].} =
  var currentVersion: int
  try:
    currentVersion = db.value("SELECT version FROM schema_version;").get().fromDbValue(int)
  except SqliteError:
    discard
  if currentVersion != latestVersion:
    try:
      db.exec("BEGIN")
      for v in currentVersion..<latestVersion:
        db.execScript(migrations[v])
      db.exec("DELETE FROM schema_version;")
      db.exec("INSERT INTO schema_version (version) VALUES (?);", latestVersion)
      db.exec("COMMIT;")
    except:
      let msg = getCurrentExceptionMsg()
      echo msg
      try:
        db.exec("ROLLBACK")
      except SqliteError:
        discard
      return false
  return true

type ShortUrl* = object
  ID*: int
  Token*: string
  Title*: string
  Url*: string
  Created*: DateTime
  Expires*: DateTime

proc AddUrl*(db: DbConn, url: ShortUrl) {.raises: [SqliteError].} =
  let stmt = db.stmt("""
    INSERT INTO url(token, title, url, created, expires)
    VALUES (?, ?, ?, ?, ?);
  """)
  stmt.exec(url.Token, url.Title, url.Url, url.Created, $url.Expires)

proc GetUrl*(db: DbConn, token: string): ref ShortUrl {.raises: [SqliteError].} =
  let stmt = db.stmt("SELECT id, title, url, created, expires FROM url WHERE token = ?")
  for row in stmt.iterate(token):
    new(result)
    result.ID = row[0].fromDbValue(int)
    result.Token = token
    result.Title = row[1].fromDbValue(string)
    result.Url = row[2].fromDbValue(string)
    result.Created = row[3].fromDbValue(DateTime)
    result.Expires = row[4].fromDbValue(DateTime)

proc CleanExpired*(db: DbConn) {.raises: [].} =
  try:
    let stmt = db.stmt("DELETE FROM url WHERE expires < ?")
    stmt.exec(times.now())
  except:
    discard