sqlpiston 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,99 @@
1
+ from abc import ABC, abstractmethod
2
+ from enum import Enum
3
+ from typing import Any, List, Optional, Tuple
4
+
5
+ from sqlpiston.builder.nodes import ExprValue
6
+ from sqlpiston._types import SQLValue
7
+ from sqlpiston.compiler.base import Dialect
8
+
9
+
10
+ class DBType(Enum):
11
+ MySQL = 1
12
+ SQLite = 2
13
+
14
+
15
+ class Cursor(ABC):
16
+ """Query result cursor. Wraps DB-API cursor."""
17
+
18
+ @abstractmethod
19
+ def fetchall(self) -> List[Tuple[SQLValue, ...]]:
20
+ ...
21
+
22
+ @abstractmethod
23
+ def fetchone(self) -> Optional[Tuple[SQLValue, ...]]:
24
+ ...
25
+
26
+ @property
27
+ @abstractmethod
28
+ def rowcount(self) -> int:
29
+ ...
30
+
31
+ @property
32
+ @abstractmethod
33
+ def description(self) -> List[Tuple[str, int, Any, Any, Any, Any, Any]]:
34
+ ...
35
+
36
+
37
+ class Connection(ABC):
38
+ """A single database connection."""
39
+
40
+ @abstractmethod
41
+ def execute(self, sql: str, params: Tuple[ExprValue, ...]) -> Cursor:
42
+ ...
43
+
44
+ @abstractmethod
45
+ def begin(self) -> None:
46
+ ...
47
+
48
+ @abstractmethod
49
+ def commit(self) -> None:
50
+ ...
51
+
52
+ @abstractmethod
53
+ def rollback(self) -> None:
54
+ ...
55
+
56
+ @abstractmethod
57
+ def close(self) -> None:
58
+ ...
59
+
60
+ def __enter__(self) -> 'Connection': # pragma: no cover — abstract class, covered via subclasses
61
+ return self
62
+
63
+ def __exit__(self, *args: Any) -> None: # pragma: no cover — abstract class, covered via subclasses
64
+ self.close()
65
+
66
+
67
+ class Engine(ABC):
68
+ """Abstract database engine."""
69
+
70
+ @property
71
+ @abstractmethod
72
+ def dialect(self) -> Dialect:
73
+ ...
74
+
75
+ @abstractmethod
76
+ def connect(self) -> Connection:
77
+ ...
78
+
79
+ @abstractmethod
80
+ def close(self) -> None:
81
+ ...
82
+
83
+ def __enter__(self) -> 'Engine': # pragma: no cover — abstract class, covered via subclasses
84
+ return self
85
+
86
+ def __exit__(self, *args: Any) -> None: # pragma: no cover — abstract class, covered via subclasses
87
+ self.close()
88
+
89
+
90
+ def DBEngine(db_type: DBType) -> Engine:
91
+ """Factory: returns typed engine by DBType."""
92
+ if db_type == DBType.MySQL:
93
+ from sqlpiston.core.engine.mysql import MySQLEngine
94
+ return MySQLEngine()
95
+ elif db_type == DBType.SQLite:
96
+ from sqlpiston.core.engine.sqlite import SQLiteEngine
97
+ return SQLiteEngine()
98
+ else:
99
+ raise ValueError(f"Unsupported DB type: {db_type}")
@@ -0,0 +1,80 @@
1
+ from typing import Any, Dict, List, Optional, Tuple, cast
2
+
3
+ from sqlpiston.builder.nodes import ExprValue
4
+ from sqlpiston._types import SQLValue
5
+ from sqlpiston.compiler.mysql import MySQLDialect
6
+ from sqlpiston.core.engine.base import Connection, Cursor, Engine
7
+
8
+
9
+ class MySQLCursor(Cursor): # pragma: no cover — requires mysql.connector (optional dependency)
10
+ def __init__(self, raw_cursor: Any) -> None:
11
+ self._cursor = raw_cursor
12
+
13
+ def fetchall(self) -> List[Tuple[SQLValue, ...]]:
14
+ return [tuple(row) for row in self._cursor.fetchall()]
15
+
16
+ def fetchone(self) -> Optional[Tuple[SQLValue, ...]]:
17
+ row = self._cursor.fetchone()
18
+ return tuple(row) if row else None
19
+
20
+ @property
21
+ def rowcount(self) -> int:
22
+ return int(self._cursor.rowcount)
23
+
24
+ @property
25
+ def description(self) -> List[Tuple[str, int, Any, Any, Any, Any, Any]]: # pragma: no cover — requires mysql.connector
26
+ desc = self._cursor.description
27
+ if desc is None:
28
+ return []
29
+ return cast(List[Tuple[str, int, Any, Any, Any, Any, Any]], desc)
30
+
31
+
32
+ class MySQLConnection(Connection): # pragma: no cover — requires mysql.connector (optional dependency)
33
+ def __init__(self, raw_conn: Any) -> None:
34
+ self._conn = raw_conn
35
+
36
+ def execute(self, sql: str, params: Tuple[ExprValue, ...]) -> MySQLCursor:
37
+ cursor = self._conn.cursor()
38
+ cursor.execute(sql, params)
39
+ return MySQLCursor(cursor)
40
+
41
+ def begin(self) -> None:
42
+ self._conn.begin()
43
+
44
+ def commit(self) -> None:
45
+ self._conn.commit()
46
+
47
+ def rollback(self) -> None:
48
+ self._conn.rollback()
49
+
50
+ def close(self) -> None:
51
+ self._conn.close()
52
+
53
+
54
+ class MySQLEngine(Engine):
55
+ def __init__(self) -> None:
56
+ self._config: Optional[Dict[str, Any]] = None
57
+ self._conn: Any = None
58
+
59
+ def init_engine(self, host: str, port: int, user: str, password: str, database: str) -> None:
60
+ self._config = {
61
+ 'host': host, 'port': port,
62
+ 'user': user, 'password': password,
63
+ 'database': database,
64
+ }
65
+
66
+ @property
67
+ def dialect(self) -> MySQLDialect:
68
+ return MySQLDialect()
69
+
70
+ def connect(self) -> MySQLConnection: # pragma: no cover — requires mysql.connector (optional dependency)
71
+ if self._config is None:
72
+ raise RuntimeError("Call init_engine() before connect()")
73
+ import mysql.connector # type: ignore[import-not-found]
74
+ self._conn = mysql.connector.connect(**self._config)
75
+ return MySQLConnection(self._conn)
76
+
77
+ def close(self) -> None: # pragma: no cover — requires mysql.connector
78
+ if self._conn:
79
+ self._conn.close()
80
+ self._conn = None
@@ -0,0 +1,76 @@
1
+ import sqlite3
2
+ from typing import Any, List, Optional, Tuple, cast
3
+
4
+ from sqlpiston.builder.nodes import ExprValue
5
+ from sqlpiston._types import SQLValue
6
+ from sqlpiston.compiler.sqlite import SQLiteDialect
7
+ from sqlpiston.core.engine.base import Connection, Cursor, Engine
8
+
9
+
10
+ class SQLiteCursor(Cursor):
11
+ def __init__(self, raw_cursor: sqlite3.Cursor) -> None:
12
+ self._cursor = raw_cursor
13
+
14
+ def fetchall(self) -> List[Tuple[SQLValue, ...]]:
15
+ return [tuple(row) for row in self._cursor.fetchall()]
16
+
17
+ def fetchone(self) -> Optional[Tuple[SQLValue, ...]]:
18
+ row = self._cursor.fetchone()
19
+ return tuple(row) if row else None
20
+
21
+ @property
22
+ def rowcount(self) -> int:
23
+ return self._cursor.rowcount
24
+
25
+ @property
26
+ def description(self) -> List[Tuple[str, int, Any, Any, Any, Any, Any]]:
27
+ desc = self._cursor.description
28
+ if desc is None:
29
+ return []
30
+ return cast(List[Tuple[str, int, Any, Any, Any, Any, Any]], [tuple(d) for d in desc])
31
+
32
+
33
+ class SQLiteConnection(Connection):
34
+ def __init__(self, raw_conn: sqlite3.Connection) -> None:
35
+ self._conn = raw_conn
36
+
37
+ def execute(self, sql: str, params: Tuple[ExprValue, ...]) -> SQLiteCursor:
38
+ cursor = self._conn.cursor()
39
+ cursor.execute(sql, params)
40
+ return SQLiteCursor(cursor)
41
+
42
+ def begin(self) -> None:
43
+ self._conn.execute("BEGIN")
44
+
45
+ def commit(self) -> None:
46
+ self._conn.commit()
47
+
48
+ def rollback(self) -> None:
49
+ self._conn.rollback()
50
+
51
+ def close(self) -> None:
52
+ self._conn.close()
53
+
54
+
55
+ class SQLiteEngine(Engine):
56
+ def __init__(self) -> None:
57
+ self._file_path: Optional[str] = None
58
+ self._conn: Optional[sqlite3.Connection] = None
59
+
60
+ def init_engine(self, file_path: str) -> None:
61
+ self._file_path = file_path
62
+
63
+ @property
64
+ def dialect(self) -> SQLiteDialect:
65
+ return SQLiteDialect()
66
+
67
+ def connect(self) -> SQLiteConnection:
68
+ if self._file_path is None:
69
+ raise RuntimeError("Call init_engine() before connect()")
70
+ self._conn = sqlite3.connect(self._file_path)
71
+ return SQLiteConnection(self._conn)
72
+
73
+ def close(self) -> None:
74
+ if self._conn:
75
+ self._conn.close()
76
+ self._conn = None
sqlpiston/core/pool.py ADDED
@@ -0,0 +1,49 @@
1
+ import threading
2
+ from typing import Any, List
3
+
4
+ from sqlpiston.core.engine.base import Connection, Engine
5
+
6
+
7
+ class ConnectionPool:
8
+ """Thread-safe connection pool."""
9
+
10
+ def __init__(self, engine: Engine, min_size: int = 1, max_size: int = 10) -> None:
11
+ self._engine = engine
12
+ self._min_size = min_size
13
+ self._max_size = max_size
14
+ self._lock = threading.Lock()
15
+ self._available: List[Connection] = []
16
+ self._in_use: int = 0
17
+
18
+ for _ in range(min_size):
19
+ self._available.append(engine.connect())
20
+
21
+ def acquire(self) -> Connection:
22
+ with self._lock:
23
+ if self._available:
24
+ conn = self._available.pop()
25
+ self._in_use += 1
26
+ return conn
27
+ if self._in_use >= self._max_size:
28
+ raise RuntimeError("Connection pool exhausted")
29
+ conn = self._engine.connect()
30
+ self._in_use += 1
31
+ return conn
32
+
33
+ def release(self, conn: Connection) -> None:
34
+ with self._lock:
35
+ self._in_use -= 1
36
+ self._available.append(conn)
37
+
38
+ def close(self) -> None:
39
+ with self._lock:
40
+ for conn in self._available:
41
+ conn.close()
42
+ self._available.clear()
43
+ self._in_use = 0
44
+
45
+ def __enter__(self) -> 'ConnectionPool':
46
+ return self
47
+
48
+ def __exit__(self, *args: Any) -> None:
49
+ self.close()
@@ -0,0 +1,61 @@
1
+ from typing import Any, Optional
2
+
3
+ from sqlpiston.builder.nodes import ASTNode
4
+ from sqlpiston.core.engine.base import Connection, Engine
5
+ from sqlpiston.core.pool import ConnectionPool
6
+ from sqlpiston.orm.mapper import ResultSet
7
+
8
+
9
+ class Session:
10
+ """Entry point for users. Binds engine, compiles AST, executes SQL.
11
+
12
+ Usage::
13
+
14
+ s = Session(engine)
15
+ result = s.execute(
16
+ Select().select('id', 'name').from_table('users').where(Field('age') >= 18)
17
+ )
18
+ s.commit()
19
+ s.close()
20
+ """
21
+
22
+ def __init__(self, engine: Engine, pool: Optional[ConnectionPool] = None) -> None:
23
+ self._engine = engine
24
+ self._pool = pool if pool is not None else ConnectionPool(engine)
25
+ self._current_conn: Optional[Connection] = None
26
+
27
+ def _get_conn(self) -> Connection:
28
+ if self._current_conn is None:
29
+ self._current_conn = self._pool.acquire()
30
+ return self._current_conn
31
+
32
+ def execute(self, stmt: ASTNode) -> ResultSet:
33
+ conn = self._get_conn()
34
+ sql, params = stmt.compile(self._engine.dialect)
35
+ cursor = conn.execute(sql, params)
36
+ column_names = [desc[0] for desc in cursor.description] if cursor.description else []
37
+ return ResultSet(cursor, column_names)
38
+
39
+ def begin(self) -> None:
40
+ conn = self._get_conn()
41
+ conn.begin()
42
+
43
+ def commit(self) -> None:
44
+ if self._current_conn:
45
+ self._current_conn.commit()
46
+
47
+ def rollback(self) -> None:
48
+ if self._current_conn:
49
+ self._current_conn.rollback()
50
+
51
+ def close(self) -> None:
52
+ if self._current_conn:
53
+ self._pool.release(self._current_conn)
54
+ self._current_conn = None
55
+ self._pool.close()
56
+
57
+ def __enter__(self) -> 'Session':
58
+ return self
59
+
60
+ def __exit__(self, *args: Any) -> None:
61
+ self.close()
File without changes
@@ -0,0 +1,68 @@
1
+ from typing import (
2
+ Any, Dict, Iterator, List, Optional, Type, TypeVar,
3
+ )
4
+
5
+ from sqlpiston._types import SQLValue
6
+ from sqlpiston.core.engine.base import Cursor
7
+
8
+ T = TypeVar('T')
9
+
10
+
11
+ class ResultSet:
12
+ """Iterable set of mapped results from a query."""
13
+
14
+ def __init__(self, cursor: Cursor, column_names: List[str]) -> None:
15
+ self._cursor = cursor
16
+ self._column_names = column_names
17
+
18
+ def all(self) -> List[Dict[str, SQLValue]]:
19
+ rows = self._cursor.fetchall()
20
+ return [dict(zip(self._column_names, row)) for row in rows]
21
+
22
+ def one(self) -> Dict[str, SQLValue]:
23
+ rows = self.all()
24
+ if len(rows) == 0:
25
+ raise ValueError("Expected exactly one row, got none")
26
+ if len(rows) > 1:
27
+ raise ValueError(f"Expected exactly one row, got {len(rows)}")
28
+ return rows[0]
29
+
30
+ def one_or_none(self) -> Optional[Dict[str, SQLValue]]:
31
+ rows = self.all()
32
+ if len(rows) == 0:
33
+ return None
34
+ if len(rows) > 1:
35
+ raise ValueError(f"Expected at most one row, got {len(rows)}")
36
+ return rows[0]
37
+
38
+ def first(self) -> Optional[Dict[str, SQLValue]]:
39
+ row = self._cursor.fetchone()
40
+ if row is None:
41
+ return None
42
+ return dict(zip(self._column_names, row))
43
+
44
+ def scalar(self) -> Any:
45
+ row = self._cursor.fetchone()
46
+ if row is None:
47
+ raise ValueError("Expected at least one row for scalar(), got none")
48
+ return row[0]
49
+
50
+ def map(self, target: Type[T]) -> List[T]:
51
+ rows = self.all()
52
+ results: List[T] = []
53
+ for row in rows:
54
+ obj = target(**row)
55
+ results.append(obj)
56
+ return results
57
+
58
+ def map_one(self, target: Type[T]) -> T:
59
+ row = self.one()
60
+ return target(**row)
61
+
62
+ def __iter__(self) -> Iterator[Dict[str, SQLValue]]:
63
+ all_rows = self.all()
64
+ return iter(all_rows)
65
+
66
+ @property
67
+ def rowcount(self) -> int:
68
+ return self._cursor.rowcount
@@ -0,0 +1,180 @@
1
+ Metadata-Version: 2.4
2
+ Name: sqlpiston
3
+ Version: 0.1.0
4
+ Summary: A low-level SQL library that builds parameterized SQL queries through Python operator overloading
5
+ Author: MuliMuri
6
+ License: MIT
7
+ Keywords: sql,query-builder,orm,mysql,sqlite
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Database
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=8; extra == "dev"
23
+ Requires-Dist: coverage>=7; extra == "dev"
24
+ Requires-Dist: flake8>=7; extra == "dev"
25
+ Requires-Dist: mypy>=1; extra == "dev"
26
+ Dynamic: license-file
27
+
28
+ # SQLPiston
29
+
30
+ [![test](https://github.com/MuliMuri/sqlpiston/actions/workflows/test.yml/badge.svg)](https://github.com/MuliMuri/sqlpiston/actions/workflows/test.yml)
31
+ [![lint](https://github.com/MuliMuri/sqlpiston/actions/workflows/lint.yml/badge.svg)](https://github.com/MuliMuri/sqlpiston/actions/workflows/lint.yml)
32
+ [![coverage](https://codecov.io/gh/MuliMuri/sqlpiston/branch/main/graph/badge.svg)](https://codecov.io/gh/MuliMuri/sqlpiston)
33
+ [![pypi](https://img.shields.io/pypi/v/sqlpiston.svg)](https://pypi.org/project/sqlpiston/)
34
+ [![python](https://img.shields.io/pypi/pyversions/sqlpiston)](https://pypi.org/project/sqlpiston/)
35
+ [![license](https://img.shields.io/github/license/MuliMuri/sqlpiston)](https://github.com/MuliMuri/sqlpiston/blob/main/LICENSE)
36
+
37
+ *Write once, query everywhere — build SQL with Python operators.*
38
+
39
+ [中文版](README_ZH.md)
40
+
41
+ SQLPiston is a low-level SQL library that builds parameterized SQL queries
42
+ through Python operator overloading. AST nodes carry zero SQL knowledge;
43
+ dialect-specific compilers translate the same AST into the right SQL for each
44
+ database.
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ git clone https://github.com/MuliMuri/sqlpiston.git
50
+ cd sqlpiston
51
+ pip install -e .
52
+ ```
53
+
54
+ Python 3.9+ on Linux / macOS / Windows.
55
+
56
+ ## Basic Usage
57
+
58
+ ```python
59
+ from sqlpiston import Select, Field, Insert
60
+ from sqlpiston import DBEngine, DBType, Session
61
+ from dataclasses import dataclass
62
+
63
+ eng = DBEngine(DBType.SQLite)
64
+ eng.init_engine(":memory:")
65
+ session = Session(eng)
66
+
67
+ stmt = (
68
+ Select()
69
+ .select("id", "name", "age")
70
+ .from_table("users")
71
+ .where((Field("age") >= 18) & (Field("status") == "active"))
72
+ .order_by("id", "ASC")
73
+ .limit(10)
74
+ )
75
+ result = session.execute(stmt)
76
+
77
+ @dataclass
78
+ class User:
79
+ id: int
80
+ name: str
81
+ age: int
82
+
83
+ users = result.map(User)
84
+
85
+ session.execute(
86
+ Insert().into("users").values({"name": "Alice", "age": 25})
87
+ )
88
+
89
+ session.commit()
90
+ session.close()
91
+ ```
92
+
93
+ <details>
94
+ <summary>More examples: JOIN, subquery, CTE, UPSERT, DDL</summary>
95
+
96
+ **JOIN**
97
+
98
+ ```python
99
+ Select() \
100
+ .select("users.name", "orders.total") \
101
+ .from_table("users") \
102
+ .join("orders",
103
+ Field("user_id", "orders") == Field("id", "users")) \
104
+ .where(Field("total", "orders") > 100)
105
+ ```
106
+
107
+ **Subquery (IN / EXISTS / Scalar)**
108
+
109
+ ```python
110
+ # IN subquery
111
+ admin_ids = Select().select("id").from_table("admins")
112
+ stmt = Select().select("name").from_table("users") \
113
+ .where(Field("id").is_in(admin_ids))
114
+
115
+ # EXISTS
116
+ sub = Select().select("1").from_table("orders") \
117
+ .where(Field("user_id", "orders") == Field("id", "users"))
118
+ stmt = Select().select("name").from_table("users").where(sub.exists())
119
+
120
+ # Scalar
121
+ avg = Select().select(SQLFunction("avg", "salary")).from_table("employees")
122
+ stmt = Select().select("name").from_table("staff").where(Field("salary") > avg)
123
+ ```
124
+
125
+ **CTE**
126
+
127
+ ```python
128
+ cte = Select().select("*").from_table("sales") \
129
+ .where(Field("amount") > 100).cte("big_sales")
130
+ stmt = Select().with_(cte).select("*").from_table("big_sales")
131
+ ```
132
+
133
+ **UPSERT — same AST, different SQL per dialect**
134
+
135
+ ```python
136
+ Upsert() \
137
+ .into("users") \
138
+ .values({"id": 1, "name": "X"}) \
139
+ .on_conflict("id") \
140
+ .do_update({"name": "X"})
141
+ ```
142
+
143
+ | Dialect | Generated SQL |
144
+ |---------|--------------|
145
+ | MySQL | `INSERT INTO ... ON DUPLICATE KEY UPDATE` |
146
+ | SQLite | `INSERT INTO ... ON CONFLICT DO UPDATE` |
147
+
148
+ **DDL**
149
+
150
+ ```python
151
+ CreateTable().table("users").if_not_exists() \
152
+ .column("id", "INTEGER", primary_key=True, nullable=False) \
153
+ .column("name", "VARCHAR(255)")
154
+
155
+ AlterTable().table("users").add_column("age", "INTEGER", default=0)
156
+
157
+ DropTable().table("users").if_exists()
158
+ ```
159
+
160
+ </details>
161
+
162
+ ## Highlights
163
+
164
+ - **Operator overloading** — `Field("age") >= 18` builds AST, not a boolean
165
+ - **Dialect-aware** — same AST compiles to MySQL (%s, backticks) or SQLite (?, double-quotes)
166
+ - **Full standard SQL** — SELECT, INSERT, UPDATE, DELETE, UPSERT, CTE, UNION, subqueries, DDL
167
+ - **Parameterized by design** — values never interpolated into SQL strings
168
+ - **Weak ORM** — result-to-dataclass mapping, no identity map or change tracking
169
+
170
+ ## Documentation
171
+
172
+ ```bash
173
+ cd docs
174
+ pip install -r requirements.txt
175
+ sphinx-build -b html source build/html
176
+ ```
177
+
178
+ ## License
179
+
180
+ MIT
@@ -0,0 +1,25 @@
1
+ sqlpiston/__init__.py,sha256=3ghxUHksL7Hf7K7z32-qK-X6hK6GmjLo5uEhVetOMEg,1054
2
+ sqlpiston/_types.py,sha256=khQZ0rFi-wAxXF829o6Pj_GQEOfWqZt0uLTirIA0amA,125
3
+ sqlpiston/builder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ sqlpiston/builder/ddl.py,sha256=LwzUlJLhh163ndZoJ7yPSW2Wz8gSzErJ-jsqXnV7_QI,6414
5
+ sqlpiston/builder/dml.py,sha256=pkU5pINsQown4UY04I44mICPvgLxXUF4NRlZGiWu0Eo,3540
6
+ sqlpiston/builder/nodes.py,sha256=XP30lmbUlHWnPT0_qvXMuAkUkN2SnuxDEnf4oIAARDA,8072
7
+ sqlpiston/builder/selectable.py,sha256=B7c0hogEiFyyu3SRzdm85Ok4xU3fhy7VfMZwgKlQ638,5010
8
+ sqlpiston/compiler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ sqlpiston/compiler/base.py,sha256=iSVVLK8NEjnxEhE0vjI_iRdpOBjFv5nIk1kAVqerAAg,24502
10
+ sqlpiston/compiler/mysql.py,sha256=cbixJVUae699ht9Hx7zm5xqLcvSvhNPiRiPH9MkBJRI,2007
11
+ sqlpiston/compiler/sqlite.py,sha256=ccRxvrnaIXzwz6xt1jjdstbQfUaAuQN-BJKxj5UrlMk,2134
12
+ sqlpiston/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ sqlpiston/core/pool.py,sha256=g69X70znqPgKjk_XNQm8w6I61KyV8IDVrQtPXrW3aHA,1434
14
+ sqlpiston/core/session.py,sha256=1YMpdRE-kdaYkfgMTy-G2ZqGJMlmgP_feyyv96UBbHk,1861
15
+ sqlpiston/core/engine/__init__.py,sha256=BTeVrKTDJuE_EENZKLv-UEkIo4d2MynUBA9xwkTNzvk,90
16
+ sqlpiston/core/engine/base.py,sha256=Vc72j9B4dhwChnAoCN4K3ukNXb2E_ofUuafNIqCALFo,2347
17
+ sqlpiston/core/engine/mysql.py,sha256=Ofb_Lo_0bNhun3jD27lUnXwSL9V-I5gkpRXHJgM861c,2734
18
+ sqlpiston/core/engine/sqlite.py,sha256=s_QKIp2V7sBF4myvuNMrYlgUg-3jwyur2IFyDVD46A4,2273
19
+ sqlpiston/orm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ sqlpiston/orm/mapper.py,sha256=VzL9Hj-7jIS6eNKWhJvZ4RYSB7CjSnl8wsCZvU2xnBk,2010
21
+ sqlpiston-0.1.0.dist-info/licenses/LICENSE,sha256=FKq1ES92GFfgEWVFaOrUwjYp5Vw1Ax7erfJD-hf8-T0,1065
22
+ sqlpiston-0.1.0.dist-info/METADATA,sha256=hYCIoJfNuP0CCOMcxW2H6dj8YSrgyiRHMh6WPXt_S1w,5206
23
+ sqlpiston-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
24
+ sqlpiston-0.1.0.dist-info/top_level.txt,sha256=FrpiXMbeu-XF58dz1QZcE1FRBGK-GY2oA_m-E0uEtBw,10
25
+ sqlpiston-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 MuliMuri
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.
@@ -0,0 +1 @@
1
+ sqlpiston