embedize 1.0.2__py3-none-any.whl
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.
- embedize/__init__.py +4 -0
- embedize/dbs.py +231 -0
- embedize/dcore.py +622 -0
- embedize-1.0.2.dist-info/METADATA +23 -0
- embedize-1.0.2.dist-info/RECORD +8 -0
- embedize-1.0.2.dist-info/WHEEL +5 -0
- embedize-1.0.2.dist-info/licenses/LICENSE +21 -0
- embedize-1.0.2.dist-info/top_level.txt +1 -0
embedize/__init__.py
ADDED
embedize/dbs.py
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
def full_year (column, yyyy):
|
|
2
|
+
return f"(CAST(STRFTIME('%Y', {column}) AS INT) = CAST({yyyy} AS INT))"
|
|
3
|
+
|
|
4
|
+
def year_month (column, yyyy, mm):
|
|
5
|
+
return f"(CAST(STRFTIME('%Y', {column}) AS INT) = CAST({yyyy} AS INT) AND CAST(STRFTIME('%m', {column}) AS INT) = CAST({mm} AS INT))"
|
|
6
|
+
|
|
7
|
+
def date_between (column, dd1, dd2):
|
|
8
|
+
return f'(DATE({column}) BETWEEN DATE({dd1}) AND DATE({dd2}))'
|
|
9
|
+
|
|
10
|
+
def moderators_of_system ():
|
|
11
|
+
return f'(SELECT id FROM users WHERE zone=0)'
|
|
12
|
+
|
|
13
|
+
def admins_of_system ():
|
|
14
|
+
return f'(SELECT id FROM users WHERE zone=0 AND zadmin=1)'
|
|
15
|
+
|
|
16
|
+
def items_of_sub (sub_placeholder):
|
|
17
|
+
return f'(SELECT id FROM items WHERE sub={sub_placeholder})'
|
|
18
|
+
|
|
19
|
+
def subs_of_account (account_placeholder):
|
|
20
|
+
return f'(SELECT id FROM subs WHERE account={account_placeholder})'
|
|
21
|
+
|
|
22
|
+
def column_setting (column, cplaceholder, placeholder):
|
|
23
|
+
return f"{column} = CASE WHEN {cplaceholder} != '' THEN {placeholder} ELSE {column} END"
|
|
24
|
+
|
|
25
|
+
def close_items_listing (limit, offset):
|
|
26
|
+
return f'ORDER BY CAST(subs.account AS VARCHAR), subs.code, items.head LIMIT {limit} OFFSET {offset}'
|
|
27
|
+
|
|
28
|
+
def close_subs_listing (limit, offset):
|
|
29
|
+
return f'ORDER BY CAST(subs.account AS VARCHAR), subs.code LIMIT {limit} OFFSET {offset}'
|
|
30
|
+
|
|
31
|
+
def accounts_of_code_like (code_placeholder):
|
|
32
|
+
return f"(SELECT id FROM accounts WHERE code LIKE '%'||{code_placeholder}||'%')"
|
|
33
|
+
|
|
34
|
+
def check_sub_identify (id_placeholder, account_placeholder, code_placeholder):
|
|
35
|
+
return f'(id={id_placeholder} OR (account={account_placeholder} AND code=UPPER(TRIM({code_placeholder}))))'
|
|
36
|
+
|
|
37
|
+
def check_sub_acc_like (placeholder):
|
|
38
|
+
return f"CAST(subs.account AS VARCHAR) LIKE '%'||{placeholder}||'%'"
|
|
39
|
+
|
|
40
|
+
def check_uid_identify (id_placeholder, uuid_placeholder):
|
|
41
|
+
return f'(id={id_placeholder} OR uuid={uuid_placeholder})'
|
|
42
|
+
|
|
43
|
+
def check_uid_identifies (ids_placeholder, uuids_placeholder):
|
|
44
|
+
return f'(id IN ({ids_placeholder}) OR uuid IN ({uuids_placeholder}))'
|
|
45
|
+
|
|
46
|
+
def check_item_uid_identify (id_placeholder, uuid_placeholder):
|
|
47
|
+
return f'(items.id={id_placeholder} OR items.uuid={uuid_placeholder})'
|
|
48
|
+
|
|
49
|
+
def check_item_uid_identifies (ids_placeholder, uuids_placeholder):
|
|
50
|
+
return f'(items.id IN ({ids_placeholder}) OR items.uuid IN ({uuids_placeholder}))'
|
|
51
|
+
|
|
52
|
+
def role_exists (id_placeholder):
|
|
53
|
+
return f'EXISTS (SELECT 1 FROM roles WHERE id={id_placeholder})'
|
|
54
|
+
|
|
55
|
+
def specrole_exists (spec_placeholder, role_placeholder):
|
|
56
|
+
return f'EXISTS (SELECT 1 FROM specroles WHERE spec={spec_placeholder} AND role={role_placeholder})'
|
|
57
|
+
|
|
58
|
+
def userrole_exists (user_placeholder, role_placeholder):
|
|
59
|
+
return f'EXISTS (SELECT 1 FROM userroles WHERE user={user_placeholder} AND role={role_placeholder})'
|
|
60
|
+
|
|
61
|
+
def spec_exists (id_placeholder):
|
|
62
|
+
return f'EXISTS (SELECT 1 FROM specs WHERE id={id_placeholder})'
|
|
63
|
+
|
|
64
|
+
def userspec_exists (user_placeholder, spec_placeholder):
|
|
65
|
+
return f'EXISTS (SELECT 1 FROM userspecs WHERE user={user_placeholder} AND spec={spec_placeholder})'
|
|
66
|
+
|
|
67
|
+
def group_exists (id_placeholder):
|
|
68
|
+
return f'EXISTS (SELECT 1 FROM groups WHERE id={id_placeholder})'
|
|
69
|
+
|
|
70
|
+
group_id_exists = group_exists
|
|
71
|
+
|
|
72
|
+
def root_exists (id_placeholder, code_placeholder):
|
|
73
|
+
return f'EXISTS (SELECT 1 FROM roots WHERE id={id_placeholder} OR code=UPPER(TRIM({code_placeholder})))'
|
|
74
|
+
|
|
75
|
+
def root_id_exists (id_placeholder):
|
|
76
|
+
return f'EXISTS (SELECT 1 FROM roots WHERE id={id_placeholder})'
|
|
77
|
+
|
|
78
|
+
def account_exists (id_placeholder, code_placeholder):
|
|
79
|
+
return f'EXISTS (SELECT 1 FROM accounts WHERE id={id_placeholder} OR code=UPPER(TRIM({code_placeholder})))'
|
|
80
|
+
|
|
81
|
+
def account_id_exists (id_placeholder):
|
|
82
|
+
return f'EXISTS (SELECT 1 FROM accounts WHERE id={id_placeholder})'
|
|
83
|
+
|
|
84
|
+
def sub_exists (code_placeholder, account_placeholder):
|
|
85
|
+
return f'EXISTS (SELECT 1 FROM subs, accounts WHERE subs.code=UPPER(TRIM({code_placeholder})) AND subs.account={account_placeholder} AND subs.account=accounts.id)'
|
|
86
|
+
|
|
87
|
+
def sub_id_exists (id_placeholder):
|
|
88
|
+
return f'EXISTS (SELECT 1 FROM subs WHERE id={id_placeholder})'
|
|
89
|
+
|
|
90
|
+
def zone_exists (id_placeholder, name_placeholder):
|
|
91
|
+
return f'EXISTS (SELECT 1 FROM zones WHERE id={id_placeholder} OR name=UPPER(TRIM({name_placeholder})))'
|
|
92
|
+
|
|
93
|
+
def zone_id_exists (id_placeholder):
|
|
94
|
+
return f'EXISTS (SELECT 1 FROM zones WHERE id={id_placeholder})'
|
|
95
|
+
|
|
96
|
+
def attach_user_exists (id_placeholder):
|
|
97
|
+
return f'EXISTS (SELECT 1 FROM admin.users WHERE id={id_placeholder})'
|
|
98
|
+
|
|
99
|
+
def attach_user_check (idname_placeholder):
|
|
100
|
+
return f'(SELECT id FROM admin.users WHERE {check_idname(idname_placeholder)})'
|
|
101
|
+
|
|
102
|
+
def user_name_exists (name_placeholder):
|
|
103
|
+
return f'EXISTS (SELECT 1 FROM users WHERE name=LOWER(TRIM({name_placeholder})))'
|
|
104
|
+
|
|
105
|
+
def user_id_exists (id_placeholder):
|
|
106
|
+
return f'EXISTS (SELECT 1 FROM users WHERE id={id_placeholder})'
|
|
107
|
+
|
|
108
|
+
def check_obj_active (active_placeholder):
|
|
109
|
+
return f'(obj.active = (CASE WHEN {active_placeholder} IN (0,1) THEN {active_placeholder} ELSE obj.active END))'
|
|
110
|
+
|
|
111
|
+
def check_obj_zone_name (name_placeholder):
|
|
112
|
+
return f'(obj.zone = (SELECT id FROM zones WHERE name=UPPER(TRIM({name_placeholder})) LIMIT 1))'
|
|
113
|
+
|
|
114
|
+
def check_obj_zoneidn (id_placeholder, name_placeholder):
|
|
115
|
+
return f'(obj.zone = (SELECT id FROM zones WHERE {check_zone_id_or_name(id_placeholder, name_placeholder)} LIMIT 1))'
|
|
116
|
+
|
|
117
|
+
def check_user_id_or_name (id_placeholder, name_placeholder):
|
|
118
|
+
return f'(id={id_placeholder} OR name=LOWER(TRIM({name_placeholder})))'
|
|
119
|
+
|
|
120
|
+
def check_strict_user_id_or_name (id_placeholder, name_placeholder):
|
|
121
|
+
return f'(users.id={id_placeholder} OR users.name=LOWER(TRIM({name_placeholder})))'
|
|
122
|
+
|
|
123
|
+
def check_strict_user_worktime (worktime_placeholder):
|
|
124
|
+
return f"(users.workend IS NULL OR DATE({worktime_placeholder}) BETWEEN IFNULL(DATE(users.workbegin), DATE('1900-01-01')) AND DATE(users.workend))"
|
|
125
|
+
|
|
126
|
+
def check_strict_user_working (worktime_placeholder):
|
|
127
|
+
return f'({check_strict_user_active()} AND {check_strict_user_worktime(worktime_placeholder)})'
|
|
128
|
+
|
|
129
|
+
def check_strict_user_active ():
|
|
130
|
+
return f'(users.active=1 AND users.zone IN (SELECT id FROM zones WHERE active=1))'
|
|
131
|
+
|
|
132
|
+
def check_zone_id_or_name (id_placeholder, name_placeholder):
|
|
133
|
+
return f'(id={id_placeholder} OR name=UPPER(TRIM({name_placeholder})))'
|
|
134
|
+
|
|
135
|
+
def set_user_note (cnote_placeholder, note_placeholder, modifier_placeholder):
|
|
136
|
+
return f"note = CASE WHEN {cnote_placeholder} != '' THEN (IFNULL(note,'') || '\n' || {note_placeholder} || ' [uid.' || IFNULL({modifier_placeholder},'N/A') || '] ' || DATETIME('now')) ELSE note END"
|
|
137
|
+
|
|
138
|
+
def set_user_modify (modifier_placeholder):
|
|
139
|
+
return f"modified=(DATETIME('now')), modifier={modifier_placeholder}"
|
|
140
|
+
|
|
141
|
+
set_modifier_value = set_user_modify
|
|
142
|
+
|
|
143
|
+
def check_user_id (id_placeholder, name_placeholder):
|
|
144
|
+
return f'((user={id_placeholder} OR users.name=LOWER(TRIM({name_placeholder}))) AND user=users.id)'
|
|
145
|
+
|
|
146
|
+
def check_user_in_specs (user_placeholder, name_placeholder):
|
|
147
|
+
return f'({check_user_id(user_placeholder, name_placeholder)} AND spec=specs.id)'
|
|
148
|
+
|
|
149
|
+
def check_user_in_roles (user_placeholder, name_placeholder):
|
|
150
|
+
return f'({check_user_id(user_placeholder, name_placeholder)} AND role=roles.id)'
|
|
151
|
+
|
|
152
|
+
def check_user_spec (user_placeholder, name_placeholder, spec_placeholder):
|
|
153
|
+
return f'({check_user_id(user_placeholder, name_placeholder)} AND spec={spec_placeholder})'
|
|
154
|
+
|
|
155
|
+
def check_user_role (user_placeholder, name_placeholder, role_placeholder):
|
|
156
|
+
return f'({check_user_id(user_placeholder, name_placeholder)} AND role={role_placeholder})'
|
|
157
|
+
|
|
158
|
+
def check_user_spec_in_specs (user_placeholder, name_placeholder, spec_placeholder):
|
|
159
|
+
return f'({check_user_id(user_placeholder, name_placeholder)} AND spec={spec_placeholder} AND spec=specs.id)'
|
|
160
|
+
|
|
161
|
+
def check_user_role_in_roles (user_placeholder, name_placeholder, role_placeholder):
|
|
162
|
+
return f'({check_user_id(user_placeholder, name_placeholder)} AND role={role_placeholder} AND role=roles.id)'
|
|
163
|
+
|
|
164
|
+
check_id_or_uuid = check_uid_identify
|
|
165
|
+
|
|
166
|
+
def check_id_or_name (id_placeholder, name_placeholder):
|
|
167
|
+
return f'(id={id_placeholder} OR LOWER(TRIM(name))=LOWER(TRIM({name_placeholder})))'
|
|
168
|
+
|
|
169
|
+
def check_iduuid (placeholder):
|
|
170
|
+
return f'(TRIM(CAST(id AS VARCHAR))=TRIM({placeholder}) OR LOWER(TRIM(uuid))=LOWER(TRIM({placeholder})))'
|
|
171
|
+
|
|
172
|
+
def check_idname (placeholder):
|
|
173
|
+
return f'(TRIM(CAST(id AS VARCHAR))=TRIM({placeholder}) OR LOWER(TRIM(name))=LOWER(TRIM({placeholder})))'
|
|
174
|
+
|
|
175
|
+
def check_strict_idname (placeholder):
|
|
176
|
+
return f'(TRIM(CAST(users.id AS VARCHAR))=TRIM({placeholder}) OR LOWER(TRIM(users.name))=LOWER(TRIM({placeholder})))'
|
|
177
|
+
|
|
178
|
+
def check_ones_admin (zone_placeholder, user_placeholder):
|
|
179
|
+
return f'(zadmin=1 AND zone IN ({zone_of_zoneuser(zone_placeholder,user_placeholder)}))'
|
|
180
|
+
|
|
181
|
+
def check_ones_admin_or_moderator (zone_placeholder, user_placeholder):
|
|
182
|
+
return f'(zone=0 OR {check_ones_admin(zone_placeholder,user_placeholder)})'
|
|
183
|
+
|
|
184
|
+
check_admin_or_moderator_of = check_ones_admin_or_moderator
|
|
185
|
+
|
|
186
|
+
check_admin_of = check_ones_admin
|
|
187
|
+
|
|
188
|
+
def zone_of_user (user_placeholder):
|
|
189
|
+
return f'(SELECT zone FROM users WHERE {check_idname(user_placeholder)})'
|
|
190
|
+
|
|
191
|
+
def zone_by_user (user_placeholder):
|
|
192
|
+
return f'(SELECT id FROM zones WHERE id IN {zone_of_user(user_placeholder)})'
|
|
193
|
+
|
|
194
|
+
def zone_by_idname (idn_placeholder):
|
|
195
|
+
return f'(SELECT id FROM zones WHERE id={idn_placeholder} OR name=UPPER(TRIM({idn_placeholder})) LIMIT 1)'
|
|
196
|
+
|
|
197
|
+
def zone_of_zoneuser (zone_placeholder, user_placeholder):
|
|
198
|
+
return f'(SELECT id FROM zones WHERE {check_idname(zone_placeholder)} OR id IN {zone_of_user(user_placeholder)})'
|
|
199
|
+
|
|
200
|
+
def zone_case_idname (zone_placeholder):
|
|
201
|
+
return f"(CASE WHEN {zone_placeholder} != '' THEN (SELECT id FROM zones WHERE {check_idname(zone_placeholder)}) ELSE zone END)"
|
|
202
|
+
|
|
203
|
+
def get_zoneidn_by_useridn (zone_placeholder, user_placeholder):
|
|
204
|
+
return f"(CASE WHEN {user_placeholder} != '' THEN {zone_by_user(user_placeholder)} ELSE {zone_case_idname(zone_placeholder)} END)"
|
|
205
|
+
|
|
206
|
+
def zone_case_system (zone_placeholder, zone='zone'):
|
|
207
|
+
return f"(CASE WHEN TRIM({zone_placeholder})='0' OR UPPER(TRIM({zone_placeholder}))='ADMIN' THEN {zone} ELSE (SELECT id FROM zones WHERE {check_idname(zone_placeholder)} LIMIT 1) END)"
|
|
208
|
+
|
|
209
|
+
def increase_id (table):
|
|
210
|
+
return f'(SELECT IFNULL(MAX(id),0)+1 FROM {table})'
|
|
211
|
+
|
|
212
|
+
def search_idname (table, placeholder, fields='*'):
|
|
213
|
+
return f"SELECT {fields} FROM {table} WHERE (CAST(id AS VARCHAR) LIKE '%'||{placeholder}||'%' OR name LIKE '%'||{placeholder}||'%')"
|
|
214
|
+
|
|
215
|
+
def limit_offset (limnum, setnum):
|
|
216
|
+
return f'{limit(limnum)} {offset(setnum)}'
|
|
217
|
+
|
|
218
|
+
def offset (num):
|
|
219
|
+
return f'\n OFFSET {num}'
|
|
220
|
+
|
|
221
|
+
def limit (num):
|
|
222
|
+
return f'\n LIMIT {num}'
|
|
223
|
+
|
|
224
|
+
def multi_holders (query, lst):
|
|
225
|
+
return query.replace('??', ','.join(['(?)' for x in lst]))
|
|
226
|
+
|
|
227
|
+
def uuid_value ():
|
|
228
|
+
return "lower(hex(randomblob(4)))||'-'||lower(hex(randomblob(2)))||'-4'||substr(lower(hex(randomblob(2))),2)||'-'||substr('89ab',abs(random())%4+1,1)||substr(lower(hex(randomblob(2))),2)||'-'||lower(hex(randomblob(6)))"
|
|
229
|
+
|
|
230
|
+
def empty_json ():
|
|
231
|
+
return '{}'
|
embedize/dcore.py
ADDED
|
@@ -0,0 +1,622 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
import sys
|
|
4
|
+
import json
|
|
5
|
+
import duckdb
|
|
6
|
+
import sqlite3
|
|
7
|
+
import inspect
|
|
8
|
+
from typing import Callable
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
|
|
11
|
+
DBENGINE = 'SQLite'
|
|
12
|
+
ADMINDB = 'db/admin.db'
|
|
13
|
+
DUCKDBENGINE = 'DUCK'
|
|
14
|
+
ADMINDUCKDB = 'db/dadmin.db'
|
|
15
|
+
|
|
16
|
+
ADMINDBNAME = 'admin'
|
|
17
|
+
ADMINZONENAME = 'ADMIN'
|
|
18
|
+
ADMINUSERNAME = 'admin'
|
|
19
|
+
ADMINZONE = 0
|
|
20
|
+
ADMINUSER = 1
|
|
21
|
+
DEFPASSWORD = '123456'
|
|
22
|
+
ENCODING = 'ISO-8859-1'
|
|
23
|
+
ENCODINGSIG = 'utf-8-sig'
|
|
24
|
+
PLACEHOLDER = r'\:\w+\b'
|
|
25
|
+
COLUUID = 'uuid'
|
|
26
|
+
ARRAY = 'array'
|
|
27
|
+
|
|
28
|
+
JOURPRAGMA = 'PRAGMA journal_mode=WAL'
|
|
29
|
+
FKEYPRAGMA = 'PRAGMA foreign_keys=1'
|
|
30
|
+
TEMPPRAGMA = 'PRAGMA temp_store=2'
|
|
31
|
+
|
|
32
|
+
## GLOBAL CONST
|
|
33
|
+
|
|
34
|
+
ERROR = 'error'
|
|
35
|
+
ACTION = 'action'
|
|
36
|
+
RESULT = 'result'
|
|
37
|
+
|
|
38
|
+
UNKNOWN = 'Unknown'
|
|
39
|
+
DBERROR = 'DatabaseError'
|
|
40
|
+
UNERROR = 'UnexpectedError'
|
|
41
|
+
|
|
42
|
+
BADZONEID = 'Zone ID not allowed'
|
|
43
|
+
ERRORINPUT = 'Invalid function parameters'
|
|
44
|
+
NOROWCOUNT = 'Input not verified, no updates were made'
|
|
45
|
+
|
|
46
|
+
NOENTRIES = 'A financial transaction must be recorded with at least 2 entries'
|
|
47
|
+
NOBALANCE = 'The total value of debits must equal the total value of credits'
|
|
48
|
+
|
|
49
|
+
## GLOBAL COLUMN
|
|
50
|
+
|
|
51
|
+
COL_ACCOUNT = 'account'
|
|
52
|
+
COL_ACTIVE = 'active'
|
|
53
|
+
COL_CODE = 'code'
|
|
54
|
+
COL_CREATED = 'created'
|
|
55
|
+
COL_CREATOR = 'creator'
|
|
56
|
+
COL_CREDIT = 'credit'
|
|
57
|
+
COL_DATED = 'dated'
|
|
58
|
+
COL_DEBIT = 'debit'
|
|
59
|
+
COL_GROUP = 'grup'
|
|
60
|
+
COL_ID = 'id'
|
|
61
|
+
COL_INFO = 'info'
|
|
62
|
+
COL_ITEM = 'item'
|
|
63
|
+
COL_MODIFIED = 'modified'
|
|
64
|
+
COL_MODIFIER = 'modifier'
|
|
65
|
+
COL_NAME = 'name'
|
|
66
|
+
COL_NOTE = 'note'
|
|
67
|
+
COL_REF = 'ref'
|
|
68
|
+
COL_ROLE = 'role'
|
|
69
|
+
COL_ROOT = 'root'
|
|
70
|
+
COL_SPEC = 'spec'
|
|
71
|
+
COL_SUB = 'sub'
|
|
72
|
+
COL_TX = 'tx'
|
|
73
|
+
COL_USER = 'user'
|
|
74
|
+
COL_UUID = 'uuid'
|
|
75
|
+
COL_WORKBEGIN = 'workbegin'
|
|
76
|
+
COL_WORKEND = 'workend'
|
|
77
|
+
COL_ZADM = 'zadmin'
|
|
78
|
+
COL_ZONE = 'zone'
|
|
79
|
+
|
|
80
|
+
COL_ZONEID = 'zoneid'
|
|
81
|
+
COL_ZONEIDN = 'zoneidn'
|
|
82
|
+
COL_CONUSER = 'conuser'
|
|
83
|
+
COL_USERIDN = 'useridn'
|
|
84
|
+
|
|
85
|
+
COL_PASS = 'hpwd'
|
|
86
|
+
COL_OPWD = 'oldpass'
|
|
87
|
+
COL_NPWD = 'newpass'
|
|
88
|
+
|
|
89
|
+
COL_ACCOUNTCODE = 'accountcode'
|
|
90
|
+
COL_WORKTIME = 'worktime'
|
|
91
|
+
|
|
92
|
+
COL_OFFSET = 'offset'
|
|
93
|
+
COL_LIMIT = 'limit'
|
|
94
|
+
|
|
95
|
+
QUERY_ZONEID = 'SELECT id FROM zones WHERE CAST(id AS VARCHAR)=TRIM(:zoneidn) OR name=UPPER(TRIM(:zoneidn)) LIMIT 1'
|
|
96
|
+
|
|
97
|
+
class Execute (BaseModel):
|
|
98
|
+
func: Callable=None
|
|
99
|
+
data: dict={'query':'','values':{},'retquery':None,'retvalues':{},'db_path':None,'many':False,'script':False,'aid':UNKNOWN,'engine':None,'connect':None,'pandas':False}
|
|
100
|
+
check: dict={'err_stat':None,'err_func':None,'err_message':''}
|
|
101
|
+
|
|
102
|
+
def set_engine (engine):
|
|
103
|
+
return setattr(sys.modules[__name__], 'sys_engine', engine)
|
|
104
|
+
|
|
105
|
+
def set_connect (connect):
|
|
106
|
+
return setattr(sys.modules[__name__], 'sys_connect', connect)
|
|
107
|
+
|
|
108
|
+
def say_engine ():
|
|
109
|
+
return print(sys_engine)
|
|
110
|
+
|
|
111
|
+
def say_connect ():
|
|
112
|
+
return print(sys_connect)
|
|
113
|
+
|
|
114
|
+
def is_select (query, check='select'):
|
|
115
|
+
return str(query).strip().lower().startswith(check)
|
|
116
|
+
|
|
117
|
+
def admindb (engine):
|
|
118
|
+
return ADMINDB if engine in [sqlite3, None] else (ADMINDUCKDB if engine in [duckdb] else None)
|
|
119
|
+
|
|
120
|
+
def dbprefix (engine, defval='x'):
|
|
121
|
+
return '' if engine in [sqlite3, None] else ('d' if engine in [duckdb] else defval)
|
|
122
|
+
|
|
123
|
+
def get_zonedb (zoneidn, engine):
|
|
124
|
+
return f"{dbprefix(engine)}{ADMINDBNAME if (zoneid:=get_zoneid(zoneidn, engine=engine))==ADMINZONE else (str(zoneid) if zoneid is not None else '')}"
|
|
125
|
+
|
|
126
|
+
def get_zoneid (zoneidn, engine=None):
|
|
127
|
+
return ADMINZONE if str(zoneidn).upper() in [ADMINZONENAME, str(ADMINZONE)] else check_admin(QUERY_ZONEID, {COL_ZONEIDN: str(zoneidn)}, engine=(engine or sys_engine))
|
|
128
|
+
|
|
129
|
+
def get_aid (layer=4):
|
|
130
|
+
return callup(layer)
|
|
131
|
+
|
|
132
|
+
def callup (layer=2):
|
|
133
|
+
return inspect.stack()[layer][3]
|
|
134
|
+
|
|
135
|
+
def kwarg (**kw):
|
|
136
|
+
return kw
|
|
137
|
+
|
|
138
|
+
def dict_item (modifier, active, cancel, id, uuid):
|
|
139
|
+
return locals()
|
|
140
|
+
|
|
141
|
+
def dicts_items (it):
|
|
142
|
+
return [dict_item(it.modifier, it.active, it.cancel, x, None) for x in it.ids] if it.ids else [dict_item(it.modifier, it.active, it.cancel, None, x) for x in it.uuids]
|
|
143
|
+
|
|
144
|
+
def select_value (query, vals={}, index=0, engine=None):
|
|
145
|
+
return check_admin(query, vals, index, engine=(engine or sys_engine))
|
|
146
|
+
|
|
147
|
+
def first_row (resultset, defrow=None):
|
|
148
|
+
return resultset_first_row(resultset) if not resultset_is_empty(resultset) else defrow
|
|
149
|
+
|
|
150
|
+
def reform_model (model):
|
|
151
|
+
return model if type(model) in [dict, list, tuple, str, int, float] else model.model_dump()
|
|
152
|
+
|
|
153
|
+
def regexp (pattern, text):
|
|
154
|
+
return 1 if re.search(pattern, text) else 0
|
|
155
|
+
|
|
156
|
+
## SQLITE vs DUCKDB
|
|
157
|
+
|
|
158
|
+
def sql_replace (text, pat, rep):
|
|
159
|
+
return re.sub(re.escape(pat), rep, text, flags=re.IGNORECASE)
|
|
160
|
+
|
|
161
|
+
def sql_date_replace (text):
|
|
162
|
+
return re.sub(r'DATE\((.*?)\)', r'CAST(\1 AS DATE)', text, flags=re.IGNORECASE)
|
|
163
|
+
|
|
164
|
+
def sql_uni_replace (text: str, replaces: dict={}) -> str:
|
|
165
|
+
for key, val in replaces.items(): text = sql_replace(text, key, val)
|
|
166
|
+
return text
|
|
167
|
+
|
|
168
|
+
def sql_duck_replace (text: str, replaces: dict={}) -> str:
|
|
169
|
+
return sql_date_replace(sql_uni_replace(text, replaces))
|
|
170
|
+
|
|
171
|
+
def check_valid_naming (column='name'):
|
|
172
|
+
return f"({column} NOT REGEXP '^[0-9]+$')"
|
|
173
|
+
|
|
174
|
+
def check_valid_naming2 (column='name'):
|
|
175
|
+
return f"(NOT REGEXP_MATCHES({column}, '^[0-9]+$'))"
|
|
176
|
+
|
|
177
|
+
def duck_replaces ():
|
|
178
|
+
return {
|
|
179
|
+
check_valid_naming(): check_valid_naming2(),
|
|
180
|
+
"DATETIME('now')": 'now()',
|
|
181
|
+
"DATE('now')": 'CAST(now() AS DATE)',
|
|
182
|
+
'AUTOINCREMENT': ''
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
## STORED FUNCTIONS
|
|
186
|
+
|
|
187
|
+
def json_extract (json_str, path):
|
|
188
|
+
try:
|
|
189
|
+
json_data = json.loads(json_str)
|
|
190
|
+
path = path.split('$.')[-1]
|
|
191
|
+
path_components = path.split('.')
|
|
192
|
+
value = json_data
|
|
193
|
+
for component in path_components:
|
|
194
|
+
value = value.get(component)
|
|
195
|
+
return value
|
|
196
|
+
except (json.JSONDecodeError, AttributeError, TypeError):
|
|
197
|
+
return None
|
|
198
|
+
|
|
199
|
+
def update_placeholders (query: str, engine=None, holdermark: str=':', holder: str=PLACEHOLDER) -> str:
|
|
200
|
+
engine = engine or sys_engine
|
|
201
|
+
if type(query) not in [str]: return None
|
|
202
|
+
if engine in [sqlite3, None]: return query
|
|
203
|
+
if engine in [duckdb]: query = sql_duck_replace(query, duck_replaces())
|
|
204
|
+
newmark = '$' if engine in [duckdb] else holdermark
|
|
205
|
+
subs = re.findall(holder, query)
|
|
206
|
+
items = iter(str(e) for e in subs)
|
|
207
|
+
newquery = re.sub(holder, lambda lm: f'{newmark}{next(items)[1:]}', query)
|
|
208
|
+
return newquery
|
|
209
|
+
|
|
210
|
+
def update_values (query: str, values: dict, engine=None, holder: str=PLACEHOLDER) -> dict:
|
|
211
|
+
engine = engine or sys_engine
|
|
212
|
+
if type(query) not in [str]: return None
|
|
213
|
+
if engine in [sqlite3, None]: return values
|
|
214
|
+
if type(values) not in [dict, list, tuple]: return values
|
|
215
|
+
def update(object):
|
|
216
|
+
if type(object) not in [dict]: return object
|
|
217
|
+
subs = list(set(re.findall(holder, query)))
|
|
218
|
+
subs = [sub[1:] for sub in subs]
|
|
219
|
+
return {key: value for key, value in object.items() if key in subs}
|
|
220
|
+
if type(values) in [list, tuple]:
|
|
221
|
+
newvalues = [update(value) for value in list(values)]
|
|
222
|
+
else:
|
|
223
|
+
newvalues = update(values)
|
|
224
|
+
return newvalues
|
|
225
|
+
|
|
226
|
+
def get_rowcount (cursor, engine=None):
|
|
227
|
+
engine = engine or sys_engine
|
|
228
|
+
try:
|
|
229
|
+
if engine in [duckdb]:
|
|
230
|
+
(rowcount,) = cursor.fetchone()
|
|
231
|
+
else:
|
|
232
|
+
rowcount = cursor.rowcount
|
|
233
|
+
except:
|
|
234
|
+
rowcount = cursor.rowcount
|
|
235
|
+
return rowcount
|
|
236
|
+
|
|
237
|
+
def attach (cursor, engine=None):
|
|
238
|
+
try:
|
|
239
|
+
cursor.execute(f"ATTACH DATABASE '{admindb(engine or sys_engine)}' AS admin")
|
|
240
|
+
except:
|
|
241
|
+
pass
|
|
242
|
+
|
|
243
|
+
def connect_duckdb (db_path: str):
|
|
244
|
+
conn = duckdb.connect(db_path)
|
|
245
|
+
return conn
|
|
246
|
+
|
|
247
|
+
def connect_sqlite (db_path: str):
|
|
248
|
+
return connect_db(db_path)
|
|
249
|
+
|
|
250
|
+
def connect_db (db_path: str):
|
|
251
|
+
conn = sqlite3.connect(db_path)
|
|
252
|
+
conn.create_function('json_extract', 2, json_extract)
|
|
253
|
+
conn.create_function('regexp_matches', 2, regexp)
|
|
254
|
+
conn.create_function('regexp', 2, regexp)
|
|
255
|
+
conn.execute(JOURPRAGMA)
|
|
256
|
+
conn.execute(TEMPPRAGMA)
|
|
257
|
+
conn.execute(FKEYPRAGMA)
|
|
258
|
+
return conn
|
|
259
|
+
|
|
260
|
+
set_engine(sqlite3)
|
|
261
|
+
|
|
262
|
+
set_connect(connect_sqlite)
|
|
263
|
+
|
|
264
|
+
def zonedb (zoneid: any, engine=None) -> str:
|
|
265
|
+
engine = engine or sys_engine
|
|
266
|
+
zoneid = get_zonedb(zoneid, engine=engine)
|
|
267
|
+
return None if zoneid is None else f'db/{zoneid}.db'
|
|
268
|
+
|
|
269
|
+
def getdb (zoneid: any, engine=None) -> str:
|
|
270
|
+
engine = engine or sys_engine
|
|
271
|
+
db = zonedb(zoneid, engine=engine)
|
|
272
|
+
if not db: raise(ValueError(f'DataError: no such database: {zoneid}'))
|
|
273
|
+
return db
|
|
274
|
+
|
|
275
|
+
def import_zone_database (zoneid: any, table: str, csvdata: any, engine=None) -> dict:
|
|
276
|
+
import io
|
|
277
|
+
import csv
|
|
278
|
+
conn = None
|
|
279
|
+
res = dict_result(aid=callup(1))
|
|
280
|
+
engine = engine or sys_engine
|
|
281
|
+
try:
|
|
282
|
+
if type(csvdata) is str:
|
|
283
|
+
with open(csvdata, 'r', encoding=ENCODINGSIG) as file:
|
|
284
|
+
reader = csv.reader(file)
|
|
285
|
+
headers = next(reader)
|
|
286
|
+
rows = [tuple(row) for row in reader]
|
|
287
|
+
elif type(csvdata) is dict:
|
|
288
|
+
reader = csv.reader(io.StringIO(csvdata.get('data')))
|
|
289
|
+
headers = next(reader)
|
|
290
|
+
rows = [tuple(row) for row in reader]
|
|
291
|
+
else:
|
|
292
|
+
res[ERROR] = f'ReadError: no valid data loaded'
|
|
293
|
+
return res
|
|
294
|
+
placeholders = ','.join(['?' for _ in headers])
|
|
295
|
+
query = f"INSERT INTO {table} ({','.join(headers)}) VALUES ({placeholders})"
|
|
296
|
+
conn = engine.connect(getdb(zoneid, engine=engine))
|
|
297
|
+
cursor = conn.cursor()
|
|
298
|
+
cursor.executemany(query, list(filter(None, rows)))
|
|
299
|
+
except Exception as e:
|
|
300
|
+
res[ERROR] = f'ActionError: {e}'
|
|
301
|
+
finally:
|
|
302
|
+
if conn:
|
|
303
|
+
conn.commit()
|
|
304
|
+
conn.close()
|
|
305
|
+
return res
|
|
306
|
+
|
|
307
|
+
def export_zone_database (zoneid: any, table: str, csv_path: str=None, idr: list=[], engine=None) -> dict:
|
|
308
|
+
import io
|
|
309
|
+
import csv
|
|
310
|
+
conn = None
|
|
311
|
+
res = dict_result(aid=callup(1))
|
|
312
|
+
where = '' if not idr else f'WHERE id BETWEEN ? AND ?'
|
|
313
|
+
query = f'SELECT * FROM {table} {where}'
|
|
314
|
+
engine = engine or sys_engine
|
|
315
|
+
try:
|
|
316
|
+
conn = engine.connect(getdb(zoneid, engine=engine))
|
|
317
|
+
cursor = conn.cursor()
|
|
318
|
+
cursor.execute(query, idr if where else [])
|
|
319
|
+
rows = cursor.fetchall()
|
|
320
|
+
headers = [description[0] for description in cursor.description]
|
|
321
|
+
def csvwrite(output, headers, rows):
|
|
322
|
+
writer = csv.writer(output)
|
|
323
|
+
writer.writerow(headers)
|
|
324
|
+
writer.writerows(rows)
|
|
325
|
+
if csv_path:
|
|
326
|
+
with open(csv_path, 'w', newline='', encoding=ENCODINGSIG) as output:
|
|
327
|
+
csvwrite(output, headers, rows)
|
|
328
|
+
res[RESULT] = [{'file': csv_path}]
|
|
329
|
+
else:
|
|
330
|
+
output = io.StringIO()
|
|
331
|
+
csvwrite(output, headers, rows)
|
|
332
|
+
res[RESULT] = [{'data': output.getvalue()}]
|
|
333
|
+
except Exception as e:
|
|
334
|
+
res[ERROR] = f'ActionError: {e}'
|
|
335
|
+
finally:
|
|
336
|
+
if conn:
|
|
337
|
+
conn.close()
|
|
338
|
+
return res
|
|
339
|
+
|
|
340
|
+
def export_database_tables (zoneid: any, engine=None) -> dict:
|
|
341
|
+
conn = None
|
|
342
|
+
res = dict_result(aid=callup(1))
|
|
343
|
+
engine = engine or sys_engine
|
|
344
|
+
if engine in [duckdb]:
|
|
345
|
+
query = "SELECT table_name FROM duckdb_tables"
|
|
346
|
+
elif engine in [sqlite3, None]:
|
|
347
|
+
query = "SELECT name FROM sqlite_master WHERE type='table'"
|
|
348
|
+
else:
|
|
349
|
+
query = ""
|
|
350
|
+
try:
|
|
351
|
+
conn = engine.connect(getdb(zoneid, engine=engine))
|
|
352
|
+
cursor = conn.cursor()
|
|
353
|
+
cursor.execute(query)
|
|
354
|
+
tables = cursor.fetchall()
|
|
355
|
+
tables = [table[0] for table in tables]
|
|
356
|
+
res[RESULT] = tables
|
|
357
|
+
except Exception as e:
|
|
358
|
+
res[ERROR] = f'ActionError: {e}'
|
|
359
|
+
finally:
|
|
360
|
+
if conn:
|
|
361
|
+
conn.close()
|
|
362
|
+
return res
|
|
363
|
+
|
|
364
|
+
def check_admin (query: str, values: dict={}, index=0, engine=None) -> dict:
|
|
365
|
+
engine = engine or sys_engine
|
|
366
|
+
conn = None
|
|
367
|
+
try:
|
|
368
|
+
conn = engine.connect(getdb(ADMINDBNAME, engine=engine))
|
|
369
|
+
cursor = conn.cursor()
|
|
370
|
+
cursor.execute(update_placeholders(query, engine), update_values(query, values, engine))
|
|
371
|
+
rows = cursor.fetchone()
|
|
372
|
+
return None if not rows else rows[index]
|
|
373
|
+
except Exception as e:
|
|
374
|
+
return None
|
|
375
|
+
finally:
|
|
376
|
+
if conn:
|
|
377
|
+
conn.close()
|
|
378
|
+
|
|
379
|
+
def out_pandas (conn, query: str, values: dict={}, simplelist: bool=False, dataindex: int=0):
|
|
380
|
+
import pandas as pd
|
|
381
|
+
df = pd.read_sql_query(query, conn, params=values)
|
|
382
|
+
if simplelist: return df.iloc[:,dataindex]
|
|
383
|
+
return df
|
|
384
|
+
|
|
385
|
+
## CORE FUNCTIONS
|
|
386
|
+
|
|
387
|
+
def execute_table_create_insert_update (db_path: str, query: str, values: dict={}, retquery: str=None, retvalues: dict={}, many: bool=False, script: bool=False, aid: str=UNKNOWN, engine=None, connect=None, pandas: bool=False) -> dict:
|
|
388
|
+
engine = engine or sys_engine
|
|
389
|
+
connect = connect or sys_connect
|
|
390
|
+
conn = None
|
|
391
|
+
try:
|
|
392
|
+
conn = connect(db_path)
|
|
393
|
+
cursor = conn.cursor()
|
|
394
|
+
attach(cursor, engine=engine)
|
|
395
|
+
if script and engine in [sqlite3, None]:
|
|
396
|
+
cursor.executescript(query)
|
|
397
|
+
else:
|
|
398
|
+
newquery = update_placeholders(query, engine)
|
|
399
|
+
newvalues = update_values(query, values, engine)
|
|
400
|
+
if many:
|
|
401
|
+
cursor.executemany(newquery, newvalues)
|
|
402
|
+
else:
|
|
403
|
+
cursor.execute(newquery, newvalues)
|
|
404
|
+
rowcount = get_rowcount(cursor, engine)
|
|
405
|
+
conn.commit()
|
|
406
|
+
if rowcount==0:
|
|
407
|
+
return error_database(NOROWCOUNT)
|
|
408
|
+
if retquery is None:
|
|
409
|
+
return dict_result(aid=aid)
|
|
410
|
+
elif not is_select(retquery):
|
|
411
|
+
return dict_result(err=ERRORINPUT, aid=aid)
|
|
412
|
+
else:
|
|
413
|
+
if pandas:
|
|
414
|
+
return dict_result(out_pandas(conn, update_placeholders(retquery, engine), update_values(retquery, retvalues, engine)), aid=aid)
|
|
415
|
+
else:
|
|
416
|
+
return fetch_table_as_list_of_dict(db_path, retquery, retvalues, aid=aid, engine=engine, connect=connect)
|
|
417
|
+
except engine.Error as e:
|
|
418
|
+
conn.rollback()
|
|
419
|
+
return error_database(e)
|
|
420
|
+
except Exception as e:
|
|
421
|
+
return error_unexpect(e)
|
|
422
|
+
finally:
|
|
423
|
+
if conn:
|
|
424
|
+
conn.close()
|
|
425
|
+
|
|
426
|
+
def fetch_table_as_list_of_dict (db_path: str, query: str, values: dict={}, retquery=None, retvalues=None, many: bool=False, script: bool=False, aid: str=UNKNOWN, engine=None, connect=None, pandas: bool=False) -> dict:
|
|
427
|
+
engine = engine or sys_engine
|
|
428
|
+
connect = connect or sys_connect
|
|
429
|
+
conn = None
|
|
430
|
+
try:
|
|
431
|
+
conn = connect(db_path)
|
|
432
|
+
cursor = conn.cursor()
|
|
433
|
+
attach(cursor, engine=engine)
|
|
434
|
+
newquery = update_placeholders(query, engine)
|
|
435
|
+
newvalues = update_values(query, values, engine)
|
|
436
|
+
if pandas:
|
|
437
|
+
return dict_result(out_pandas(conn, newquery, newvalues), aid=aid)
|
|
438
|
+
cursor.execute(newquery, newvalues)
|
|
439
|
+
rows = cursor.fetchall()
|
|
440
|
+
columns = [desc[0] for desc in cursor.description]
|
|
441
|
+
list_of_dicts = [dict(zip(columns, row)) for row in rows]
|
|
442
|
+
return dict_result(result=list_of_dicts, aid=aid)
|
|
443
|
+
except engine.Error as e:
|
|
444
|
+
return error_database(e)
|
|
445
|
+
except Exception as e:
|
|
446
|
+
return error_unexpect(e)
|
|
447
|
+
finally:
|
|
448
|
+
if conn:
|
|
449
|
+
conn.close()
|
|
450
|
+
|
|
451
|
+
def fetch_table_as_simple_list (db_path: str, query: str, values: dict={}, retquery=None, retvalues=None, many: bool=False, script: bool=False, aid: str=UNKNOWN, engine=None, connect=None, pandas: bool=False) -> dict:
|
|
452
|
+
engine = engine or sys_engine
|
|
453
|
+
connect = connect or sys_connect
|
|
454
|
+
conn = None
|
|
455
|
+
try:
|
|
456
|
+
conn = connect(db_path)
|
|
457
|
+
cursor = conn.cursor()
|
|
458
|
+
attach(cursor, engine=engine)
|
|
459
|
+
newquery = update_placeholders(query, engine)
|
|
460
|
+
newvalues = update_values(query, values, engine)
|
|
461
|
+
if pandas:
|
|
462
|
+
return dict_result(out_pandas(conn, newquery, newvalues, simplelist=True), aid=aid)
|
|
463
|
+
cursor.execute(newquery, newvalues)
|
|
464
|
+
rows = cursor.fetchall()
|
|
465
|
+
rows = [row[0] for row in rows]
|
|
466
|
+
return dict_result(result=rows, aid=aid)
|
|
467
|
+
except engine.Error as e:
|
|
468
|
+
return error_database(e)
|
|
469
|
+
except Exception as e:
|
|
470
|
+
return error_unexpect(e)
|
|
471
|
+
finally:
|
|
472
|
+
if conn:
|
|
473
|
+
conn.close()
|
|
474
|
+
|
|
475
|
+
def resultset_first_row (result: dict) -> dict:
|
|
476
|
+
try:
|
|
477
|
+
row = result[RESULT][0]
|
|
478
|
+
if type(row) is dict: return row
|
|
479
|
+
return {}
|
|
480
|
+
except:
|
|
481
|
+
return {}
|
|
482
|
+
|
|
483
|
+
def resultset_is_empty (result: dict) -> bool:
|
|
484
|
+
try:
|
|
485
|
+
return (result.get(ERROR) is not None) or (not result.get(RESULT))
|
|
486
|
+
except:
|
|
487
|
+
return True
|
|
488
|
+
|
|
489
|
+
def dict_result (result: list=[], err: str=None, scope: str=UNKNOWN, aid: str=UNKNOWN) -> dict:
|
|
490
|
+
if err is None:
|
|
491
|
+
return {ACTION: aid, ERROR: None, RESULT: result}
|
|
492
|
+
else:
|
|
493
|
+
return {ACTION: aid, ERROR: f"{scope}: {err}", RESULT: []}
|
|
494
|
+
|
|
495
|
+
def error_database (err: str, aid: str=UNKNOWN) -> dict:
|
|
496
|
+
return dict_result([], err, DBERROR, aid=aid)
|
|
497
|
+
|
|
498
|
+
def error_unexpect (err: str, aid: str=UNKNOWN) -> dict:
|
|
499
|
+
return dict_result([], err, UNERROR, aid=aid)
|
|
500
|
+
|
|
501
|
+
def db_exist (db_path: str, engine=None) -> bool:
|
|
502
|
+
engine = engine or sys_engine
|
|
503
|
+
try:
|
|
504
|
+
if os.path.isfile(db_path):
|
|
505
|
+
if os.path.getsize(db_path)>100:
|
|
506
|
+
with open(db_path,'r', encoding=ENCODING) as f:
|
|
507
|
+
header = f.read(100)
|
|
508
|
+
if engine in [sqlite3, None]: return header.startswith(DBENGINE)
|
|
509
|
+
if engine in [duckdb]: return header[8:].startswith(DUCKDBENGINE)
|
|
510
|
+
return False
|
|
511
|
+
except:
|
|
512
|
+
return False
|
|
513
|
+
|
|
514
|
+
def setquery (model: Execute, query: str, aid: str=UNKNOWN):
|
|
515
|
+
model.data['query'] = query
|
|
516
|
+
model.data['aid'] = aid
|
|
517
|
+
|
|
518
|
+
def setretquery (model: Execute, query: str):
|
|
519
|
+
model.data['retquery'] = query
|
|
520
|
+
|
|
521
|
+
def setvals (model: Execute, vals: dict={}):
|
|
522
|
+
model.data['values'] = vals
|
|
523
|
+
|
|
524
|
+
def setretvals (model: Execute, vals: dict={}):
|
|
525
|
+
model.data['retvalues'] = vals
|
|
526
|
+
|
|
527
|
+
def setmany (model: Execute, val: bool=False):
|
|
528
|
+
model.data['many'] = val
|
|
529
|
+
|
|
530
|
+
def setscript (model: Execute, val: bool=False):
|
|
531
|
+
model.data['script'] = val
|
|
532
|
+
|
|
533
|
+
def setpandas (model: Execute, val: bool=False):
|
|
534
|
+
model.data['pandas'] = val
|
|
535
|
+
|
|
536
|
+
def setengine (model: Execute, val=None):
|
|
537
|
+
model.data['engine'] = val or sys_engine
|
|
538
|
+
|
|
539
|
+
def setconnect (model: Execute, val=None):
|
|
540
|
+
model.data['connect'] = val or sys_connect
|
|
541
|
+
|
|
542
|
+
def setdbpath (model: Execute, val: str):
|
|
543
|
+
model.data['db_path'] = val
|
|
544
|
+
|
|
545
|
+
def db_execute (db_caller: Execute) -> dict:
|
|
546
|
+
if db_caller.check['err_stat']: return db_caller.check['err_func'](db_caller.check['err_message'])
|
|
547
|
+
return db_caller.func(**db_caller.data)
|
|
548
|
+
|
|
549
|
+
def batch (queries: list, db_path: str=None, engine=None, connect=None) -> dict:
|
|
550
|
+
engine = engine or sys_engine
|
|
551
|
+
connect = connect or sys_connect
|
|
552
|
+
if not db_path: db_path = admindb(engine)
|
|
553
|
+
caller = Execute(func=execute_table_create_insert_update)
|
|
554
|
+
setquery(caller, ';'.join(queries))
|
|
555
|
+
setscript(caller, True)
|
|
556
|
+
setengine(caller, engine)
|
|
557
|
+
setconnect(caller, connect)
|
|
558
|
+
setdbpath(caller, db_path)
|
|
559
|
+
return db_execute(caller)
|
|
560
|
+
|
|
561
|
+
db_insert = execute_table_create_insert_update
|
|
562
|
+
|
|
563
|
+
db_select = fetch_table_as_list_of_dict
|
|
564
|
+
|
|
565
|
+
db_list = fetch_table_as_simple_list
|
|
566
|
+
|
|
567
|
+
def select_dict (query: str, model: BaseModel, db_path: str=None, func=db_select, layer=4, engine=None, connect=None, pandas: bool=False, **kw) -> dict:
|
|
568
|
+
engine = engine or sys_engine
|
|
569
|
+
connect = connect or sys_connect
|
|
570
|
+
if not db_path: db_path = admindb(engine)
|
|
571
|
+
caller = Execute(func=func)
|
|
572
|
+
setquery(caller, query, aid=get_aid(layer))
|
|
573
|
+
setvals(caller, reform_model(model))
|
|
574
|
+
setengine(caller, engine)
|
|
575
|
+
setconnect(caller, connect)
|
|
576
|
+
setdbpath(caller, db_path)
|
|
577
|
+
setpandas(caller, pandas)
|
|
578
|
+
return db_execute(caller)
|
|
579
|
+
|
|
580
|
+
def select_list (query: str, model: BaseModel, db_path: str=None, engine=None, connect=None, pandas: bool=False, **kw) -> dict:
|
|
581
|
+
engine = engine or sys_engine
|
|
582
|
+
connect = connect or sys_connect
|
|
583
|
+
return select_dict(func=db_list, query=query, model=model, db_path=db_path, engine=engine, connect=connect, pandas=pandas)
|
|
584
|
+
|
|
585
|
+
def insert_one (query: str, model: BaseModel, retquery: str='', db_path: str=None, layer=4, engine=None, connect=None, pandas: bool=False, **kw) -> dict:
|
|
586
|
+
engine = engine or sys_engine
|
|
587
|
+
connect = connect or sys_connect
|
|
588
|
+
if not db_path: db_path = admindb(engine)
|
|
589
|
+
caller = Execute(func=db_insert)
|
|
590
|
+
setquery(caller, query, aid=get_aid(layer))
|
|
591
|
+
setretquery(caller, retquery)
|
|
592
|
+
data = reform_model(model)
|
|
593
|
+
if type(data) is dict:
|
|
594
|
+
if data.get(ARRAY):
|
|
595
|
+
data[COL_LIMIT] = len(model.array)
|
|
596
|
+
setvals(caller, model.array)
|
|
597
|
+
setmany(caller, True)
|
|
598
|
+
else:
|
|
599
|
+
setvals(caller, data)
|
|
600
|
+
setretvals(caller, data) ##limit
|
|
601
|
+
else:
|
|
602
|
+
setvals(caller, data)
|
|
603
|
+
setretvals(caller, kw.get('retvalues'))
|
|
604
|
+
setengine(caller, engine)
|
|
605
|
+
setconnect(caller, connect)
|
|
606
|
+
setdbpath(caller, db_path)
|
|
607
|
+
setpandas(caller, pandas)
|
|
608
|
+
return db_execute(caller)
|
|
609
|
+
|
|
610
|
+
create_one = insert_one
|
|
611
|
+
|
|
612
|
+
update_one = insert_one
|
|
613
|
+
|
|
614
|
+
delete_one = insert_one
|
|
615
|
+
|
|
616
|
+
insert_many = insert_one
|
|
617
|
+
|
|
618
|
+
create_many = insert_many
|
|
619
|
+
|
|
620
|
+
update_many = insert_many
|
|
621
|
+
|
|
622
|
+
delete_many = insert_many
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: embedize
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: SQLite and DuckDB Tiny Lib
|
|
5
|
+
Home-page: https://github.com/asinerum/embedize
|
|
6
|
+
Author: Asinerum Conlang Project
|
|
7
|
+
Author-email: asinerum.com@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.7
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: duckdb>=1.4.2
|
|
16
|
+
Requires-Dist: pydantic>=2.12.5
|
|
17
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
Detailed tips, tricks, and examples, can be found at project's repository
|
|
21
|
+
https://github.com/asinerum/embedize
|
|
22
|
+
|
|
23
|
+
(C) 2026 Asinerum Conlang Project
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
embedize/__init__.py,sha256=gt_wGaSvvHy20spPijrYxSHcA2-Tbsc5krdubVcymMo,67
|
|
2
|
+
embedize/dbs.py,sha256=eAtQZ3XFs2y4l1HP4uQlUp1_PvFgssLeo8RqLuS-wbQ,10848
|
|
3
|
+
embedize/dcore.py,sha256=yatqRv3Hbhsc0brwY9KQco3tbHseoV-phxYnPzr8sCA,19997
|
|
4
|
+
embedize-1.0.2.dist-info/licenses/LICENSE,sha256=4npUbkrpgB6lqMiYYeUxZAP4SOkjVSwK8-7jW60mxvw,1081
|
|
5
|
+
embedize-1.0.2.dist-info/METADATA,sha256=-Vg7oIIZjYaA6RJf0eOQqb20ZvSK_D9En4jSLgSI2eM,732
|
|
6
|
+
embedize-1.0.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
7
|
+
embedize-1.0.2.dist-info/top_level.txt,sha256=iA0uN4RappjE38h_K_x_sjVZsyNY05nDSRfMcy9f_L4,9
|
|
8
|
+
embedize-1.0.2.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Asinerum Conlang Project
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
embedize
|