sqlym 0.1.0__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.
@@ -0,0 +1,260 @@
1
+ Metadata-Version: 2.4
2
+ Name: sqlym
3
+ Version: 0.1.0
4
+ Summary: SQL-first database access library for Python
5
+ Author: izuno4t
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Database
17
+ Requires-Python: >=3.10
18
+ Provides-Extra: mysql
19
+ Requires-Dist: pymysql>=1.1; extra == 'mysql'
20
+ Provides-Extra: oracle
21
+ Requires-Dist: oracledb>=3.0; extra == 'oracle'
22
+ Provides-Extra: postgresql
23
+ Requires-Dist: psycopg[binary]>=3.1; extra == 'postgresql'
24
+ Provides-Extra: pydantic
25
+ Requires-Dist: pydantic>=2.0; extra == 'pydantic'
26
+ Description-Content-Type: text/markdown
27
+
28
+ # sqlym
29
+
30
+ [![PyPI version](https://img.shields.io/pypi/v/sqlym.svg)](https://pypi.org/project/sqlym/)
31
+ [![Python versions](https://img.shields.io/pypi/pyversions/sqlym.svg)](https://pypi.org/project/sqlym/)
32
+ [![License](https://img.shields.io/pypi/l/sqlym.svg)](https://github.com/izuno4t/sqlym/blob/main/LICENSE)
33
+ [![CI](https://github.com/izuno4t/sqlym/actions/workflows/ci.yml/badge.svg)](https://github.com/izuno4t/sqlym/actions/workflows/ci.yml)
34
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
35
+
36
+ [日本語](README.ja.md)
37
+
38
+ A SQL template engine for Python. Inspired by Java's
39
+ [Clione-SQL](https://github.com/tauty/clione-sql) /
40
+ [Doma2](https://github.com/domaframework/doma), it provides a 2-way SQL parser
41
+ and row-to-object mapping.
42
+
43
+ - **SQL-first** — Write SQL directly, not through an ORM. sqlym never
44
+ auto-generates SQL
45
+ - **2-way SQL** — SQL files remain directly executable by DB tools
46
+ - **Zero dependencies** — Core runs on the Python standard library only
47
+ (Pydantic is optional)
48
+ - **Flexible mapping** — Auto-mapping for dataclass / Pydantic, or bring your
49
+ own function
50
+
51
+ ## Quick Start
52
+
53
+ ```bash
54
+ pip install sqlym
55
+ ```
56
+
57
+ ### 1. Define an Entity
58
+
59
+ ```python
60
+ from dataclasses import dataclass
61
+ from typing import Annotated
62
+ from sqlym import Column
63
+
64
+ @dataclass
65
+ class Employee:
66
+ id: int
67
+ name: Annotated[str, Column("EMP_NAME")] # when column name differs
68
+ dept_id: int | None = None
69
+ ```
70
+
71
+ ### 2. Write a SQL File
72
+
73
+ `sql/employee/find_by_dept.sql`:
74
+
75
+ ```sql
76
+ SELECT
77
+ id,
78
+ EMP_NAME,
79
+ dept_id
80
+ FROM
81
+ employee
82
+ WHERE
83
+ id = /* $id */0
84
+ AND dept_id = /* $dept_id */1
85
+ AND status = /* $status */'active'
86
+ ```
87
+
88
+ ### 3. Execute
89
+
90
+ ```python
91
+ from sqlym import SqlExecutor, create_mapper
92
+
93
+ executor = SqlExecutor(connection)
94
+ mapper = create_mapper(Employee)
95
+
96
+ # Lines with None parameters are automatically removed
97
+ result = executor.query(
98
+ "sql/employee/find_by_dept.sql",
99
+ {
100
+ "id": 100,
101
+ "dept_id": None,
102
+ "status": "active",
103
+ }, # dept_id line is removed
104
+ mapper=mapper
105
+ )
106
+
107
+ for emp in result:
108
+ print(emp.name)
109
+ ```
110
+
111
+ For the full SQL syntax reference, see [SQL Syntax](SQL_SYNTAX.md).
112
+
113
+ ## Features
114
+
115
+ ### 2-way SQL (Clione-SQL Style)
116
+
117
+ Parameters are written as SQL comments. The SQL file can be executed directly
118
+ by DB tools.
119
+
120
+ ```sql
121
+ -- None removes the line ($ prefix)
122
+ WHERE name = /* $name */'default'
123
+
124
+ -- None binds as NULL (no $ prefix)
125
+ WHERE name = /* name */'default'
126
+ ```
127
+
128
+ ### Indent-based Parent-Child Relationships
129
+
130
+ When all children are removed, the parent is also removed.
131
+
132
+ ```sql
133
+ WHERE
134
+ id = /* $id */0
135
+ AND (
136
+ status = /* $status1 */'a'
137
+ OR status = /* $status2 */'b'
138
+ )
139
+ -- If both status1 and status2 are None, the entire parenthesized block is
140
+ -- removed
141
+ ```
142
+
143
+ ### Automatic IN Clause Expansion
144
+
145
+ ```sql
146
+ WHERE dept_id IN /* $dept_ids */(1, 2, 3)
147
+ -- dept_ids=[10,20,30] → WHERE dept_id IN (?, ?, ?)
148
+ ```
149
+
150
+ ### Error Message Settings
151
+
152
+ Errors raised during SQL parsing include the line number by default.
153
+ If you want to hide the SQL snippet from error messages, disable it via
154
+ config:
155
+
156
+ ```python
157
+ from sqlym import config
158
+
159
+ config.ERROR_INCLUDE_SQL = False
160
+ config.ERROR_MESSAGE_LANGUAGE = "en"
161
+ ```
162
+
163
+ Set `ERROR_MESSAGE_LANGUAGE` to `ja` or `en`.
164
+
165
+ ### Mappers
166
+
167
+ ```python
168
+ # Auto-mapping (dataclass / Pydantic)
169
+ mapper = create_mapper(Employee)
170
+
171
+ # Manual mapping (when column names differ significantly)
172
+ mapper = create_mapper(Employee, mapper=lambda row: Employee(
173
+ id=row['EMP_ID'],
174
+ name=row['EMP_NM'],
175
+ dept_id=row['DEPT_CODE'],
176
+ ))
177
+ ```
178
+
179
+ ### Column Name Mapping
180
+
181
+ ```python
182
+ from typing import Annotated
183
+ from sqlym import Column, entity
184
+
185
+ @dataclass
186
+ class Employee:
187
+ # Per-field mapping
188
+ id: Annotated[int, Column("EMP_ID")]
189
+ name: Annotated[str, Column("EMP_NAME")]
190
+
191
+ # No mapping — uses field name as-is
192
+ email: str
193
+
194
+ # Or apply a naming convention
195
+ @entity(naming="snake_to_camel") # dept_id → deptId
196
+ @dataclass
197
+ class Employee:
198
+ dept_id: int # → deptId
199
+ ```
200
+
201
+ ## RDBMS Support
202
+
203
+ Supports SQLite, PostgreSQL, MySQL, and Oracle.
204
+
205
+ | RDBMS | Driver | Placeholder | Extras |
206
+ | --- | --- | --- | --- |
207
+ | SQLite | [sqlite3](https://docs.python.org/3/library/sqlite3.html) (stdlib) | `?` | — |
208
+ | PostgreSQL | [psycopg](https://www.psycopg.org/) 3.1+ | `%s` | `sqlym[postgresql]` |
209
+ | MySQL | [PyMySQL](https://pymysql.readthedocs.io/) 1.1+ | `%s` | `sqlym[mysql]` |
210
+ | Oracle | [python-oracledb](https://python-oracledb.readthedocs.io/) 3.0+ | `:name` | `sqlym[oracle]` |
211
+
212
+ For RDBMS other than SQLite, install with extras. The driver will be installed
213
+ automatically.
214
+
215
+ ```bash
216
+ pip install sqlym[postgresql]
217
+ ```
218
+
219
+ | Feature | Description |
220
+ | --- | --- |
221
+ | LIKE escaping | Handles LIKE escape differences across databases |
222
+ | IN clause limit | Splits when exceeding Oracle's 1000-element limit |
223
+ | RDBMS-specific SQL file loading | Fallback: `find.oracle.sql` → `find.sql` |
224
+
225
+ When SQL syntax differs across databases, you can provide database-specific SQL
226
+ files:
227
+
228
+ ```text
229
+ sql/employee/
230
+ ├── find.sql # Common SQL
231
+ ├── find.oracle.sql # Oracle-specific (loaded preferentially)
232
+ └── find.postgresql.sql # PostgreSQL-specific (loaded preferentially)
233
+ ```
234
+
235
+ ## What sqlym Does Not Provide
236
+
237
+ sqlym is a SQL template engine. The following features are out of scope.
238
+ Write SQL directly or combine with other libraries.
239
+
240
+ - SQL generation (INSERT/UPDATE/DELETE/UPSERT, etc.)
241
+ - Pagination SQL generation (`LIMIT/OFFSET`, `ROWNUM`, etc.)
242
+ - DDL management / migrations
243
+ - Connection management / connection pooling
244
+ - Transaction management
245
+
246
+ ## Acknowledgments
247
+
248
+ sqlym's 2-way SQL parser is based on the design of
249
+ [Clione-SQL](https://github.com/tauty/clione-sql) by tauty. The four rules for
250
+ line-based SQL processing, indent-driven parent-child relationships, and
251
+ parameter comment syntax all originate from Clione-SQL.
252
+
253
+ The dialect design and RDBMS-specific behavior handling draw from
254
+ [Doma2](https://github.com/domaframework/doma) by the Doma Framework team.
255
+
256
+ We are grateful to both projects for their pioneering work in 2-way SQL.
257
+
258
+ ## License
259
+
260
+ MIT
@@ -0,0 +1,22 @@
1
+ sqlym/__init__.py,sha256=F4CmKaMLzvkv1yJFOTb0Y0AcVFlxDfVbZXIyDNHtexI,761
2
+ sqlym/_parse.py,sha256=i88qDRBTuUrqMFf1dZhz3GJMTBNUXt7boKISINUfHK8,917
3
+ sqlym/config.py,sha256=D-lZeN4hITBu0dtXkfsMpn_EVzXVd-6V1cXBClhYgT4,196
4
+ sqlym/dialect.py,sha256=0M2AUh4ouAgLICjvf8mdnWXsOiVqCAUUnHfskAOVRxs,2592
5
+ sqlym/escape_utils.py,sha256=r5XMQpLL30T6EjzA1La6w5UmWHndcYgpy13p0OZr8Cc,1604
6
+ sqlym/exceptions.py,sha256=fLcWKHLzsa758FY-DVA20zV3g0Hxwk3UQdEe2oFdHto,313
7
+ sqlym/loader.py,sha256=53iYp7mS3mhy96RD4OjlQz9cTRxTT5EQYBv8RdfUN34,2617
8
+ sqlym/mapper/__init__.py,sha256=5n7id9I-e6vcwgj-JBXvFEajpDwJWI2MHMEQSeh1gag,235
9
+ sqlym/mapper/column.py,sha256=gQXP44kFc7_T9HHXINUL5YLk0I4d15sDn1JUKlA4Tvw,1005
10
+ sqlym/mapper/dataclass.py,sha256=TozhN28hPiw47fEdFz008WqW9xrLo1clRijbQJE_U9s,3702
11
+ sqlym/mapper/factory.py,sha256=zD2DVzDSnbmUoOWIeVImin5RxVvL5UgJlxPVZS-4p6Q,1266
12
+ sqlym/mapper/manual.py,sha256=iZ_9VMABPwLz8yFMUFdehmIvoGyHs8efXOA4NGwAJN0,680
13
+ sqlym/mapper/protocol.py,sha256=9UtYYv15BzR1kK26JznYvsXdjZfY-_UbGqKhkgTIaxc,512
14
+ sqlym/mapper/pydantic.py,sha256=vba6K5m33nuyyCgza7LV6Mo22HndVTECzL_Y5QaxOmY,768
15
+ sqlym/parser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ sqlym/parser/line_unit.py,sha256=PlFCZ31O3LNQAHKzm-ccop_r2eP5bcqBuE4q9cY1dfA,796
17
+ sqlym/parser/tokenizer.py,sha256=-eRWTt2EeEHSMV5OXtSJontmFHEDzxwJmSdaZNAwpx4,3051
18
+ sqlym/parser/twoway.py,sha256=kg65LQw9OTefPv9VjpnOq_4Aw-AW_22Hk4NpNA68i8k,19538
19
+ sqlym-0.1.0.dist-info/METADATA,sha256=1X3sOhCL62r-aefutL15sjHu7a152lZ9xXO5wz9I1qg,7137
20
+ sqlym-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
21
+ sqlym-0.1.0.dist-info/licenses/LICENSE,sha256=7vb-PbcXVPtaKh9PfRKbiAFPXA_zcRIfhE90vqCSF5A,1064
22
+ sqlym-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 izuno4t
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.