tina4-python 0.2.165__tar.gz → 0.2.166__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.
- {tina4_python-0.2.165 → tina4_python-0.2.166}/PKG-INFO +1 -1
- {tina4_python-0.2.165 → tina4_python-0.2.166}/pyproject.toml +1 -1
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Database.py +29 -20
- {tina4_python-0.2.165 → tina4_python-0.2.166}/.gitignore +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/README.md +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Api.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Auth.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/CRUD.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Constant.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/DatabaseResult.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/DatabaseTypes.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Debug.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Env.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/FieldTypes.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Localization.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Messages.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/MiddleWare.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Migration.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/ORM.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Queue.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Request.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Response.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Router.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Session.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/ShellColors.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Swagger.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Template.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Testing.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/WSDL.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Webserver.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/Websocket.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/__init__.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/cli.py +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/messages.pot +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/public/css/readme.md +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/public/images/403.png +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/public/images/404.png +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/public/images/500.png +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/public/images/logo.png +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/public/images/readme.md +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/public/js/readme.md +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/public/js/reconnecting-websocket.js +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/public/js/tina4helper.js +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/templates/readme.md +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
|
@@ -11,8 +11,7 @@ import sys
|
|
|
11
11
|
import importlib
|
|
12
12
|
import json
|
|
13
13
|
from decimal import Decimal
|
|
14
|
-
from tina4_python import Debug
|
|
15
|
-
from tina4_python.Constant import TINA4_LOG_ERROR
|
|
14
|
+
from tina4_python import Debug
|
|
16
15
|
from tina4_python.DatabaseResult import DatabaseResult
|
|
17
16
|
from tina4_python.DatabaseTypes import *
|
|
18
17
|
from tina4_python.FieldTypes import get_field_type_values
|
|
@@ -41,7 +40,7 @@ class Database:
|
|
|
41
40
|
raise Exception("Database connection string is missing, try declaring DATABASE_PATH in the .env file.")
|
|
42
41
|
|
|
43
42
|
self.database_module = importlib.import_module(params[0])
|
|
44
|
-
except Exception:
|
|
43
|
+
except Exception as e:
|
|
45
44
|
install_message = "Please implement " + params[0] + " in Database.py and make a pull request!"
|
|
46
45
|
if params[0] == SQLITE:
|
|
47
46
|
install_message = "Your python is missing the sqlite3 module, please reinstall or update"
|
|
@@ -54,7 +53,7 @@ class Database:
|
|
|
54
53
|
elif params[0] == MSSQL:
|
|
55
54
|
install_message = "Your python is missing the mssql module, please install with " + MSSQL_INSTALL
|
|
56
55
|
|
|
57
|
-
sys.exit("Could not load database driver for " + params[0] + "\n" + install_message)
|
|
56
|
+
sys.exit("Could not load database driver for " + params[0] + "\n" + install_message+ "\n"+str(e))
|
|
58
57
|
|
|
59
58
|
|
|
60
59
|
self.database_engine = params[0]
|
|
@@ -186,7 +185,7 @@ class Database:
|
|
|
186
185
|
|
|
187
186
|
def get_next_id(self, table_name, column_name="id"):
|
|
188
187
|
"""
|
|
189
|
-
Gets the next id using max method in
|
|
188
|
+
Gets the next id using max method in SQL for databases which don't have good sequences
|
|
190
189
|
:param str table_name: Name of the table
|
|
191
190
|
:param str column_name: Name of the column in that table to increment
|
|
192
191
|
:return: int : The next id in the sequence
|
|
@@ -294,7 +293,7 @@ class Database:
|
|
|
294
293
|
cols = []
|
|
295
294
|
for c in raw:
|
|
296
295
|
name = c.strip().split()[-1].split(".")[-1]
|
|
297
|
-
name = re.sub(r'^[`"\[
|
|
296
|
+
name = re.sub(r'^[`"\[(].*[`"\])]$', '', name).strip('`"[]')
|
|
298
297
|
if name and name != "*":
|
|
299
298
|
cols.append(name)
|
|
300
299
|
|
|
@@ -326,18 +325,28 @@ class Database:
|
|
|
326
325
|
counter.close()
|
|
327
326
|
|
|
328
327
|
# 4. FINAL PAGINATION – applied AFTER the filter
|
|
329
|
-
if self.database_engine ==
|
|
328
|
+
if self.database_engine == FIREBIRD:
|
|
330
329
|
final_sql = f"SELECT FIRST {limit} SKIP {skip} * FROM ({final_sql}) AS t"
|
|
331
|
-
elif self.database_engine in (
|
|
330
|
+
elif self.database_engine in (MYSQL, SQLITE):
|
|
332
331
|
final_sql = f"SELECT * FROM ({final_sql}) AS t LIMIT {limit} OFFSET {skip}"
|
|
333
|
-
elif self.database_engine ==
|
|
332
|
+
elif self.database_engine == POSTGRES:
|
|
334
333
|
final_sql = f"SELECT * FROM ({final_sql}) AS t LIMIT {limit} OFFSET {skip}"
|
|
335
|
-
elif self.database_engine ==
|
|
336
|
-
# MSSQL needs ORDER BY for OFFSET/FETCH
|
|
334
|
+
elif self.database_engine == MSSQL:
|
|
337
335
|
inner = final_sql.strip()
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
336
|
+
# Detect and extract ORDER BY if present
|
|
337
|
+
order_by_match = re.search(r"(?i)\border\s+by\s+.+?$", inner, re.DOTALL)
|
|
338
|
+
has_order_by = order_by_match is not None
|
|
339
|
+
|
|
340
|
+
# Clean inner query: remove trailing ORDER BY if it exists
|
|
341
|
+
if has_order_by:
|
|
342
|
+
inner_clean = re.sub(r"(?i)\s+order\s+by\s+.+?$", "", inner, flags=re.DOTALL).strip()
|
|
343
|
+
order_by_part = order_by_match.group(0)
|
|
344
|
+
else:
|
|
345
|
+
inner_clean = inner
|
|
346
|
+
order_by_part = "ORDER BY (SELECT NULL)"
|
|
347
|
+
|
|
348
|
+
# Build final paginated query
|
|
349
|
+
final_sql = f"SELECT * FROM ({inner_clean}) AS t {order_by_part} OFFSET {skip} ROWS FETCH NEXT {limit} ROWS ONLY"
|
|
341
350
|
else:
|
|
342
351
|
final_sql = f"SELECT * FROM ({final_sql}) AS t LIMIT {limit} OFFSET {skip}"
|
|
343
352
|
|
|
@@ -356,7 +365,7 @@ class Database:
|
|
|
356
365
|
|
|
357
366
|
def fetch_one(self, sql, params=[], skip=0):
|
|
358
367
|
"""
|
|
359
|
-
Fetch a single record based on a
|
|
368
|
+
Fetch a single record based on a SQL statement, take note that BLOB and byte record data is converted into base64 automatically
|
|
360
369
|
:param str sql: A plain SQL statement or one with params in it designated by ?
|
|
361
370
|
:param list params: A list of params in order of precedence
|
|
362
371
|
:param int skip: Offset of records to skip
|
|
@@ -384,8 +393,8 @@ class Database:
|
|
|
384
393
|
|
|
385
394
|
def parse_place_holders(self, sql):
|
|
386
395
|
"""
|
|
387
|
-
Sanitizes a
|
|
388
|
-
MYSQL expects %s and firebird,
|
|
396
|
+
Sanitizes a SQL statement to replace param chars with the appropriate placeholders
|
|
397
|
+
MYSQL expects %s and firebird, PostgresSQL and sqlite expect ?
|
|
389
398
|
:param sql:
|
|
390
399
|
:return:
|
|
391
400
|
"""
|
|
@@ -396,7 +405,7 @@ class Database:
|
|
|
396
405
|
|
|
397
406
|
def execute(self, sql, params=None):
|
|
398
407
|
"""
|
|
399
|
-
Execute a query based on a
|
|
408
|
+
Execute a query based on a SQL statement
|
|
400
409
|
:param str sql: A plain SQL statement or one with params in it designated by ?
|
|
401
410
|
:param list params: A list of params in order of precedence
|
|
402
411
|
:return: DatabaseResult
|
|
@@ -431,7 +440,7 @@ class Database:
|
|
|
431
440
|
|
|
432
441
|
def execute_many(self, sql, params=None):
|
|
433
442
|
"""
|
|
434
|
-
Execute a query based on a single
|
|
443
|
+
Execute a query based on a single SQL statement with a different number of params
|
|
435
444
|
:param sql: A plain SQL statement or one with params in it designated by ?
|
|
436
445
|
:param params: A list of params in order of precedence
|
|
437
446
|
:return: DatabaseResult
|
|
@@ -513,7 +522,7 @@ class Database:
|
|
|
513
522
|
|
|
514
523
|
def sanitize(self, record):
|
|
515
524
|
"""
|
|
516
|
-
Changes dictionaries and list values into
|
|
525
|
+
Changes dictionaries and list values into JSON for updating and inserting
|
|
517
526
|
:param record:
|
|
518
527
|
:return:
|
|
519
528
|
"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/public/js/reconnecting-websocket.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/public/swagger/oauth2-redirect.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-0.2.165 → tina4_python-0.2.166}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|