-
Notifications
You must be signed in to change notification settings - Fork 0
/
item_store.py
138 lines (119 loc) · 5.06 KB
/
item_store.py
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
#!/usr/bin/python
from item import Item
import sqlite3 as sqlite
db_name = 'la.db'
instance = None
def db():
global instance
if instance is None:
instance = ItemStore()
instance.connect_db(db_name)
return instance
class ItemStore(object):
def __init__(self):
self.con = None
def __del__(self):
if self.con:
# print('Closing SQL connection')
self.con.close()
def connect_db(self, db_name):
try:
self.con = sqlite.connect(db_name)
# Foreign keys are disabled by default, so we need to turn them on every time.
self.con.cursor().execute("PRAGMA foreign_keys=ON")
except sqlite.Error as e:
print("Error %s:" % e.args[0])
raise
def dump_db(self, dump_file):
""" dump_file is of type io.TextIOWrapper. """
for line in self.con.iterdump():
print(line)
dump_file.write('%s\n' % line)
return 'Database exported'
# The methods below assume the database is connected
def create_item(self, item):
cur = self.con.cursor()
cur.execute("INSERT INTO items (url, type) VALUES ('%s', '%s') ;" % (item.url, item.typ))
self.con.commit()
return cur.lastrowid
def rename_item(self, old_name, new_name):
cur = self.con.cursor()
cur.execute("UPDATE items set url = :new_url WHERE items.url = :old_url ;" ,
{'new_url': new_name, 'old_url': old_name})
self.con.commit()
return cur.rowcount
def delete_item(self, name):
cur = self.con.cursor()
cur.execute("DELETE from items where url = :name ;", {'name': name})
self.con.commit()
return cur.rowcount
# query = "with p as (select id from items where url = :purl), "
# "c as (select id from items where url = :curl ) select p.id, c.id from p, c ;"
def associate(self, parent_name, child_name):
insert_select = ("with p as (select id from items where url = :purl), "
"c as (select id from items where url = :curl ) "
"INSERT INTO associations (parent, child) select p.id, c.id from p, c ;")
cur = self.con.cursor()
cur.execute(insert_select, {'purl': parent_name, 'curl': child_name})
self.con.commit()
return 1
def all_associations(self):
cur = self.con.cursor()
cur.execute('SELECT parent, child FROM associations ;')
result = cur.fetchall()
return result
def select_all(self):
cur = self.con.cursor()
cur.execute('SELECT * FROM items ;')
rows = cur.fetchall()
result = dict()
for row in rows:
result[row[0]] = Item(row[0], row[2], row[1])
return result
def search(self, query):
cur = self.con.cursor()
# Get the associations.
query_descendents = (
"WITH RECURSIVE descendents(p, c, anc_url) AS ( "
" select parent, child, url from ASSOCIATIONS join items ON items.id = parent "
" where items.url IN (" + ", ".join(["?"] * len(query)) + " ) "
" UNION ALL "
" SELECT parent, child, anc_url "
" FROM ASSOCIATIONS join descendents ON parent = c ) ")
query_intersect = (" SELECT c as child from descendents as d"
" WHERE d.anc_url = ? ")
# query_pairs = query_descendents + " INTERSECT ".join([query_intersect] * len(query))
# cur.execute(query_pairs, query*2)
pairs_list = [] # cur.fetchall()
query_matches = " INTERSECT ".join([query_intersect] * len(query))
query_items = query_descendents + " , matched_ids as (" + query_matches + ") SELECT items.* FROM items JOIN matched_ids ON id = child ; "
item_dict = dict()
cur.execute(query_items, query * 2)
rows = cur.fetchall()
for row in rows:
item_dict[row[0]] = Item(row[0], row[2], row[1])
return item_dict, pairs_list
def initialize_db(db_instance):
con = db_instance.con
# con.execute("DROP TABLE items ;")
# con.execute("DROP TABLE associations ;")
con.execute("CREATE TABLE items (id INTEGER PRIMARY KEY AUTOINCREMENT, url VARCHAR UNIQUE, type VARCHAR) ;")
con.execute("CREATE TABLE associations ( "
"parent INTEGER REFERENCES items (id) ON DELETE CASCADE , "
"child INTEGER REFERENCES items (id) ON DELETE CASCADE, "
"PRIMARY KEY (parent, child) ) WITHOUT ROWID ; ")
cr_trig_no_cycles = ("CREATE TRIGGER nocycles BEFORE INSERT ON associations"
" BEGIN"
" WITH RECURSIVE anc(x) AS ("
" SELECT NEW.parent"
" UNION ALL"
" SELECT parent FROM associations, anc WHERE child = x"
" )"
" SELECT RAISE(ABORT, \"Item is already a descendent\")"
" FROM anc WHERE EXISTS ("
" SELECT 1 FROM anc WHERE x = NEW.child"
" );"
" END;")
con.execute(cr_trig_no_cycles)
return 'database initialized'
#with p as (select id from items where url = 'A'), c as (select id from items where url = 'ab' ) INSERT INTO associations (parent, child) select p.id, c.id from p, c ;