db_setup.py 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. from game import CURRENCY_NAME
  2. from util import debug
  3. replace = True and debug
  4. def setup(cursor):
  5. print('Database setup...')
  6. if replace:
  7. drop_database(cursor)
  8. tables(cursor)
  9. integrity_checks(cursor)
  10. if replace: # TODO also seed new databases
  11. seed(cursor)
  12. def drop_database(cursor):
  13. print(' - Dropping old tables...')
  14. cursor.execute("DROP TABLE IF EXISTS users")
  15. cursor.execute("DROP TABLE IF EXISTS ownables")
  16. cursor.execute("DROP TABLE IF EXISTS ownership")
  17. cursor.execute("DROP TABLE IF EXISTS sessions")
  18. cursor.execute("DROP TABLE IF EXISTS orders")
  19. cursor.execute("DROP TABLE IF EXISTS transactions")
  20. cursor.execute("DROP TABLE IF EXISTS keys")
  21. cursor.execute("DROP TABLE IF EXISTS news")
  22. cursor.execute("DROP TRIGGER IF EXISTS owned_amount_not_negative_after_insert")
  23. cursor.execute("DROP TRIGGER IF EXISTS owned_amount_not_negative_after_update")
  24. cursor.execute("DROP TRIGGER IF EXISTS order_limit_not_negative_after_insert")
  25. cursor.execute("DROP TRIGGER IF EXISTS order_limit_not_negative_after_update")
  26. cursor.execute("DROP TRIGGER IF EXISTS order_amount_positive_after_insert")
  27. cursor.execute("DROP TRIGGER IF EXISTS order_amount_positive_after_update")
  28. cursor.execute("DROP TRIGGER IF EXISTS not_more_executed_than_ordered_after_insert")
  29. cursor.execute("DROP TRIGGER IF EXISTS not_more_executed_than_ordered_after_update")
  30. cursor.execute("DROP TRIGGER IF EXISTS expiry_dt_in_future_after_insert")
  31. cursor.execute("DROP TRIGGER IF EXISTS expiry_dt_in_future_after_update")
  32. cursor.execute("DROP TRIGGER IF EXISTS order_amount_positive_after_update")
  33. def seed(cursor):
  34. print(' - Seeding initial data...')
  35. cursor.execute('''
  36. INSERT INTO ownables
  37. (name)
  38. VALUES (?)
  39. ''', (CURRENCY_NAME,))
  40. cursor.execute('''
  41. INSERT INTO users
  42. (username,password)
  43. VALUES ('bank','')
  44. ''')
  45. cursor.execute('''
  46. INSERT INTO ownership
  47. (user_id, ownable_id)
  48. VALUES ((SELECT rowid FROM users WHERE username = 'bank'),
  49. (SELECT rowid FROM ownables WHERE name = ?))
  50. ''', (CURRENCY_NAME,))
  51. def integrity_checks(cursor):
  52. print(' - Integrity checks...')
  53. cursor.execute('''
  54. CREATE TRIGGER IF NOT EXISTS owned_amount_not_negative_after_insert
  55. AFTER INSERT
  56. ON ownership
  57. WHEN NEW.amount < 0
  58. BEGIN
  59. SELECT RAISE(ROLLBACK, 'Can not own an amount less than 0.');
  60. END
  61. ''')
  62. cursor.execute('''
  63. CREATE TRIGGER IF NOT EXISTS owned_amount_not_negative_after_update
  64. AFTER UPDATE
  65. ON ownership
  66. WHEN NEW.amount < 0
  67. BEGIN
  68. SELECT RAISE(ROLLBACK, 'Can not own an amount less than 0.');
  69. END
  70. ''')
  71. cursor.execute('''
  72. CREATE TRIGGER IF NOT EXISTS amount_positive_after_insert
  73. AFTER INSERT
  74. ON transactions
  75. WHEN NEW.amount <= 0
  76. BEGIN
  77. SELECT RAISE(ROLLBACK, 'Can not perform empty transactions.');
  78. END
  79. ''')
  80. cursor.execute('''
  81. CREATE TRIGGER IF NOT EXISTS amount_positive_after_update
  82. AFTER UPDATE
  83. ON transactions
  84. WHEN NEW.amount <= 0
  85. BEGIN
  86. SELECT RAISE(ROLLBACK, 'Can not perform empty transactions.');
  87. END
  88. ''')
  89. cursor.execute('''
  90. CREATE TRIGGER IF NOT EXISTS order_limit_not_negative_after_insert
  91. AFTER INSERT
  92. ON orders
  93. WHEN NEW."limit" IS NOT NULL AND NEW."limit" < 0
  94. BEGIN
  95. SELECT RAISE(ROLLBACK, 'Can not set a limit less than 0.');
  96. END
  97. ''')
  98. cursor.execute('''
  99. CREATE TRIGGER IF NOT EXISTS order_limit_not_negative_after_update
  100. AFTER UPDATE
  101. ON orders
  102. WHEN NEW."limit" IS NOT NULL AND NEW."limit" < 0
  103. BEGIN
  104. SELECT RAISE(ROLLBACK, 'Can not set a limit less than 0.');
  105. END
  106. ''')
  107. cursor.execute('''
  108. CREATE TRIGGER IF NOT EXISTS order_amount_positive_after_insert
  109. AFTER INSERT
  110. ON orders
  111. WHEN NEW.ordered_amount <= 0 OR NEW.executed_amount < 0
  112. BEGIN
  113. SELECT RAISE(ROLLBACK, 'Can not order 0 or less.');
  114. END
  115. ''')
  116. cursor.execute('''
  117. CREATE TRIGGER IF NOT EXISTS order_amount_positive_after_update
  118. AFTER UPDATE
  119. ON orders
  120. WHEN NEW.ordered_amount <= 0 OR NEW.executed_amount < 0
  121. BEGIN
  122. SELECT RAISE(ROLLBACK, 'Can not order 0 or less.');
  123. END
  124. ''')
  125. cursor.execute('''
  126. CREATE TRIGGER IF NOT EXISTS not_more_executed_than_ordered_after_insert
  127. AFTER INSERT
  128. ON orders
  129. WHEN NEW.ordered_amount < NEW.executed_amount
  130. BEGIN
  131. SELECT RAISE(ROLLBACK, 'Can not execute more than ordered.');
  132. END
  133. ''')
  134. cursor.execute('''
  135. CREATE TRIGGER IF NOT EXISTS not_more_executed_than_ordered_after_update
  136. AFTER UPDATE
  137. ON orders
  138. WHEN NEW.ordered_amount < NEW.executed_amount
  139. BEGIN
  140. SELECT RAISE(ROLLBACK, 'Can not execute more than ordered.');
  141. END
  142. ''')
  143. cursor.execute('''
  144. CREATE TRIGGER IF NOT EXISTS expiry_dt_in_future_after_insert
  145. AFTER INSERT
  146. ON orders
  147. WHEN NEW.expiry_dt <= datetime('now')
  148. BEGIN
  149. SELECT RAISE(ROLLBACK, 'Order is already expired.');
  150. END
  151. ''')
  152. cursor.execute('''
  153. CREATE TRIGGER IF NOT EXISTS expiry_dt_in_future_after_update
  154. AFTER UPDATE
  155. ON orders
  156. WHEN NEW.expiry_dt <= datetime('now')
  157. BEGIN
  158. SELECT RAISE(ROLLBACK, 'Order is already expired.');
  159. END
  160. ''')
  161. cursor.execute('''
  162. CREATE TRIGGER IF NOT EXISTS stop_loss_requires_limit_after_insert
  163. AFTER INSERT
  164. ON orders
  165. WHEN NEW."limit" IS NULL AND NEW.stop_loss IS NOT NULL
  166. BEGIN
  167. SELECT RAISE(ROLLBACK, 'Can only set `stop_loss` `for limit orders.');
  168. END
  169. ''')
  170. cursor.execute('''
  171. CREATE TRIGGER IF NOT EXISTS stop_loss_requires_limit_after_update
  172. AFTER UPDATE
  173. ON orders
  174. WHEN NEW."limit" IS NULL AND NEW.stop_loss IS NOT NULL
  175. BEGIN
  176. SELECT RAISE(ROLLBACK, 'Can only set `stop_loss` `for limit orders.');
  177. END
  178. ''')
  179. def tables(cursor):
  180. print(' - Creating tables...')
  181. cursor.execute('''
  182. CREATE TABLE IF NOT EXISTS users(
  183. username VARCHAR(10) UNIQUE NOT NULL,
  184. password VARCHAR(200) NOT NULL)
  185. ''')
  186. cursor.execute('''
  187. CREATE TABLE IF NOT EXISTS ownables(
  188. name VARCHAR(10) UNIQUE NOT NULL)
  189. ''')
  190. cursor.execute('''
  191. CREATE TABLE IF NOT EXISTS ownership(
  192. user_id INTEGER NOT NULL,
  193. ownable_id INTEGER NOT NULL,
  194. amount CURRENCY NOT NULL DEFAULT 0,
  195. FOREIGN KEY (user_id) REFERENCES users(rowid),
  196. FOREIGN KEY (ownable_id) REFERENCES ownables(rowid),
  197. UNIQUE (user_id, ownable_id)
  198. )
  199. ''')
  200. cursor.execute('''
  201. CREATE TABLE IF NOT EXISTS sessions(
  202. user_id INTEGER NOT NULL,
  203. session_id STRING NOT NULL,
  204. FOREIGN KEY (user_id) REFERENCES users(rowid)
  205. )
  206. ''')
  207. cursor.execute('''
  208. CREATE TABLE IF NOT EXISTS orders(
  209. ownership_id INTEGER NOT NULL,
  210. buy BOOLEAN NOT NULL,
  211. "limit" CURRENCY,
  212. stop_loss BOOLEAN,
  213. ordered_amount CURRENCY NOT NULL,
  214. executed_amount CURRENCY DEFAULT 0 NOT NULL,
  215. expiry_dt DATETIME NOT NULL,
  216. FOREIGN KEY (ownership_id) REFERENCES ownership(rowid)
  217. )
  218. ''')
  219. cursor.execute('''
  220. CREATE TABLE IF NOT EXISTS transactions(
  221. dt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  222. price CURRENCY NOT NULL,
  223. ownable_id INTEGER NOT NULL,
  224. amount CURRENCY NOT NULL,
  225. FOREIGN KEY (ownable_id) REFERENCES ownable(rowid)
  226. )
  227. ''')
  228. cursor.execute('''
  229. CREATE TABLE IF NOT EXISTS keys(
  230. key STRING UNIQUE NOT NULL,
  231. used_by_user_id INTEGER,
  232. FOREIGN KEY (used_by_user_id) REFERENCES user(rowid)
  233. )
  234. ''')
  235. cursor.execute('''
  236. CREATE TABLE IF NOT EXISTS news(
  237. dt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  238. title VARCHAR(50) NOT NULL
  239. )
  240. ''')