PyCyphORM 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- PyCyphORM-0.1.3/PKG-INFO +54 -0
- PyCyphORM-0.1.3/PyCyphORM.egg-info/PKG-INFO +54 -0
- PyCyphORM-0.1.3/PyCyphORM.egg-info/SOURCES.txt +12 -0
- PyCyphORM-0.1.3/PyCyphORM.egg-info/dependency_links.txt +1 -0
- PyCyphORM-0.1.3/PyCyphORM.egg-info/entry_points.txt +2 -0
- PyCyphORM-0.1.3/PyCyphORM.egg-info/top_level.txt +1 -0
- PyCyphORM-0.1.3/README.md +45 -0
- PyCyphORM-0.1.3/setup.cfg +4 -0
- PyCyphORM-0.1.3/setup.py +27 -0
- PyCyphORM-0.1.3/src/PyCyphORM/__init__.py +3 -0
- PyCyphORM-0.1.3/src/PyCyphORM/cli.py +45 -0
- PyCyphORM-0.1.3/src/PyCyphORM/lib/__init__.py +2 -0
- PyCyphORM-0.1.3/src/PyCyphORM/lib/adapter.py +68 -0
- PyCyphORM-0.1.3/src/PyCyphORM/lib/orm.py +175 -0
PyCyphORM-0.1.3/PKG-INFO
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: PyCyphORM
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: A Minimalistic SQLite InMemory Encrypted ORM
|
|
5
|
+
Author: jafrmartins
|
|
6
|
+
Author-email: j.afr.martins@outlook.pt
|
|
7
|
+
Keywords: sqlite encrypted inmemory orm
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
|
|
10
|
+
# PyCyphOrm
|
|
11
|
+
|
|
12
|
+
A Minimalistic SQLite InMemory Encrypted ORM
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
### Command Line Interface
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
usage: PyCyphORM [-h] [-i INIT] [-d FILEPATH]
|
|
20
|
+
|
|
21
|
+
A Minimalistic SQLite InMemory Encrypted ORM
|
|
22
|
+
|
|
23
|
+
options:
|
|
24
|
+
-h, --help show this help message and exit
|
|
25
|
+
-i INIT, --init INIT Initialize Salt and Password for
|
|
26
|
+
Encrypted Database
|
|
27
|
+
-d FILEPATH, --decrypt FILEPATH
|
|
28
|
+
Descrypt SQLite Database
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Example
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
|
|
35
|
+
from PyCyphORM.lib import load_config, ORM
|
|
36
|
+
|
|
37
|
+
cnf = load_config(".pyorm")
|
|
38
|
+
orm = ORM.instance(".cache", cnf["PASSWORD"], cnf["SALT"], {
|
|
39
|
+
"Note": {
|
|
40
|
+
"id": "INTEGER PRIMARY KEY AUTOINCREMENT",
|
|
41
|
+
"title": "TEXT NOT NULL",
|
|
42
|
+
"description": "TEXT NOT NULL",
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
orm.model("Note").insert({
|
|
48
|
+
"title": "Your Title #1",
|
|
49
|
+
"description": "Your Descriptioj #2",
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
orm.save()
|
|
53
|
+
|
|
54
|
+
```
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: PyCyphORM
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: A Minimalistic SQLite InMemory Encrypted ORM
|
|
5
|
+
Author: jafrmartins
|
|
6
|
+
Author-email: j.afr.martins@outlook.pt
|
|
7
|
+
Keywords: sqlite encrypted inmemory orm
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
|
|
10
|
+
# PyCyphOrm
|
|
11
|
+
|
|
12
|
+
A Minimalistic SQLite InMemory Encrypted ORM
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
### Command Line Interface
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
usage: PyCyphORM [-h] [-i INIT] [-d FILEPATH]
|
|
20
|
+
|
|
21
|
+
A Minimalistic SQLite InMemory Encrypted ORM
|
|
22
|
+
|
|
23
|
+
options:
|
|
24
|
+
-h, --help show this help message and exit
|
|
25
|
+
-i INIT, --init INIT Initialize Salt and Password for
|
|
26
|
+
Encrypted Database
|
|
27
|
+
-d FILEPATH, --decrypt FILEPATH
|
|
28
|
+
Descrypt SQLite Database
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Example
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
|
|
35
|
+
from PyCyphORM.lib import load_config, ORM
|
|
36
|
+
|
|
37
|
+
cnf = load_config(".pyorm")
|
|
38
|
+
orm = ORM.instance(".cache", cnf["PASSWORD"], cnf["SALT"], {
|
|
39
|
+
"Note": {
|
|
40
|
+
"id": "INTEGER PRIMARY KEY AUTOINCREMENT",
|
|
41
|
+
"title": "TEXT NOT NULL",
|
|
42
|
+
"description": "TEXT NOT NULL",
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
orm.model("Note").insert({
|
|
48
|
+
"title": "Your Title #1",
|
|
49
|
+
"description": "Your Descriptioj #2",
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
orm.save()
|
|
53
|
+
|
|
54
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
PyCyphORM.egg-info/PKG-INFO
|
|
4
|
+
PyCyphORM.egg-info/SOURCES.txt
|
|
5
|
+
PyCyphORM.egg-info/dependency_links.txt
|
|
6
|
+
PyCyphORM.egg-info/entry_points.txt
|
|
7
|
+
PyCyphORM.egg-info/top_level.txt
|
|
8
|
+
src/PyCyphORM/__init__.py
|
|
9
|
+
src/PyCyphORM/cli.py
|
|
10
|
+
src/PyCyphORM/lib/__init__.py
|
|
11
|
+
src/PyCyphORM/lib/adapter.py
|
|
12
|
+
src/PyCyphORM/lib/orm.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
PyCyphORM
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# PyCyphOrm
|
|
2
|
+
|
|
3
|
+
A Minimalistic SQLite InMemory Encrypted ORM
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
### Command Line Interface
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
usage: PyCyphORM [-h] [-i INIT] [-d FILEPATH]
|
|
11
|
+
|
|
12
|
+
A Minimalistic SQLite InMemory Encrypted ORM
|
|
13
|
+
|
|
14
|
+
options:
|
|
15
|
+
-h, --help show this help message and exit
|
|
16
|
+
-i INIT, --init INIT Initialize Salt and Password for
|
|
17
|
+
Encrypted Database
|
|
18
|
+
-d FILEPATH, --decrypt FILEPATH
|
|
19
|
+
Descrypt SQLite Database
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Example
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
|
|
26
|
+
from PyCyphORM.lib import load_config, ORM
|
|
27
|
+
|
|
28
|
+
cnf = load_config(".pyorm")
|
|
29
|
+
orm = ORM.instance(".cache", cnf["PASSWORD"], cnf["SALT"], {
|
|
30
|
+
"Note": {
|
|
31
|
+
"id": "INTEGER PRIMARY KEY AUTOINCREMENT",
|
|
32
|
+
"title": "TEXT NOT NULL",
|
|
33
|
+
"description": "TEXT NOT NULL",
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
orm.model("Note").insert({
|
|
39
|
+
"title": "Your Title #1",
|
|
40
|
+
"description": "Your Descriptioj #2",
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
orm.save()
|
|
44
|
+
|
|
45
|
+
```
|
PyCyphORM-0.1.3/setup.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import setuptools
|
|
3
|
+
|
|
4
|
+
# pip install ./PyORM --upgrade -t /home/jam/.local/lib/python3.10/site-packages/PyORM
|
|
5
|
+
|
|
6
|
+
readme = open("%s%sREADME.md"%(os.path.dirname(__file__), os.path.sep)).read()
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
setuptools.setup(
|
|
10
|
+
name='PyCyphORM',
|
|
11
|
+
version='0.1.3',
|
|
12
|
+
author='jafrmartins',
|
|
13
|
+
keywords='sqlite encrypted inmemory orm',
|
|
14
|
+
author_email='j.afr.martins@outlook.pt',
|
|
15
|
+
description='A Minimalistic SQLite InMemory Encrypted ORM',
|
|
16
|
+
packages=setuptools.find_packages('src'),
|
|
17
|
+
install_requires=[],
|
|
18
|
+
package_dir={'PyCyphORM': 'src/PyCyphORM', },
|
|
19
|
+
entry_points={
|
|
20
|
+
'console_scripts': [
|
|
21
|
+
'pycyphorm=cli:cli',
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
include_package_data=True,
|
|
25
|
+
long_description=readme,
|
|
26
|
+
long_description_content_type='text/markdown'
|
|
27
|
+
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/bin/env python3
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
|
|
5
|
+
from os import urandom, path
|
|
6
|
+
from base64 import b16encode
|
|
7
|
+
import random
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
|
|
11
|
+
def random_password():
|
|
12
|
+
password = ""
|
|
13
|
+
characters = "abcdefghijklmnopqrstuvxyz0123456789~/|#$%&()"
|
|
14
|
+
for index in range(12):
|
|
15
|
+
password = password + random.choice(characters)
|
|
16
|
+
return password
|
|
17
|
+
|
|
18
|
+
parser = argparse.ArgumentParser(
|
|
19
|
+
prog = 'PyCyphORM',
|
|
20
|
+
description = 'A Minimalistic SQLite InMemory Encrypted ORM',
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
parser.add_argument("-i", "--init", metavar="INIT", help="Initialize Salt and Password for Encrypted Database")
|
|
24
|
+
parser.add_argument("-d", "--decrypt", metavar="FILEPATH", help="Descrypt SQLite Database")
|
|
25
|
+
#parser.add_argument("output", metavar="DEST", default=".", help="Destination Folder")
|
|
26
|
+
|
|
27
|
+
def cli():
|
|
28
|
+
args = vars(parser.parse_args())
|
|
29
|
+
if args["init"]:
|
|
30
|
+
with open(".pyorm", "w") as f:
|
|
31
|
+
f.write(json.dumps({
|
|
32
|
+
"SALT": b16encode(urandom(16)).decode("utf-8"),
|
|
33
|
+
"PASSWORD": b16encode(bytes(random_password(), "utf-8")).decode("utf-8")
|
|
34
|
+
}))
|
|
35
|
+
|
|
36
|
+
elif args['decrypt']:
|
|
37
|
+
if path.exists(path.abspath(args['decrypt'])):
|
|
38
|
+
|
|
39
|
+
from .lib.adapter import decrypt_cdb, load_config
|
|
40
|
+
|
|
41
|
+
cnf = load_config(".pyorm")
|
|
42
|
+
decrypt_cdb(path.abspath(args['decrypt']), cnf["PASSWORD"], cnf["SALT"])
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
if __name__ == "__main__": cli()
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from cryptography.fernet import Fernet
|
|
2
|
+
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
|
3
|
+
from cryptography.hazmat.primitives import hashes
|
|
4
|
+
from cryptography.hazmat.backends import default_backend
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
import sqlite3
|
|
8
|
+
import gzip
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
from base64 import b16decode, urlsafe_b64encode
|
|
12
|
+
|
|
13
|
+
def load_config(filepath):
|
|
14
|
+
config = None
|
|
15
|
+
with open(filepath, "rb") as f:
|
|
16
|
+
config = json.loads(f.read())
|
|
17
|
+
for key in config:
|
|
18
|
+
if isinstance(config[key], str):
|
|
19
|
+
config[key] = b16decode(config[key])
|
|
20
|
+
return config
|
|
21
|
+
|
|
22
|
+
def key_creation(password, salt):
|
|
23
|
+
kdf=PBKDF2HMAC(algorithm = hashes.SHA256(), salt=salt, iterations=1024, length=32, backend=default_backend())
|
|
24
|
+
key=Fernet(urlsafe_b64encode(kdf.derive(password)))
|
|
25
|
+
return key
|
|
26
|
+
|
|
27
|
+
def encryption(b, password, salt):
|
|
28
|
+
f=key_creation(password, salt)
|
|
29
|
+
safe=f.encrypt(b)
|
|
30
|
+
return safe
|
|
31
|
+
|
|
32
|
+
def decryption(safe, password, salt):
|
|
33
|
+
f=key_creation(password, salt)
|
|
34
|
+
b=f.decrypt(safe)
|
|
35
|
+
return b
|
|
36
|
+
|
|
37
|
+
def open_cdb(filename, password, salt):
|
|
38
|
+
if not os.path.exists(filename):
|
|
39
|
+
con = sqlite3.connect(':memory:')
|
|
40
|
+
return con
|
|
41
|
+
f=gzip.open(filename,'rb')
|
|
42
|
+
safe=f.read()
|
|
43
|
+
f.close()
|
|
44
|
+
content=decryption(safe,password,salt)
|
|
45
|
+
content=content.decode('utf-8')
|
|
46
|
+
con=sqlite3.connect(':memory:')
|
|
47
|
+
con.executescript(content)
|
|
48
|
+
return con
|
|
49
|
+
|
|
50
|
+
def decrypt_cdb(filename, password, salt):
|
|
51
|
+
f=gzip.open(filename,'rb')
|
|
52
|
+
safe=f.read()
|
|
53
|
+
f.close()
|
|
54
|
+
content=decryption(safe,password,salt)
|
|
55
|
+
fp=gzip.open(filename+".decoded.db",'wb')
|
|
56
|
+
fp.write(content)
|
|
57
|
+
fp.close()
|
|
58
|
+
|
|
59
|
+
def save_cdb(con, filename, password, salt):
|
|
60
|
+
fp=gzip.open(filename,'wb')
|
|
61
|
+
b=b''
|
|
62
|
+
for line in con.iterdump():
|
|
63
|
+
b+=bytes('%s\n','utf8') % bytes(line,'utf8')
|
|
64
|
+
b=encryption(b,password, salt)
|
|
65
|
+
fp.write(b)
|
|
66
|
+
fp.close()
|
|
67
|
+
|
|
68
|
+
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
from .adapter import open_cdb, save_cdb
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
class QueryBuilder:
|
|
5
|
+
|
|
6
|
+
@staticmethod
|
|
7
|
+
def __where__(clause):
|
|
8
|
+
where = []
|
|
9
|
+
for k in clause:
|
|
10
|
+
if clause[k] == None:
|
|
11
|
+
where.append("%s IS NULL" % (k))
|
|
12
|
+
else:
|
|
13
|
+
where.append("%s = \"%s\"" % (k, clause[k]))
|
|
14
|
+
return ",".join(where)
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def __set__(clause):
|
|
18
|
+
st = []
|
|
19
|
+
for k in clause:
|
|
20
|
+
if clause[k] == None:
|
|
21
|
+
st.append("%s = NULL" % (k))
|
|
22
|
+
else:
|
|
23
|
+
st.append("%s = \"%s\"" % (k, clause[k]))
|
|
24
|
+
return ",".join(st)
|
|
25
|
+
|
|
26
|
+
@staticmethod
|
|
27
|
+
def __insert__(table, data):
|
|
28
|
+
if isinstance(data, dict):
|
|
29
|
+
columns = []
|
|
30
|
+
values = []
|
|
31
|
+
for column in data:
|
|
32
|
+
columns.append(column)
|
|
33
|
+
values.append("\"%s\"" % data[column])
|
|
34
|
+
sql = "INSERT INTO %s (%s) VALUES (%s)" % (table, ",".join(columns), ",".join(values))
|
|
35
|
+
else:
|
|
36
|
+
count = 0
|
|
37
|
+
columns = []
|
|
38
|
+
bulk = []
|
|
39
|
+
for row in data:
|
|
40
|
+
values = []
|
|
41
|
+
for column in row:
|
|
42
|
+
if count == 0:
|
|
43
|
+
columns.append(column)
|
|
44
|
+
values.append("\"%s\"" % data[column])
|
|
45
|
+
count += 1
|
|
46
|
+
bulk.append("(%s)" % (",".join(values)))
|
|
47
|
+
sql = "INSERT INTO %s (%s) VALUES %s" % (table, ",".join(columns), ",".join(bulk))
|
|
48
|
+
return sql
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def __create_table__(table, schema):
|
|
52
|
+
definition = []
|
|
53
|
+
for column in schema:
|
|
54
|
+
definition.append("%s %s" % (column, schema[column]))
|
|
55
|
+
sql = "CREATE TABLE %s (%s)" % (table, ",".join(definition))
|
|
56
|
+
return sql
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
def __drop_table__(table):
|
|
60
|
+
sql = "DROP TABLE %s" % (table)
|
|
61
|
+
return sql
|
|
62
|
+
|
|
63
|
+
def __update__(self, table, data, where):
|
|
64
|
+
sql = "UPDATE %s SET %s" % (table, self.__set__(data))
|
|
65
|
+
if isinstance(where, dict):
|
|
66
|
+
sql += " WHERE %s" % self.__where__(where)
|
|
67
|
+
return sql
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def __select__(self, table, fields, where=None, orderby=None):
|
|
71
|
+
sql = "SELECT %s FROM %s" % (",".join(fields), table)
|
|
72
|
+
if isinstance(where, dict):
|
|
73
|
+
sql += " WHERE %s" % self.__where__(where)
|
|
74
|
+
if isinstance(orderby, str):
|
|
75
|
+
sql += " ORDER BY %s" % (orderby)
|
|
76
|
+
return sql
|
|
77
|
+
|
|
78
|
+
def __delete__(self, table, where):
|
|
79
|
+
sql = "DELETE FROM %s WHERE %s" % (table, self.__where__(where))
|
|
80
|
+
return sql
|
|
81
|
+
|
|
82
|
+
class Model(QueryBuilder):
|
|
83
|
+
|
|
84
|
+
def __init__(self, conn, table, schema):
|
|
85
|
+
self.conn = conn
|
|
86
|
+
self.table = table
|
|
87
|
+
self.schema = schema
|
|
88
|
+
|
|
89
|
+
def down(self):
|
|
90
|
+
sql = self.__drop_table__(self.table)
|
|
91
|
+
cur = self.conn.cursor()
|
|
92
|
+
cur.execute(sql)
|
|
93
|
+
self.conn.commit()
|
|
94
|
+
return cur.rowcount
|
|
95
|
+
|
|
96
|
+
def up(self):
|
|
97
|
+
sql = self.__create_table__(self.table, self.schema)
|
|
98
|
+
cur = self.conn.cursor()
|
|
99
|
+
cur.execute(sql)
|
|
100
|
+
self.conn.commit()
|
|
101
|
+
return cur.rowcount
|
|
102
|
+
|
|
103
|
+
def insert(self, data):
|
|
104
|
+
sql = self.__insert__(self.table, data)
|
|
105
|
+
cur = self.conn.cursor()
|
|
106
|
+
cur.execute(sql)
|
|
107
|
+
self.conn.commit()
|
|
108
|
+
return cur.lastrowid
|
|
109
|
+
|
|
110
|
+
def update(self, where, data):
|
|
111
|
+
sql = self.__update__(self.table, data, where)
|
|
112
|
+
cur = self.conn.cursor()
|
|
113
|
+
cur.execute(sql)
|
|
114
|
+
self.conn.commit()
|
|
115
|
+
return cur.rowcount
|
|
116
|
+
|
|
117
|
+
def delete(self, where):
|
|
118
|
+
sql = self.__delete__(self.table, where)
|
|
119
|
+
cur = self.conn.cursor()
|
|
120
|
+
cur.execute(sql)
|
|
121
|
+
self.conn.commit()
|
|
122
|
+
return cur.rowcount
|
|
123
|
+
|
|
124
|
+
def find(self, where=None):
|
|
125
|
+
sql = self.__select__(self.table, ["*"], where)
|
|
126
|
+
cur = self.conn.cursor()
|
|
127
|
+
cur.execute(sql)
|
|
128
|
+
rows = cur.fetchall()
|
|
129
|
+
return rows
|
|
130
|
+
|
|
131
|
+
def first(self, where):
|
|
132
|
+
sql = self.__select__(self.table, ["*"], where)
|
|
133
|
+
cur = self.conn.cursor()
|
|
134
|
+
cur.execute(sql)
|
|
135
|
+
row = cur.fetchone()
|
|
136
|
+
return row
|
|
137
|
+
|
|
138
|
+
class ORM:
|
|
139
|
+
|
|
140
|
+
__models__ = {}
|
|
141
|
+
__instance__ = None
|
|
142
|
+
|
|
143
|
+
@staticmethod
|
|
144
|
+
def instance(filename, password, salt, schema):
|
|
145
|
+
if ORM.__instance__ == None:
|
|
146
|
+
ORM.__instance__ = ORM(filename, password, salt, schema)
|
|
147
|
+
return ORM.__instance__
|
|
148
|
+
|
|
149
|
+
def __init__(self, filename, password, salt, schema):
|
|
150
|
+
|
|
151
|
+
self.filename = filename
|
|
152
|
+
self.password = password
|
|
153
|
+
self.salt = salt
|
|
154
|
+
self.__instance__ = self
|
|
155
|
+
|
|
156
|
+
install = False
|
|
157
|
+
if os.path.exists(filename) == False:
|
|
158
|
+
install = True
|
|
159
|
+
|
|
160
|
+
self.conn = open_cdb(self.filename, self.password, self.salt)
|
|
161
|
+
|
|
162
|
+
for table in schema:
|
|
163
|
+
self.__models__[table] = Model(self.conn, table, schema[table])
|
|
164
|
+
if install:
|
|
165
|
+
self.__models__[table].up()
|
|
166
|
+
if install:
|
|
167
|
+
save_cdb(self.conn, self.filename, self.password, self.salt)
|
|
168
|
+
|
|
169
|
+
def model(self, name) -> Model|None:
|
|
170
|
+
if name in self.__models__:
|
|
171
|
+
return self.__models__[name]
|
|
172
|
+
return None
|
|
173
|
+
|
|
174
|
+
def save(self):
|
|
175
|
+
save_cdb(self.conn, self.filename, self.password, self.salt)
|