dapper-sqls 0.9.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.
- dapper_sqls/__init__.py +7 -0
- dapper_sqls/_types.py +15 -0
- dapper_sqls/async_dapper/__init__.py +5 -0
- dapper_sqls/async_dapper/async_dapper.py +67 -0
- dapper_sqls/async_dapper/async_executors.py +343 -0
- dapper_sqls/builders/__init__.py +7 -0
- dapper_sqls/builders/model/__init__.py +5 -0
- dapper_sqls/builders/model/model.py +375 -0
- dapper_sqls/builders/model/utils.py +420 -0
- dapper_sqls/builders/query.py +80 -0
- dapper_sqls/builders/stored.py +66 -0
- dapper_sqls/builders/stp.py +133 -0
- dapper_sqls/config.py +109 -0
- dapper_sqls/dapper/__init__.py +6 -0
- dapper_sqls/dapper/dapper.py +66 -0
- dapper_sqls/dapper/executors.py +342 -0
- dapper_sqls/decorators.py +63 -0
- dapper_sqls/models/__init__.py +8 -0
- dapper_sqls/models/base.py +35 -0
- dapper_sqls/models/connection.py +60 -0
- dapper_sqls/models/http.py +10 -0
- dapper_sqls/models/result.py +123 -0
- dapper_sqls/sqlite/__init__.py +4 -0
- dapper_sqls/sqlite/local_database.py +268 -0
- dapper_sqls/sqlite/models.py +30 -0
- dapper_sqls/utils.py +89 -0
- dapper_sqls-0.9.2.dist-info/METADATA +11 -0
- dapper_sqls-0.9.2.dist-info/RECORD +30 -0
- dapper_sqls-0.9.2.dist-info/WHEEL +5 -0
- dapper_sqls-0.9.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,375 @@
|
|
1
|
+
# -*- coding: latin -*-
|
2
|
+
|
3
|
+
from itertools import groupby
|
4
|
+
import os
|
5
|
+
from .utils import create_content_orm, InformationSchemaTables, InformationSchemaRoutines, create_field, create_content_async_orm, create_params_routine, get_parameters_with_defaults
|
6
|
+
|
7
|
+
class TableBuilderData:
|
8
|
+
def __init__(self, table_schema : str, table_name : str, class_name : str, model : str, orm : str | None, async_orm : str | None):
|
9
|
+
self.table_schema = table_schema
|
10
|
+
self.table_name = table_name
|
11
|
+
self.class_name = class_name
|
12
|
+
self.model = model
|
13
|
+
self.orm = orm
|
14
|
+
self.async_orm = async_orm
|
15
|
+
|
16
|
+
class RoutineBuilderData:
|
17
|
+
def __init__(self, table_schema : str, stp_name : str, content_stp : str, content_async_stp : str):
|
18
|
+
self.table_schema = table_schema
|
19
|
+
self.stp_name = stp_name
|
20
|
+
self.content_stp = content_stp
|
21
|
+
self.content_async_stp = content_async_stp
|
22
|
+
|
23
|
+
class BuilderData(object):
|
24
|
+
def __init__(self, table_catalog : str):
|
25
|
+
self.table_catalog = table_catalog
|
26
|
+
self.talbes : list[TableBuilderData] = []
|
27
|
+
self.routines : list[RoutineBuilderData] = []
|
28
|
+
|
29
|
+
class ModelBuilder(object):
|
30
|
+
|
31
|
+
class TableOptions(object):
|
32
|
+
def __init__(self, table_name : str, *, create_orm=True, ignore_table=False):
|
33
|
+
self.table_name = table_name
|
34
|
+
self.create_orm = create_orm
|
35
|
+
self.ignore_table = ignore_table
|
36
|
+
|
37
|
+
class RoutineOptions(object):
|
38
|
+
def __init__(self, routine_name : str, ignore_routine=False):
|
39
|
+
self.routine_name = routine_name
|
40
|
+
self.ignore_routine = ignore_routine
|
41
|
+
|
42
|
+
def __init__(self, dapper):
|
43
|
+
self._dapper = dapper
|
44
|
+
self.query_tables = f"""
|
45
|
+
SELECT c.TABLE_CATALOG, c.TABLE_SCHEMA, c.TABLE_NAME, c.DATA_TYPE, c.COLUMN_NAME, c.IS_NULLABLE
|
46
|
+
FROM (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE') t
|
47
|
+
JOIN (
|
48
|
+
SELECT *
|
49
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
50
|
+
) c ON t.TABLE_NAME = c.TABLE_NAME
|
51
|
+
"""
|
52
|
+
|
53
|
+
self.query_routines = f"""
|
54
|
+
SELECT
|
55
|
+
p.SPECIFIC_NAME,
|
56
|
+
p.PARAMETER_NAME,
|
57
|
+
p.DATA_TYPE,
|
58
|
+
p.SPECIFIC_CATALOG,
|
59
|
+
p.SPECIFIC_SCHEMA,
|
60
|
+
p.ORDINAL_POSITION,
|
61
|
+
sm.definition AS PROCEDURE_DEFINITION
|
62
|
+
FROM
|
63
|
+
INFORMATION_SCHEMA.PARAMETERS p
|
64
|
+
JOIN
|
65
|
+
INFORMATION_SCHEMA.ROUTINES r ON p.SPECIFIC_NAME = r.SPECIFIC_NAME
|
66
|
+
JOIN
|
67
|
+
sys.sql_modules sm ON OBJECT_NAME(sm.object_id) = r.SPECIFIC_NAME
|
68
|
+
WHERE
|
69
|
+
r.ROUTINE_TYPE = 'PROCEDURE'
|
70
|
+
ORDER BY
|
71
|
+
p.SPECIFIC_NAME, p.ORDINAL_POSITION;
|
72
|
+
"""
|
73
|
+
|
74
|
+
@property
|
75
|
+
def dapper(self):
|
76
|
+
return self._dapper
|
77
|
+
|
78
|
+
def get_info_model_db(self):
|
79
|
+
with self.dapper.query() as db:
|
80
|
+
information_schema_tables = db.fetchall(self.query_tables)
|
81
|
+
if not information_schema_tables.success:
|
82
|
+
return False
|
83
|
+
information_schema_tables = self.dapper.load(InformationSchemaTables, information_schema_tables)
|
84
|
+
information_schema_tables = [table for table in information_schema_tables if not table.TABLE_NAME.startswith('__')]
|
85
|
+
|
86
|
+
information_schema_tables.sort(key=lambda x: x.TABLE_NAME)
|
87
|
+
grouped_data = groupby(information_schema_tables, lambda x: x.TABLE_NAME)
|
88
|
+
grouped_list : list[list[InformationSchemaTables]] = [[obj for obj in group] for _, group in grouped_data]
|
89
|
+
if not grouped_list:
|
90
|
+
return False
|
91
|
+
return grouped_list
|
92
|
+
|
93
|
+
def get_info_routines_db(self):
|
94
|
+
with self.dapper.query() as db:
|
95
|
+
information_schema_routines = db.fetchall(self.query_routines)
|
96
|
+
if not information_schema_routines:
|
97
|
+
return []
|
98
|
+
information_schema_routines = self.dapper.load(InformationSchemaRoutines, information_schema_routines)
|
99
|
+
|
100
|
+
information_schema_routines.sort(key=lambda x: x.SPECIFIC_NAME)
|
101
|
+
grouped_data = groupby(information_schema_routines, lambda x: x.SPECIFIC_NAME)
|
102
|
+
grouped_list : list[list[InformationSchemaRoutines]] = [[obj for obj in group] for _, group in grouped_data]
|
103
|
+
if not grouped_list:
|
104
|
+
return []
|
105
|
+
return grouped_list
|
106
|
+
|
107
|
+
def create_model_db(self, dir_path : str, create_orm = True, create_stp = True, *, table_catalog : str | list[str] | tuple[str] = "all",
|
108
|
+
table_schema : str | list[str] | tuple[str] = "all",
|
109
|
+
tables_options : list[TableOptions] = [], routines_oprions : list[RoutineOptions] = []):
|
110
|
+
|
111
|
+
dict_tables_options = {}
|
112
|
+
if tables_options:
|
113
|
+
dict_tables_options = {options.table_name : options for options in tables_options}
|
114
|
+
create_orm = False
|
115
|
+
for options in tables_options:
|
116
|
+
if options.create_orm:
|
117
|
+
create_orm = True
|
118
|
+
break
|
119
|
+
|
120
|
+
dict_routines_options = {options.routine_name : options for options in routines_oprions}
|
121
|
+
if routines_oprions:
|
122
|
+
create_stp = False
|
123
|
+
for options in routines_oprions:
|
124
|
+
if not options.ignore_routine:
|
125
|
+
create_stp = True
|
126
|
+
break
|
127
|
+
|
128
|
+
information_db = self.get_info_model_db()
|
129
|
+
information_routines = []
|
130
|
+
if create_stp:
|
131
|
+
information_routines = self.get_info_routines_db()
|
132
|
+
if not information_db:
|
133
|
+
return False
|
134
|
+
|
135
|
+
table_catalog = [table_catalog] if isinstance(table_catalog, str) and table_catalog != "all" else table_catalog
|
136
|
+
table_schema = [table_schema] if isinstance(table_schema, str) and table_schema != "all" else table_schema
|
137
|
+
|
138
|
+
builder_data : dict[str, BuilderData] = {}
|
139
|
+
import_init_db = ""
|
140
|
+
for data in information_db:
|
141
|
+
|
142
|
+
if table_catalog != "all":
|
143
|
+
if data[0].TABLE_CATALOG not in table_catalog :
|
144
|
+
continue
|
145
|
+
|
146
|
+
if table_schema != "all":
|
147
|
+
if data[0].TABLE_SCHEMA not in table_schema :
|
148
|
+
continue
|
149
|
+
|
150
|
+
table_options = dict_tables_options.get(data[0].TABLE_NAME)
|
151
|
+
if table_options:
|
152
|
+
if table_options.ignore_table:
|
153
|
+
continue
|
154
|
+
|
155
|
+
content_model = '''# -*- coding: latin -*-
|
156
|
+
|
157
|
+
from dapper_sqls import TableBaseModel
|
158
|
+
from datetime import datetime
|
159
|
+
from pydantic import Field
|
160
|
+
from typing import Union
|
161
|
+
|
162
|
+
'''
|
163
|
+
|
164
|
+
table_name = data[0].TABLE_NAME
|
165
|
+
class_name = table_name.replace("TBL_", "")
|
166
|
+
schema = data[0].TABLE_SCHEMA
|
167
|
+
|
168
|
+
fields = [create_field(row) for row in data]
|
169
|
+
fields_str = "\n ".join(fields)
|
170
|
+
|
171
|
+
content_model += f'''
|
172
|
+
class {class_name}(TableBaseModel):
|
173
|
+
_TABLE_NAME: str = '[{schema}].[{table_name}]'
|
174
|
+
|
175
|
+
{fields_str}
|
176
|
+
\n
|
177
|
+
'''
|
178
|
+
|
179
|
+
fields_args = [create_field(row, "None") for row in data]
|
180
|
+
fields_args_str = ", ".join(fields_args)
|
181
|
+
|
182
|
+
table_create_orm = create_orm
|
183
|
+
if table_options:
|
184
|
+
table_create_orm = table_options.create_orm
|
185
|
+
|
186
|
+
content_orm = create_content_orm(class_name, fields_args_str) if table_create_orm else None
|
187
|
+
content_async_orm = create_content_async_orm(class_name, fields_args_str) if table_create_orm else None
|
188
|
+
|
189
|
+
catalog = data[0].TABLE_CATALOG
|
190
|
+
if catalog not in builder_data:
|
191
|
+
builder_data[catalog] = BuilderData(catalog)
|
192
|
+
|
193
|
+
table_builder_data = TableBuilderData(schema, table_name, class_name, content_model, content_orm, content_async_orm)
|
194
|
+
builder_data[catalog].talbes.append(table_builder_data)
|
195
|
+
|
196
|
+
for data in information_routines:
|
197
|
+
|
198
|
+
if table_catalog != "all":
|
199
|
+
if data[0].SPECIFIC_CATALOG not in table_catalog :
|
200
|
+
continue
|
201
|
+
|
202
|
+
if table_schema != "all":
|
203
|
+
if data[0].SPECIFIC_SCHEMA not in table_schema :
|
204
|
+
continue
|
205
|
+
|
206
|
+
routine_oprions = dict_routines_options.get(data[0].SPECIFIC_NAME)
|
207
|
+
if routine_oprions:
|
208
|
+
if routine_oprions.ignore_routine:
|
209
|
+
continue
|
210
|
+
|
211
|
+
defaults_values = get_parameters_with_defaults(data[0].PROCEDURE_DEFINITION)
|
212
|
+
params_routine = [create_params_routine(row, defaults_values) for row in data]
|
213
|
+
params_routine_str = ", ".join(params_routine)
|
214
|
+
|
215
|
+
stp_name = data[0].SPECIFIC_NAME.replace('STP_', '')
|
216
|
+
content_routine = f'''
|
217
|
+
def {stp_name}(self, *, {params_routine_str}):
|
218
|
+
return StpBuilder(self.dapper, '[{data[0].SPECIFIC_SCHEMA}].[{data[0].SPECIFIC_NAME}]',locals())'''
|
219
|
+
|
220
|
+
content_async_routine = f'''
|
221
|
+
def {stp_name}(self, *, {params_routine_str}):
|
222
|
+
return AsyncStpBuilder(self.async_dapper, '[{data[0].SPECIFIC_SCHEMA}].[{data[0].SPECIFIC_NAME}]', locals())'''
|
223
|
+
|
224
|
+
catalog = data[0].SPECIFIC_CATALOG
|
225
|
+
if catalog not in builder_data:
|
226
|
+
builder_data[catalog] = BuilderData(catalog)
|
227
|
+
|
228
|
+
builder_data[catalog].routines.append(RoutineBuilderData(data[0].SPECIFIC_SCHEMA, data[0].SPECIFIC_NAME, content_routine, content_async_routine))
|
229
|
+
|
230
|
+
for catalog, data in builder_data.items():
|
231
|
+
import_init_db += f"from .{catalog} import {catalog}\n"
|
232
|
+
|
233
|
+
dir_catalog = os.path.join(dir_path, catalog)
|
234
|
+
schema_data_tables : dict[str, list[TableBuilderData]] = {}
|
235
|
+
for table in data.talbes:
|
236
|
+
if table.table_schema not in schema_data_tables:
|
237
|
+
schema_data_tables[table.table_schema] = []
|
238
|
+
|
239
|
+
dir_schema = os.path.join(dir_catalog, table.table_schema)
|
240
|
+
dir_table = os.path.join(dir_schema, table.table_name)
|
241
|
+
|
242
|
+
if not os.path.exists(dir_table):
|
243
|
+
os.makedirs(dir_table)
|
244
|
+
|
245
|
+
table_options = dict_tables_options.get(table.table_name)
|
246
|
+
|
247
|
+
table_create_orm = create_orm
|
248
|
+
if table_options:
|
249
|
+
table_create_orm = table_options.create_orm
|
250
|
+
|
251
|
+
if table_create_orm:
|
252
|
+
with open(os.path.join(dir_table ,'orm.py'), 'w', encoding='utf-8') as file:
|
253
|
+
file.write(''.join(table.orm))
|
254
|
+
|
255
|
+
with open(os.path.join(dir_table ,'async_orm.py'), 'w', encoding='utf-8') as file:
|
256
|
+
file.write(''.join(table.async_orm))
|
257
|
+
|
258
|
+
with open(os.path.join(dir_table ,f'__init__.py'), 'w', encoding='utf-8') as file:
|
259
|
+
if table_create_orm:
|
260
|
+
file.write(f'from .orm import {table.class_name}ORM\nfrom .async_orm import Async{table.class_name}ORM\nfrom .model import {table.class_name}')
|
261
|
+
else:
|
262
|
+
file.write(f'from .model import {table.class_name}')
|
263
|
+
|
264
|
+
with open(os.path.join(dir_table ,'model.py'), 'w', encoding='utf-8') as file:
|
265
|
+
file.write(''.join(table.model))
|
266
|
+
|
267
|
+
|
268
|
+
schema_data_tables[table.table_schema].append(table)
|
269
|
+
|
270
|
+
schema_data_routine : dict[str, list[RoutineBuilderData]] = {}
|
271
|
+
content_file_routine = '''# -*- coding: latin -*-
|
272
|
+
from dapper_sqls import StpBuilder
|
273
|
+
from dapper_sqls import Dapper
|
274
|
+
from datetime import datetime
|
275
|
+
from typing import Union
|
276
|
+
|
277
|
+
class stp(object):
|
278
|
+
|
279
|
+
def __init__(self, dapper : Dapper):
|
280
|
+
self._dapper = dapper
|
281
|
+
|
282
|
+
@property
|
283
|
+
def dapper(self):
|
284
|
+
return self._dapper
|
285
|
+
'''
|
286
|
+
|
287
|
+
content_file_async_rounine = '''# -*- coding: latin -*-
|
288
|
+
from dapper_sqls import AsyncStpBuilder
|
289
|
+
from dapper_sqls import AsyncDapper
|
290
|
+
from datetime import datetime
|
291
|
+
from typing import Union
|
292
|
+
|
293
|
+
class async_stp(object):
|
294
|
+
|
295
|
+
def __init__(self, async_dapper : AsyncDapper):
|
296
|
+
self._async_dapper = async_dapper
|
297
|
+
|
298
|
+
@property
|
299
|
+
def async_dapper(self):
|
300
|
+
return self._async_dapper
|
301
|
+
'''
|
302
|
+
|
303
|
+
for routine in data.routines:
|
304
|
+
if routine.table_schema not in schema_data_routine:
|
305
|
+
schema_data_routine[routine.table_schema] = []
|
306
|
+
|
307
|
+
dir_schema = os.path.join(dir_catalog, routine.table_schema)
|
308
|
+
if not os.path.exists(dir_schema):
|
309
|
+
os.makedirs(dir_schema)
|
310
|
+
|
311
|
+
content_file_routine += f'{routine.content_stp}\n'
|
312
|
+
content_file_async_rounine += f'{routine.content_async_stp}\n'
|
313
|
+
|
314
|
+
if data.routines:
|
315
|
+
dir_schema = os.path.join(dir_catalog, data.routines[0].table_schema)
|
316
|
+
with open(os.path.join(dir_schema ,'routines.py'), 'w', encoding='utf-8') as file:
|
317
|
+
file.write(''.join(content_file_routine))
|
318
|
+
with open(os.path.join(dir_schema ,'async_routines.py'), 'w', encoding='utf-8') as file:
|
319
|
+
file.write(''.join(content_file_async_rounine))
|
320
|
+
|
321
|
+
import_init_catalog = ""
|
322
|
+
class_init_catalog = f"class {catalog}(object):\n"
|
323
|
+
|
324
|
+
for schema, data in schema_data_tables.items():
|
325
|
+
import_init_catalog += f"from .{schema} import schema_{schema}\n"
|
326
|
+
class_init_catalog += f"\n class {schema}(schema_{schema}):\n ...\n"
|
327
|
+
import_init_schema = ""
|
328
|
+
class_init_schema = ""
|
329
|
+
class_models_schema = " class models(object):\n"
|
330
|
+
class_orm_schema = " class orm(object):\n def __init__(self, dapper : Dapper):\n"
|
331
|
+
class_async_orm_schema = " class async_orm(object):\n def __init__(self, async_dapper : AsyncDapper):\n"
|
332
|
+
for table in data:
|
333
|
+
|
334
|
+
table_options = dict_tables_options.get(table.table_name)
|
335
|
+
table_create_orm = create_orm
|
336
|
+
if table_options:
|
337
|
+
table_create_orm = table_options.create_orm
|
338
|
+
|
339
|
+
dir_schema = os.path.join(dir_catalog, schema)
|
340
|
+
class_models_schema += f"\n class {table.class_name}({table.class_name}):\n ...\n"
|
341
|
+
if table_create_orm:
|
342
|
+
class_orm_schema += f" self.{table.class_name} = {table.class_name}ORM(dapper)\n"
|
343
|
+
class_async_orm_schema += f" self.{table.class_name} = Async{table.class_name}ORM(async_dapper)\n"
|
344
|
+
import_init_schema += f"from .{table.table_name} import {table.class_name}, {table.class_name}ORM, Async{table.class_name}ORM\n"
|
345
|
+
class_init_schema += f"\n class {table.class_name}ORM({table.class_name}ORM):\n ...\n"
|
346
|
+
class_init_schema += f"\n class Async{table.class_name}ORM(Async{table.class_name}ORM):\n ...\n"
|
347
|
+
else:
|
348
|
+
import_init_schema += f"from .{table.table_name} import {table.class_name}\n"
|
349
|
+
|
350
|
+
if information_routines :
|
351
|
+
import_init_schema += "from .routines import stp\nfrom .async_routines import async_stp\n"
|
352
|
+
|
353
|
+
class_stp = "\n class stp(stp):\n ...\n" if information_routines else ""
|
354
|
+
class_async_stp = "\n class async_stp(async_stp):\n ...\n" if information_routines else ""
|
355
|
+
|
356
|
+
class_schema = f"class schema_{schema}(object):\n"
|
357
|
+
if create_orm:
|
358
|
+
class_init_schema = f"{class_schema}{class_stp}{class_async_stp}\n{class_models_schema}\n{class_orm_schema}\n{class_async_orm_schema}\n{class_init_schema}"
|
359
|
+
content_init_schema = f"{import_init_schema}\nfrom dapper_sqls import Dapper, AsyncDapper\n\n{class_init_schema}"
|
360
|
+
else:
|
361
|
+
class_init_schema = f"{class_schema}{class_stp}{class_async_stp}\n{class_models_schema}"
|
362
|
+
content_init_schema = f"{import_init_schema}\n\n{class_init_schema}"
|
363
|
+
|
364
|
+
with open(os.path.join(dir_schema ,f'__init__.py'), 'w', encoding='utf-8') as file:
|
365
|
+
file.write(''.join(content_init_schema))
|
366
|
+
|
367
|
+
content_init_catalog = f"{import_init_catalog}\n\n{class_init_catalog}"
|
368
|
+
with open(os.path.join(dir_catalog ,f'__init__.py'), 'w', encoding='utf-8') as file:
|
369
|
+
file.write(''.join(content_init_catalog))
|
370
|
+
|
371
|
+
if builder_data:
|
372
|
+
#with open(os.path.join(dir_path ,f'__init__.py'), 'w', encoding='utf-8') as file:
|
373
|
+
# file.write(''.join(import_init_db))
|
374
|
+
|
375
|
+
return True
|