fleet-python 0.2.97__tar.gz → 0.2.98__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.
- {fleet_python-0.2.97/fleet_python.egg-info → fleet_python-0.2.98}/PKG-INFO +1 -1
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/__init__.py +1 -1
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/__init__.py +1 -1
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/base.py +1 -1
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/base.py +1 -1
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/resources/sqlite.py +40 -29
- {fleet_python-0.2.97 → fleet_python-0.2.98/fleet_python.egg-info}/PKG-INFO +1 -1
- {fleet_python-0.2.97 → fleet_python-0.2.98}/pyproject.toml +1 -1
- {fleet_python-0.2.97 → fleet_python-0.2.98}/LICENSE +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/README.md +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/diff_example.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/dsl_example.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/example.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/exampleResume.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/example_account.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/example_action_log.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/example_client.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/example_mcp_anthropic.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/example_mcp_openai.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/example_sync.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/example_task.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/example_tasks.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/example_verifier.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/export_tasks.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/fetch_tasks.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/gemini_example.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/import_tasks.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/iterate_verifiers.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/json_tasks_example.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/nova_act_example.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/openai_example.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/openai_simple_example.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/query_builder_example.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/quickstart.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/examples/test_cdp_logging.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/client.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/env/__init__.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/env/client.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/exceptions.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/global_client.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/instance/__init__.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/instance/base.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/instance/client.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/models.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/resources/__init__.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/resources/api.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/resources/base.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/resources/browser.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/resources/mcp.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/resources/sqlite.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/tasks.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/verifiers/__init__.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/verifiers/bundler.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/_async/verifiers/verifier.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/agent/__init__.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/agent/gemini_cua/Dockerfile +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/agent/gemini_cua/__init__.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/agent/gemini_cua/agent.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/agent/gemini_cua/mcp/main.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/agent/gemini_cua/mcp_server/__init__.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/agent/gemini_cua/mcp_server/main.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/agent/gemini_cua/mcp_server/tools.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/agent/gemini_cua/requirements.txt +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/agent/gemini_cua/start.sh +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/agent/orchestrator.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/agent/types.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/agent/utils.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/cli.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/client.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/config.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/env/__init__.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/env/client.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/eval/__init__.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/eval/uploader.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/exceptions.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/global_client.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/instance/__init__.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/instance/base.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/instance/client.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/instance/models.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/models.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/proxy/__init__.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/proxy/proxy.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/proxy/whitelist.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/resources/__init__.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/resources/api.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/resources/base.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/resources/browser.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/resources/mcp.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/tasks.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/types.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/utils/__init__.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/utils/http_logging.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/utils/logging.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/utils/playwright.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/verifiers/__init__.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/verifiers/bundler.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/verifiers/code.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/verifiers/db.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/verifiers/decorator.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/verifiers/parse.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/verifiers/sql_differ.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet/verifiers/verifier.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet_python.egg-info/SOURCES.txt +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet_python.egg-info/dependency_links.txt +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet_python.egg-info/entry_points.txt +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet_python.egg-info/requires.txt +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/fleet_python.egg-info/top_level.txt +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/scripts/fix_sync_imports.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/scripts/unasync.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/setup.cfg +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/tests/__init__.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/tests/test_app_method.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/tests/test_expect_only.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/tests/test_instance_dispatch.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/tests/test_sqlite_resource_dual_mode.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/tests/test_sqlite_shared_memory_behavior.py +0 -0
- {fleet_python-0.2.97 → fleet_python-0.2.98}/tests/test_verifier_from_string.py +0 -0
|
@@ -22,6 +22,17 @@ from fleet.verifiers.db import (
|
|
|
22
22
|
)
|
|
23
23
|
|
|
24
24
|
|
|
25
|
+
def _quote_identifier(identifier: str) -> str:
|
|
26
|
+
"""Quote an identifier (table or column name) for SQLite.
|
|
27
|
+
|
|
28
|
+
SQLite uses double quotes for identifiers and escapes internal quotes by doubling them.
|
|
29
|
+
This handles reserved keywords like 'order', 'table', etc.
|
|
30
|
+
"""
|
|
31
|
+
# Escape any double quotes in the identifier by doubling them
|
|
32
|
+
escaped = identifier.replace('"', '""')
|
|
33
|
+
return f'"{escaped}"'
|
|
34
|
+
|
|
35
|
+
|
|
25
36
|
class SyncDatabaseSnapshot:
|
|
26
37
|
"""Lazy database snapshot that fetches data on-demand through API."""
|
|
27
38
|
|
|
@@ -56,12 +67,12 @@ class SyncDatabaseSnapshot:
|
|
|
56
67
|
return
|
|
57
68
|
|
|
58
69
|
# Get table schema
|
|
59
|
-
schema_response = self.resource.query(f"PRAGMA table_info({table})")
|
|
70
|
+
schema_response = self.resource.query(f"PRAGMA table_info({_quote_identifier(table)})")
|
|
60
71
|
if schema_response.rows:
|
|
61
72
|
self._schemas[table] = [row[1] for row in schema_response.rows] # Column names
|
|
62
73
|
|
|
63
74
|
# Get all data for this table
|
|
64
|
-
data_response = self.resource.query(f"SELECT * FROM {table}")
|
|
75
|
+
data_response = self.resource.query(f"SELECT * FROM {_quote_identifier(table)}")
|
|
65
76
|
if data_response.rows and data_response.columns:
|
|
66
77
|
self._data[table] = [
|
|
67
78
|
dict(zip(data_response.columns, row)) for row in data_response.rows
|
|
@@ -122,23 +133,23 @@ class SyncSnapshotQueryBuilder:
|
|
|
122
133
|
where_parts = []
|
|
123
134
|
for col, op, val in self._conditions:
|
|
124
135
|
if op == "=" and val is None:
|
|
125
|
-
where_parts.append(f"{col} IS NULL")
|
|
136
|
+
where_parts.append(f"{_quote_identifier(col)} IS NULL")
|
|
126
137
|
elif op == "IS":
|
|
127
|
-
where_parts.append(f"{col} IS NULL")
|
|
138
|
+
where_parts.append(f"{_quote_identifier(col)} IS NULL")
|
|
128
139
|
elif op == "IS NOT":
|
|
129
|
-
where_parts.append(f"{col} IS NOT NULL")
|
|
140
|
+
where_parts.append(f"{_quote_identifier(col)} IS NOT NULL")
|
|
130
141
|
elif op == "=":
|
|
131
142
|
if isinstance(val, str):
|
|
132
143
|
escaped_val = val.replace("'", "''")
|
|
133
|
-
where_parts.append(f"{col} = '{escaped_val}'")
|
|
144
|
+
where_parts.append(f"{_quote_identifier(col)} = '{escaped_val}'")
|
|
134
145
|
else:
|
|
135
|
-
where_parts.append(f"{col} = '{val}'")
|
|
146
|
+
where_parts.append(f"{_quote_identifier(col)} = '{val}'")
|
|
136
147
|
|
|
137
148
|
where_clause = " AND ".join(where_parts)
|
|
138
149
|
|
|
139
150
|
# Build full query
|
|
140
151
|
cols = ", ".join(self._select_cols)
|
|
141
|
-
query = f"SELECT {cols} FROM {self._table} WHERE {where_clause}"
|
|
152
|
+
query = f"SELECT {cols} FROM {_quote_identifier(self._table)} WHERE {where_clause}"
|
|
142
153
|
|
|
143
154
|
if self._order_by:
|
|
144
155
|
query += f" ORDER BY {self._order_by}"
|
|
@@ -270,7 +281,7 @@ class SyncSnapshotDiff:
|
|
|
270
281
|
def _get_primary_key_columns(self, table: str) -> List[str]:
|
|
271
282
|
"""Get primary key columns for a table."""
|
|
272
283
|
# Try to get from schema
|
|
273
|
-
schema_response = self.after.resource.query(f"PRAGMA table_info({table})")
|
|
284
|
+
schema_response = self.after.resource.query(f"PRAGMA table_info({_quote_identifier(table)})")
|
|
274
285
|
if not schema_response.rows:
|
|
275
286
|
return ["id"] # Default fallback
|
|
276
287
|
|
|
@@ -409,18 +420,18 @@ class SyncSnapshotDiff:
|
|
|
409
420
|
return f"'{val}'"
|
|
410
421
|
|
|
411
422
|
if len(pk_columns) == 1:
|
|
412
|
-
return f"{pk_columns[0]} = {escape_value(pk_value)}"
|
|
423
|
+
return f"{_quote_identifier(pk_columns[0])} = {escape_value(pk_value)}"
|
|
413
424
|
else:
|
|
414
425
|
# Composite key
|
|
415
426
|
if isinstance(pk_value, tuple):
|
|
416
427
|
conditions = [
|
|
417
|
-
f"{col} = {escape_value(val)}"
|
|
428
|
+
f"{_quote_identifier(col)} = {escape_value(val)}"
|
|
418
429
|
for col, val in zip(pk_columns, pk_value)
|
|
419
430
|
]
|
|
420
431
|
return " AND ".join(conditions)
|
|
421
432
|
else:
|
|
422
433
|
# Shouldn't happen if data is consistent
|
|
423
|
-
return f"{pk_columns[0]} = {escape_value(pk_value)}"
|
|
434
|
+
return f"{_quote_identifier(pk_columns[0])} = {escape_value(pk_value)}"
|
|
424
435
|
|
|
425
436
|
def _expect_no_changes(self):
|
|
426
437
|
"""Efficiently verify that no changes occurred between snapshots using row counts."""
|
|
@@ -470,7 +481,7 @@ class SyncSnapshotDiff:
|
|
|
470
481
|
|
|
471
482
|
if table in before_tables:
|
|
472
483
|
before_count_response = self.before.resource.query(
|
|
473
|
-
f"SELECT COUNT(*) FROM {table}"
|
|
484
|
+
f"SELECT COUNT(*) FROM {_quote_identifier(table)}"
|
|
474
485
|
)
|
|
475
486
|
before_count = (
|
|
476
487
|
before_count_response.rows[0][0]
|
|
@@ -480,7 +491,7 @@ class SyncSnapshotDiff:
|
|
|
480
491
|
|
|
481
492
|
if table in after_tables:
|
|
482
493
|
after_count_response = self.after.resource.query(
|
|
483
|
-
f"SELECT COUNT(*) FROM {table}"
|
|
494
|
+
f"SELECT COUNT(*) FROM {_quote_identifier(table)}"
|
|
484
495
|
)
|
|
485
496
|
after_count = (
|
|
486
497
|
after_count_response.rows[0][0]
|
|
@@ -559,10 +570,10 @@ class SyncSnapshotDiff:
|
|
|
559
570
|
order_by = ", ".join(pk_columns) if pk_columns else "rowid"
|
|
560
571
|
|
|
561
572
|
before_response = self.before.resource.query(
|
|
562
|
-
f"SELECT * FROM {table} ORDER BY {order_by}"
|
|
573
|
+
f"SELECT * FROM {_quote_identifier(table)} ORDER BY {order_by}"
|
|
563
574
|
)
|
|
564
575
|
after_response = self.after.resource.query(
|
|
565
|
-
f"SELECT * FROM {table} ORDER BY {order_by}"
|
|
576
|
+
f"SELECT * FROM {_quote_identifier(table)} ORDER BY {order_by}"
|
|
566
577
|
)
|
|
567
578
|
|
|
568
579
|
# Quick check: if column counts differ, there's a schema change
|
|
@@ -646,7 +657,7 @@ class SyncSnapshotDiff:
|
|
|
646
657
|
where_sql = self._build_pk_where_clause(pk_columns, pk)
|
|
647
658
|
|
|
648
659
|
# Query before snapshot
|
|
649
|
-
before_query = f"SELECT * FROM {table} WHERE {where_sql}"
|
|
660
|
+
before_query = f"SELECT * FROM {_quote_identifier(table)} WHERE {where_sql}"
|
|
650
661
|
before_response = self.before.resource.query(before_query)
|
|
651
662
|
before_row = (
|
|
652
663
|
dict(zip(before_response.columns, before_response.rows[0]))
|
|
@@ -743,7 +754,7 @@ class SyncSnapshotDiff:
|
|
|
743
754
|
try:
|
|
744
755
|
# For tables with no allowed changes, just check row counts
|
|
745
756
|
before_count_response = self.before.resource.query(
|
|
746
|
-
f"SELECT COUNT(*) FROM {table}"
|
|
757
|
+
f"SELECT COUNT(*) FROM {_quote_identifier(table)}"
|
|
747
758
|
)
|
|
748
759
|
before_count = (
|
|
749
760
|
before_count_response.rows[0][0]
|
|
@@ -752,7 +763,7 @@ class SyncSnapshotDiff:
|
|
|
752
763
|
)
|
|
753
764
|
|
|
754
765
|
after_count_response = self.after.resource.query(
|
|
755
|
-
f"SELECT COUNT(*) FROM {table}"
|
|
766
|
+
f"SELECT COUNT(*) FROM {_quote_identifier(table)}"
|
|
756
767
|
)
|
|
757
768
|
after_count = (
|
|
758
769
|
after_count_response.rows[0][0] if after_count_response.rows else 0
|
|
@@ -1132,7 +1143,7 @@ class SyncSnapshotDiff:
|
|
|
1132
1143
|
where_sql = self._build_pk_where_clause(pk_columns, pk)
|
|
1133
1144
|
|
|
1134
1145
|
# Query before snapshot
|
|
1135
|
-
before_query = f"SELECT * FROM {table} WHERE {where_sql}"
|
|
1146
|
+
before_query = f"SELECT * FROM {_quote_identifier(table)} WHERE {where_sql}"
|
|
1136
1147
|
before_response = self.before.resource.query(before_query)
|
|
1137
1148
|
before_row = (
|
|
1138
1149
|
dict(zip(before_response.columns, before_response.rows[0]))
|
|
@@ -1219,7 +1230,7 @@ class SyncSnapshotDiff:
|
|
|
1219
1230
|
try:
|
|
1220
1231
|
# For tables with no allowed changes, just check row counts
|
|
1221
1232
|
before_count_response = self.before.resource.query(
|
|
1222
|
-
f"SELECT COUNT(*) FROM {table}"
|
|
1233
|
+
f"SELECT COUNT(*) FROM {_quote_identifier(table)}"
|
|
1223
1234
|
)
|
|
1224
1235
|
before_count = (
|
|
1225
1236
|
before_count_response.rows[0][0]
|
|
@@ -1228,7 +1239,7 @@ class SyncSnapshotDiff:
|
|
|
1228
1239
|
)
|
|
1229
1240
|
|
|
1230
1241
|
after_count_response = self.after.resource.query(
|
|
1231
|
-
f"SELECT COUNT(*) FROM {table}"
|
|
1242
|
+
f"SELECT COUNT(*) FROM {_quote_identifier(table)}"
|
|
1232
1243
|
)
|
|
1233
1244
|
after_count = (
|
|
1234
1245
|
after_count_response.rows[0][0] if after_count_response.rows else 0
|
|
@@ -1996,13 +2007,13 @@ class SyncQueryBuilder:
|
|
|
1996
2007
|
# Compile to SQL
|
|
1997
2008
|
def _compile(self) -> Tuple[str, List[Any]]:
|
|
1998
2009
|
cols = ", ".join(self._select_cols)
|
|
1999
|
-
sql = [f"SELECT {cols} FROM {self._table}"]
|
|
2010
|
+
sql = [f"SELECT {cols} FROM {_quote_identifier(self._table)}"]
|
|
2000
2011
|
params: List[Any] = []
|
|
2001
2012
|
|
|
2002
2013
|
# Joins
|
|
2003
2014
|
for tbl, onmap in self._joins:
|
|
2004
|
-
join_clauses = [f"{self._table}.{l} = {tbl}.{r}" for l, r in onmap.items()]
|
|
2005
|
-
sql.append(f"JOIN {tbl} ON {' AND '.join(join_clauses)}")
|
|
2015
|
+
join_clauses = [f"{_quote_identifier(self._table)}.{_quote_identifier(l)} = {_quote_identifier(tbl)}.{_quote_identifier(r)}" for l, r in onmap.items()]
|
|
2016
|
+
sql.append(f"JOIN {_quote_identifier(tbl)} ON {' AND '.join(join_clauses)}")
|
|
2006
2017
|
|
|
2007
2018
|
# WHERE
|
|
2008
2019
|
if self._conditions:
|
|
@@ -2010,12 +2021,12 @@ class SyncQueryBuilder:
|
|
|
2010
2021
|
for col, op, val in self._conditions:
|
|
2011
2022
|
if op in ("IN", "NOT IN") and isinstance(val, tuple):
|
|
2012
2023
|
ph = ", ".join(["?" for _ in val])
|
|
2013
|
-
placeholders.append(f"{col} {op} ({ph})")
|
|
2024
|
+
placeholders.append(f"{_quote_identifier(col)} {op} ({ph})")
|
|
2014
2025
|
params.extend(val)
|
|
2015
2026
|
elif op in ("IS", "IS NOT"):
|
|
2016
|
-
placeholders.append(f"{col} {op} NULL")
|
|
2027
|
+
placeholders.append(f"{_quote_identifier(col)} {op} NULL")
|
|
2017
2028
|
else:
|
|
2018
|
-
placeholders.append(f"{col} {op} ?")
|
|
2029
|
+
placeholders.append(f"{_quote_identifier(col)} {op} ?")
|
|
2019
2030
|
params.append(val)
|
|
2020
2031
|
sql.append("WHERE " + " AND ".join(placeholders))
|
|
2021
2032
|
|
|
@@ -2167,7 +2178,7 @@ class SQLiteResource(Resource):
|
|
|
2167
2178
|
tables = []
|
|
2168
2179
|
for table_name in table_names:
|
|
2169
2180
|
# Get table info
|
|
2170
|
-
cursor.execute(f"PRAGMA table_info({table_name})")
|
|
2181
|
+
cursor.execute(f"PRAGMA table_info({_quote_identifier(table_name)})")
|
|
2171
2182
|
columns = cursor.fetchall()
|
|
2172
2183
|
|
|
2173
2184
|
# Get CREATE TABLE SQL
|
|
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
|
|
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
|
|
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
|