-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdatabase.py
More file actions
150 lines (137 loc) · 5.24 KB
/
Copy pathdatabase.py
File metadata and controls
150 lines (137 loc) · 5.24 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
from ast import literal_eval
class Database:
def __init__(self, db, logger):
self._db = db
self._logger = logger
self._run_migrations()
self._db.execute("VACUUM") # Because of the auto cleanup
def get_key_value(self, key: str):
with self._db as db:
cur = db.cursor()
cur.execute(
"SELECT integer, real, text, blob FROM key_values WHERE key=?", (key,)
)
row = cur.fetchone()
for value in row or []:
if value is not None:
return value
return None
def set_key_value(self, key: str, value):
columns = {
int: "integer",
float: "real",
str: "text",
bytes: "blob",
type(None): "integer",
}
column = columns[type(value)]
with self._db as db:
db.execute(
f"INSERT INTO key_values (key, {column}) VALUES (?, ?) "
f"ON CONFLICT(key) DO UPDATE "
f"SET integer=excluded.integer, real=excluded.real, "
f" text=excluded.text, blob=excluded.blob",
(key, value),
)
def add_parts_request(self, count: int, cache_hits: int, with_result: int):
with self._db as db:
db.execute(
"INSERT INTO parts_requests "
"(count, cache_hits, with_result) "
"VALUES (?, ?, ?)",
(count, cache_hits, with_result),
)
def add_parts_cache(self, provider: str, part: dict):
with self._db as db:
db.execute(
"INSERT INTO parts_cache "
"(mpn, manufacturer, provider, part) "
"VALUES (?, ?, ?, ?) "
"ON CONFLICT(mpn, manufacturer, provider) DO UPDATE SET "
" datetime = CURRENT_TIMESTAMP, "
" part = excluded.part",
(part["mpn"], part["manufacturer"], provider, str(part)),
)
def get_parts_cache(self, mpn, manufacturer, max_age):
with self._db as db:
cur = db.cursor()
cur.execute(
"SELECT part FROM parts_cache "
"WHERE mpn=? AND manufacturer=? "
"AND datetime >= datetime('now', ?)"
"ORDER BY datetime DESC",
(mpn, manufacturer, f"-{max_age} seconds"),
)
row = cur.fetchone()
return literal_eval(row[0]) if row is not None else None
def set_digikey_manufacturers(self, rows):
with self._db as db:
db.execute("DELETE FROM digikey_manufacturers")
db.executemany(
"INSERT INTO digikey_manufacturers (id, name, normalized) "
"VALUES (?, ?, ?)",
rows,
)
def get_digikey_manufacturer_ids(self, normalized_name, limit=3):
with self._db as db:
cur = db.cursor()
cur.execute(
"SELECT id FROM digikey_manufacturers "
"WHERE normalized=? OR normalized LIKE '%' || ? || '%' "
"ORDER BY "
" CASE WHEN normalized=? THEN 0 ELSE 1 END, "
" length(normalized) "
"LIMIT ?",
(normalized_name, normalized_name, normalized_name, limit),
)
return [row[0] for row in cur.fetchall()]
def _run_migrations(self):
with self._db as db:
version = db.execute("PRAGMA user_version").fetchone()[0]
while self._migrate_to(db, version + 1):
version += 1
def _migrate_to(self, db, version):
if hasattr(self, f"_migrate_to_v{version}"):
self._logger.info(f"Migrating database to version {version}...")
getattr(self, f"_migrate_to_v{version}")(db)
db.execute(f"PRAGMA user_version={version}")
return True
return False
def _migrate_to_v1(self, db):
db.execute("""
CREATE TABLE IF NOT EXISTS parts_requests (
id INTEGER PRIMARY KEY NOT NULL,
datetime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
count INTEGER NOT NULL,
cache_hits INTEGER NOT NULL,
with_result INTEGER NOT NULL
)
""")
db.execute("""
CREATE TABLE IF NOT EXISTS parts_cache (
id INTEGER PRIMARY KEY NOT NULL,
mpn TEXT NOT NULL,
manufacturer TEXT NOT NULL,
provider TEXT NOT NULL,
datetime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
part TEXT NOT NULL,
UNIQUE(mpn, manufacturer, provider)
)
""")
def _migrate_to_v2(self, db):
db.execute("""
CREATE TABLE IF NOT EXISTS key_values (
key TEXT PRIMARY KEY NOT NULL,
integer INTEGER,
real REAL,
text TEXT,
blob BLOB
)
""")
db.execute("""
CREATE TABLE IF NOT EXISTS digikey_manufacturers (
id INTEGER NOT NULL,
name TEXT NOT NULL,
normalized TEXT NOT NULL
)
""")