t-sql 1.2.0__tar.gz → 1.2.1__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.
Files changed (34) hide show
  1. {t_sql-1.2.0 → t_sql-1.2.1}/.github/workflows/test.yml +17 -0
  2. t_sql-1.2.1/.idea/.gitignore +8 -0
  3. t_sql-1.2.1/.idea/inspectionProfiles/Project_Default.xml +24 -0
  4. t_sql-1.2.1/.idea/inspectionProfiles/profiles_settings.xml +6 -0
  5. t_sql-1.2.1/.idea/misc.xml +11 -0
  6. t_sql-1.2.1/.idea/tsql.iml +10 -0
  7. t_sql-1.2.1/.idea/vcs.xml +6 -0
  8. t_sql-1.2.1/.idea/workspace.xml +118 -0
  9. {t_sql-1.2.0 → t_sql-1.2.1}/PKG-INFO +68 -2
  10. {t_sql-1.2.0 → t_sql-1.2.1}/README.md +67 -1
  11. {t_sql-1.2.0 → t_sql-1.2.1}/pyproject.toml +1 -1
  12. {t_sql-1.2.0 → t_sql-1.2.1}/tests/test_asyncpg_integration.py +2 -1
  13. {t_sql-1.2.0 → t_sql-1.2.1}/tests/test_injection_protection_validation.py +2 -1
  14. {t_sql-1.2.0 → t_sql-1.2.1}/tests/test_injections_for_escaped.py +2 -1
  15. {t_sql-1.2.0 → t_sql-1.2.1}/.dockerignore +0 -0
  16. {t_sql-1.2.0 → t_sql-1.2.1}/.github/workflows/publish.yml +0 -0
  17. {t_sql-1.2.0 → t_sql-1.2.1}/.gitignore +0 -0
  18. {t_sql-1.2.0 → t_sql-1.2.1}/Dockerfile +0 -0
  19. {t_sql-1.2.0 → t_sql-1.2.1}/LICENSE +0 -0
  20. {t_sql-1.2.0 → t_sql-1.2.1}/compose.yaml +0 -0
  21. {t_sql-1.2.0 → t_sql-1.2.1}/context7.json +0 -0
  22. {t_sql-1.2.0 → t_sql-1.2.1}/pytest.ini +0 -0
  23. {t_sql-1.2.0 → t_sql-1.2.1}/tests/test_different_object_types.py +0 -0
  24. {t_sql-1.2.0 → t_sql-1.2.1}/tests/test_escaped.py +0 -0
  25. {t_sql-1.2.0 → t_sql-1.2.1}/tests/test_escaped_binary_hex.py +0 -0
  26. {t_sql-1.2.0 → t_sql-1.2.1}/tests/test_helper_functions.py +0 -0
  27. {t_sql-1.2.0 → t_sql-1.2.1}/tests/test_injection_edge_cases.py +0 -0
  28. {t_sql-1.2.0 → t_sql-1.2.1}/tests/test_query_builder.py +0 -0
  29. {t_sql-1.2.0 → t_sql-1.2.1}/tests/test_sqlalchemy_integration.py +0 -0
  30. {t_sql-1.2.0 → t_sql-1.2.1}/tests/test_styles.py +0 -0
  31. {t_sql-1.2.0 → t_sql-1.2.1}/tests/test_tsql.py +0 -0
  32. {t_sql-1.2.0 → t_sql-1.2.1}/tsql/__init__.py +0 -0
  33. {t_sql-1.2.0 → t_sql-1.2.1}/tsql/query_builder.py +0 -0
  34. {t_sql-1.2.0 → t_sql-1.2.1}/tsql/styles.py +0 -0
@@ -13,6 +13,21 @@ jobs:
13
13
  matrix:
14
14
  python-version: ["3.14"]
15
15
 
16
+ services:
17
+ postgres:
18
+ image: postgres:18
19
+ env:
20
+ POSTGRES_PASSWORD: password
21
+ POSTGRES_USER: postgres
22
+ POSTGRES_DB: postgres
23
+ ports:
24
+ - 5432:5432
25
+ options: >-
26
+ --health-cmd pg_isready
27
+ --health-interval 10s
28
+ --health-timeout 5s
29
+ --health-retries 5
30
+
16
31
  steps:
17
32
  - uses: actions/checkout@v4
18
33
 
@@ -28,4 +43,6 @@ jobs:
28
43
  run: uv sync
29
44
 
30
45
  - name: Run tests
46
+ env:
47
+ DATABASE_URL: postgresql://postgres:password@localhost:5432/postgres
31
48
  run: uv run pytest -v
@@ -0,0 +1,8 @@
1
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
4
+ # Editor-based HTTP Client requests
5
+ /httpRequests/
6
+ # Datasource local storage ignored files
7
+ /dataSources/
8
+ /dataSources.local.xml
@@ -0,0 +1,24 @@
1
+ <component name="InspectionProjectProfileManager">
2
+ <profile version="1.0">
3
+ <option name="myName" value="Project Default" />
4
+ <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
5
+ <inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
6
+ <option name="ourVersions">
7
+ <value>
8
+ <list size="3">
9
+ <item index="0" class="java.lang.String" itemvalue="3.11" />
10
+ <item index="1" class="java.lang.String" itemvalue="3.12" />
11
+ <item index="2" class="java.lang.String" itemvalue="3.13" />
12
+ </list>
13
+ </value>
14
+ </option>
15
+ </inspection_tool>
16
+ <inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
17
+ <option name="ignoredIdentifiers">
18
+ <list>
19
+ <option value="base64.binascii" />
20
+ </list>
21
+ </option>
22
+ </inspection_tool>
23
+ </profile>
24
+ </component>
@@ -0,0 +1,6 @@
1
+ <component name="InspectionProjectProfileManager">
2
+ <settings>
3
+ <option name="USE_PROJECT_PROFILE" value="false" />
4
+ <version value="1.0" />
5
+ </settings>
6
+ </component>
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="Black">
4
+ <option name="sdkName" value="uv (tsql)" />
5
+ </component>
6
+ <component name="KubernetesApiPersistence">{}</component>
7
+ <component name="KubernetesApiProvider"><![CDATA[{
8
+ "isMigrated": true
9
+ }]]></component>
10
+ <component name="ProjectRootManager" version="2" project-jdk-name="uv (tsql)" project-jdk-type="Python SDK" />
11
+ </project>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module version="4">
3
+ <component name="PyDocumentationSettings">
4
+ <option name="format" value="PLAIN" />
5
+ <option name="myDocStringFormat" value="Plain" />
6
+ </component>
7
+ <component name="TestRunnerService">
8
+ <option name="PROJECT_TEST_RUNNER" value="py.test" />
9
+ </component>
10
+ </module>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="" vcs="Git" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,118 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="AutoImportSettings">
4
+ <option name="autoReloadType" value="SELECTIVE" />
5
+ </component>
6
+ <component name="ChangeListManager">
7
+ <list default="true" id="059146b3-62bd-4ad4-890d-4356cf237b89" name="Changes" comment="">
8
+ <change beforePath="$PROJECT_DIR$/pyproject.toml" beforeDir="false" afterPath="$PROJECT_DIR$/pyproject.toml" afterDir="false" />
9
+ </list>
10
+ <option name="SHOW_DIALOG" value="false" />
11
+ <option name="HIGHLIGHT_CONFLICTS" value="true" />
12
+ <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
13
+ <option name="LAST_RESOLUTION" value="IGNORE" />
14
+ </component>
15
+ <component name="Git.Settings">
16
+ <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
17
+ </component>
18
+ <component name="GitHubPullRequestSearchHistory">{
19
+ &quot;lastFilter&quot;: {
20
+ &quot;state&quot;: &quot;OPEN&quot;,
21
+ &quot;assignee&quot;: &quot;nhumrich&quot;
22
+ }
23
+ }</component>
24
+ <component name="GithubPullRequestsUISettings">{
25
+ &quot;selectedUrlAndAccountId&quot;: {
26
+ &quot;url&quot;: &quot;git@github.com:nhumrich/tsql.git&quot;,
27
+ &quot;accountId&quot;: &quot;f308fc0d-c429-47fb-8e52-74bdc95408d8&quot;
28
+ }
29
+ }</component>
30
+ <component name="ProjectColorInfo">{
31
+ &quot;associatedIndex&quot;: 2
32
+ }</component>
33
+ <component name="ProjectId" id="33DagtaPqCq8RWQhigWGQcgOtLh" />
34
+ <component name="ProjectViewState">
35
+ <option name="compactDirectories" value="true" />
36
+ <option name="hideEmptyMiddlePackages" value="true" />
37
+ <option name="showLibraryContents" value="true" />
38
+ </component>
39
+ <component name="PropertiesComponent">{
40
+ &quot;keyToString&quot;: {
41
+ &quot;ModuleVcsDetector.initialDetectionPerformed&quot;: &quot;true&quot;,
42
+ &quot;Python tests.pytest in test_sqlalchemy_integration.py.executor&quot;: &quot;Debug&quot;,
43
+ &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
44
+ &quot;RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252&quot;: &quot;true&quot;,
45
+ &quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
46
+ &quot;git-widget-placeholder&quot;: &quot;main&quot;,
47
+ &quot;junie.onboarding.icon.badge.shown&quot;: &quot;true&quot;,
48
+ &quot;last_opened_file_path&quot;: &quot;/home/nhumrich/personal/tsql&quot;,
49
+ &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
50
+ &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
51
+ &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
52
+ &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
53
+ &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
54
+ &quot;to.speed.mode.migration.done&quot;: &quot;true&quot;,
55
+ &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
56
+ }
57
+ }</component>
58
+ <component name="RunManager">
59
+ <configuration name="pytest in test_sqlalchemy_integration.py" type="tests" factoryName="py.test" temporary="true" nameIsGenerated="true">
60
+ <module name="tsql" />
61
+ <option name="ENV_FILES" value="" />
62
+ <option name="INTERPRETER_OPTIONS" value="" />
63
+ <option name="PARENT_ENVS" value="true" />
64
+ <option name="SDK_HOME" value="" />
65
+ <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
66
+ <option name="IS_MODULE_SDK" value="true" />
67
+ <option name="ADD_CONTENT_ROOTS" value="true" />
68
+ <option name="ADD_SOURCE_ROOTS" value="true" />
69
+ <EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
70
+ <option name="_new_keywords" value="&quot;&quot;" />
71
+ <option name="_new_parameters" value="&quot;&quot;" />
72
+ <option name="_new_additionalArguments" value="&quot;&quot;" />
73
+ <option name="_new_target" value="&quot;$PROJECT_DIR$/tests/test_sqlalchemy_integration.py&quot;" />
74
+ <option name="_new_targetType" value="&quot;PATH&quot;" />
75
+ <method v="2" />
76
+ </configuration>
77
+ <recent_temporary>
78
+ <list>
79
+ <item itemvalue="Python tests.pytest in test_sqlalchemy_integration.py" />
80
+ </list>
81
+ </recent_temporary>
82
+ </component>
83
+ <component name="SharedIndexes">
84
+ <attachedChunks>
85
+ <set>
86
+ <option value="bundled-js-predefined-d6986cc7102b-3aa1da707db6-JavaScript-PY-252.26830.99" />
87
+ <option value="bundled-python-sdk-164cda30dcd9-0af03a5fa574-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-252.26830.99" />
88
+ </set>
89
+ </attachedChunks>
90
+ </component>
91
+ <component name="TaskManager">
92
+ <task active="true" id="Default" summary="Default task">
93
+ <changelist id="059146b3-62bd-4ad4-890d-4356cf237b89" name="Changes" comment="" />
94
+ <created>1758854212149</created>
95
+ <option name="number" value="Default" />
96
+ <option name="presentableId" value="Default" />
97
+ <updated>1758854212149</updated>
98
+ </task>
99
+ <servers />
100
+ </component>
101
+ <component name="TypeScriptGeneratedFilesManager">
102
+ <option name="version" value="3" />
103
+ </component>
104
+ <component name="Vcs.Log.Tabs.Properties">
105
+ <option name="TAB_STATES">
106
+ <map>
107
+ <entry key="MAIN">
108
+ <value>
109
+ <State />
110
+ </value>
111
+ </entry>
112
+ </map>
113
+ </option>
114
+ </component>
115
+ <component name="com.intellij.coverage.CoverageDataManagerImpl">
116
+ <SUITE FILE_PATH="coverage/tsql$pytest_in_test_sqlalchemy_integration_py.coverage" NAME="pytest in test_sqlalchemy_integration.py Coverage Results" MODIFIED="1760138305802" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
117
+ </component>
118
+ </project>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: t-sql
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: Safe SQL. SQL queries for python t-strings (PEP 750)
5
5
  Project-URL: Homepage, https://github.com/nhumrich/tsql
6
6
  License-File: LICENSE
@@ -154,11 +154,29 @@ values = {'id': 'abc123', 'name': 'bob', 'email': 'bob@example.com'}
154
154
  tsql.insert(table, values)
155
155
  # INSERT INTO users (id, name, email) VALUES ('abc123', 'bob', 'bob@example.com')
156
156
 
157
+ # insert with ignore_conflict
158
+ tsql.insert(table, values, ignore_conflict=True)
159
+ # INSERT INTO users (id, name, email) VALUES ('abc123', 'bob', 'bob@example.com') ON CONFLICT DO NOTHING RETURNING *
160
+
161
+ # upsert (insert or update on conflict)
162
+ values = {'id': 'abc123', 'name': 'joe', 'email': 'joe@example.com'}
163
+ tsql.upsert(table, values, conflict_on='id')
164
+ # INSERT INTO users (id, name, email) VALUES ('abc123', 'joe', 'joe@example.com')
165
+ # ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, email = EXCLUDED.email RETURNING *
166
+
167
+ # upsert with multiple conflict columns
168
+ tsql.upsert(table, values, conflict_on=['email', 'name'])
169
+ # ON CONFLICT (email, name) DO UPDATE SET ...
170
+
157
171
  # update values on a single row
158
172
  table = 'users'
159
173
  values = {'name': 'joe', 'email': 'joe@example.com'}
160
174
  tsql.update(table, values, id='abc123')
161
- # UPDATE users SET name='joe', email='joe@example.com' WHERE id='abc123'
175
+ # UPDATE users SET name='joe', email='joe@example.com' WHERE id='abc123' RETURNING *
176
+
177
+ # delete a single row
178
+ tsql.delete(table, id='abc123')
179
+ # DELETE FROM users WHERE id = 'abc123'
162
180
  ```
163
181
 
164
182
  # Query Builder
@@ -251,6 +269,54 @@ query = (Posts.select(Posts.title, Users.username)
251
269
  .limit(20))
252
270
  ```
253
271
 
272
+ ## Write Operations
273
+
274
+ The query builder supports INSERT, UPDATE, UPSERT, and DELETE operations:
275
+
276
+ ```python
277
+ # INSERT
278
+ values = {'id': 'abc123', 'username': 'john', 'email': 'john@example.com'}
279
+ query = Users.insert(values)
280
+ sql, params = query.render()
281
+ # INSERT INTO users (id, username, email) VALUES (?, ?, ?) RETURNING *
282
+
283
+ # INSERT with conflict handling (ignore)
284
+ query = Users.insert(values, ignore_conflict=True)
285
+ sql, params = query.render()
286
+ # INSERT INTO users (id, username, email) VALUES (?, ?, ?) ON CONFLICT DO NOTHING RETURNING *
287
+
288
+ # UPSERT (INSERT ... ON CONFLICT DO UPDATE)
289
+ values = {'id': 'abc123', 'username': 'john_updated', 'email': 'john@example.com'}
290
+ query = Users.upsert(values, conflict_on='id')
291
+ sql, params = query.render()
292
+ # INSERT INTO users (id, username, email) VALUES (?, ?, ?)
293
+ # ON CONFLICT (id) DO UPDATE SET username=EXCLUDED.username, email=EXCLUDED.email RETURNING *
294
+
295
+ # UPSERT with multiple conflict columns
296
+ query = Users.upsert(values, conflict_on=['email', 'username'])
297
+ # Can also use Column objects: conflict_on=Users.id or conflict_on=[Users.email, Users.username]
298
+
299
+ # UPDATE with WHERE conditions
300
+ query = Users.update({'email': 'newemail@example.com'}).where(Users.id == 'abc123')
301
+ sql, params = query.render()
302
+ # UPDATE users SET email=? WHERE users.id = ? RETURNING *
303
+
304
+ # UPDATE with multiple conditions
305
+ query = (Users.update({'email': 'newemail@example.com'})
306
+ .where(Users.id == 'abc123')
307
+ .where(Users.username == 'john'))
308
+
309
+ # DELETE with WHERE conditions
310
+ query = Users.delete().where(Users.id == 'abc123')
311
+ sql, params = query.render()
312
+ # DELETE FROM users WHERE users.id = ? RETURNING *
313
+
314
+ # DELETE with multiple conditions
315
+ query = Users.delete().where(Users.id > 100).where(Users.email == None)
316
+ ```
317
+
318
+ All write operations return `RETURNING *` by default to retrieve the affected rows.
319
+
254
320
  ## Advanced Mixed Query (Query Builder + T-Strings)
255
321
 
256
322
  You can combine the query builder's structured approach with raw t-string conditions for complex logic:
@@ -143,11 +143,29 @@ values = {'id': 'abc123', 'name': 'bob', 'email': 'bob@example.com'}
143
143
  tsql.insert(table, values)
144
144
  # INSERT INTO users (id, name, email) VALUES ('abc123', 'bob', 'bob@example.com')
145
145
 
146
+ # insert with ignore_conflict
147
+ tsql.insert(table, values, ignore_conflict=True)
148
+ # INSERT INTO users (id, name, email) VALUES ('abc123', 'bob', 'bob@example.com') ON CONFLICT DO NOTHING RETURNING *
149
+
150
+ # upsert (insert or update on conflict)
151
+ values = {'id': 'abc123', 'name': 'joe', 'email': 'joe@example.com'}
152
+ tsql.upsert(table, values, conflict_on='id')
153
+ # INSERT INTO users (id, name, email) VALUES ('abc123', 'joe', 'joe@example.com')
154
+ # ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, email = EXCLUDED.email RETURNING *
155
+
156
+ # upsert with multiple conflict columns
157
+ tsql.upsert(table, values, conflict_on=['email', 'name'])
158
+ # ON CONFLICT (email, name) DO UPDATE SET ...
159
+
146
160
  # update values on a single row
147
161
  table = 'users'
148
162
  values = {'name': 'joe', 'email': 'joe@example.com'}
149
163
  tsql.update(table, values, id='abc123')
150
- # UPDATE users SET name='joe', email='joe@example.com' WHERE id='abc123'
164
+ # UPDATE users SET name='joe', email='joe@example.com' WHERE id='abc123' RETURNING *
165
+
166
+ # delete a single row
167
+ tsql.delete(table, id='abc123')
168
+ # DELETE FROM users WHERE id = 'abc123'
151
169
  ```
152
170
 
153
171
  # Query Builder
@@ -240,6 +258,54 @@ query = (Posts.select(Posts.title, Users.username)
240
258
  .limit(20))
241
259
  ```
242
260
 
261
+ ## Write Operations
262
+
263
+ The query builder supports INSERT, UPDATE, UPSERT, and DELETE operations:
264
+
265
+ ```python
266
+ # INSERT
267
+ values = {'id': 'abc123', 'username': 'john', 'email': 'john@example.com'}
268
+ query = Users.insert(values)
269
+ sql, params = query.render()
270
+ # INSERT INTO users (id, username, email) VALUES (?, ?, ?) RETURNING *
271
+
272
+ # INSERT with conflict handling (ignore)
273
+ query = Users.insert(values, ignore_conflict=True)
274
+ sql, params = query.render()
275
+ # INSERT INTO users (id, username, email) VALUES (?, ?, ?) ON CONFLICT DO NOTHING RETURNING *
276
+
277
+ # UPSERT (INSERT ... ON CONFLICT DO UPDATE)
278
+ values = {'id': 'abc123', 'username': 'john_updated', 'email': 'john@example.com'}
279
+ query = Users.upsert(values, conflict_on='id')
280
+ sql, params = query.render()
281
+ # INSERT INTO users (id, username, email) VALUES (?, ?, ?)
282
+ # ON CONFLICT (id) DO UPDATE SET username=EXCLUDED.username, email=EXCLUDED.email RETURNING *
283
+
284
+ # UPSERT with multiple conflict columns
285
+ query = Users.upsert(values, conflict_on=['email', 'username'])
286
+ # Can also use Column objects: conflict_on=Users.id or conflict_on=[Users.email, Users.username]
287
+
288
+ # UPDATE with WHERE conditions
289
+ query = Users.update({'email': 'newemail@example.com'}).where(Users.id == 'abc123')
290
+ sql, params = query.render()
291
+ # UPDATE users SET email=? WHERE users.id = ? RETURNING *
292
+
293
+ # UPDATE with multiple conditions
294
+ query = (Users.update({'email': 'newemail@example.com'})
295
+ .where(Users.id == 'abc123')
296
+ .where(Users.username == 'john'))
297
+
298
+ # DELETE with WHERE conditions
299
+ query = Users.delete().where(Users.id == 'abc123')
300
+ sql, params = query.render()
301
+ # DELETE FROM users WHERE users.id = ? RETURNING *
302
+
303
+ # DELETE with multiple conditions
304
+ query = Users.delete().where(Users.id > 100).where(Users.email == None)
305
+ ```
306
+
307
+ All write operations return `RETURNING *` by default to retrieve the affected rows.
308
+
243
309
  ## Advanced Mixed Query (Query Builder + T-Strings)
244
310
 
245
311
  You can combine the query builder's structured approach with raw t-string conditions for complex logic:
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "t-sql"
7
- version = "1.2.0"
7
+ version = "1.2.1"
8
8
  description = "Safe SQL. SQL queries for python t-strings (PEP 750)"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.14"
@@ -1,4 +1,5 @@
1
1
  import asyncpg
2
+ import os
2
3
  import pytest
3
4
 
4
5
  import tsql
@@ -6,7 +7,7 @@ import tsql.styles
6
7
 
7
8
 
8
9
  # Test configuration
9
- DATABASE_URL = "postgresql://postgres:password@localhost:5454/postgres"
10
+ DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://postgres:password@localhost:5454/postgres")
10
11
 
11
12
 
12
13
  @pytest.fixture
@@ -1,11 +1,12 @@
1
1
  import asyncpg
2
+ import os
2
3
  import pytest
3
4
 
4
5
  import tsql
5
6
  import tsql.styles
6
7
 
7
8
  # Test configuration
8
- DATABASE_URL = "postgresql://postgres:password@localhost:5454/postgres"
9
+ DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://postgres:password@localhost:5454/postgres")
9
10
 
10
11
 
11
12
  @pytest.fixture
@@ -3,12 +3,13 @@ Proof-of-concept test demonstrating that tsql actually prevents SQL injection at
3
3
  against a real PostgreSQL database.
4
4
  """
5
5
  import asyncpg
6
+ import os
6
7
  import pytest
7
8
 
8
9
  import tsql
9
10
  import tsql.styles
10
11
 
11
- DATABASE_URL = "postgresql://postgres:password@localhost:5454/postgres"
12
+ DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://postgres:password@localhost:5454/postgres")
12
13
 
13
14
 
14
15
  @pytest.fixture
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