sqla-fancy-core 0.2.0__py3-none-any.whl → 1.0.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.

Potentially problematic release.


This version of sqla-fancy-core might be problematic. Click here for more details.

@@ -1,13 +1,18 @@
1
1
  """SQLAlchemy core, but fancier."""
2
2
 
3
+ from typing import Optional, Union, overload
4
+
3
5
  import sqlalchemy as sa
4
6
 
5
7
 
6
8
  class TableFactory:
7
9
  """A factory for creating SQLAlchemy columns with default values."""
8
10
 
9
- def __init__(self):
11
+ def __init__(self, metadata: Optional[sa.MetaData] = None):
10
12
  """Initialize the factory with default values."""
13
+ if metadata is None:
14
+ metadata = sa.MetaData()
15
+ self.metadata = metadata
11
16
  self.c = []
12
17
 
13
18
  def col(self, *args, **kwargs) -> sa.Column:
@@ -66,7 +71,7 @@ class TableFactory:
66
71
  def false(self, name: str, *args, **kwargs):
67
72
  return self.boolean(name, default=False, *args, **kwargs)
68
73
 
69
- def foreign_key(self, name: str, ref: str | sa.Column, *args, **kwargs):
74
+ def foreign_key(self, name: str, ref: Union[str, sa.Column], *args, **kwargs):
70
75
  return self.col(name, sa.ForeignKey(ref), *args, **kwargs)
71
76
 
72
77
  def enum(self, name: str, enum: type, *args, **kwargs) -> sa.Column:
@@ -130,7 +135,25 @@ class TableFactory:
130
135
  def created_at(self, name="created_at", *args, **kwargs) -> sa.Column:
131
136
  return self.datetime(name, default=sa.func.now(), *args, **kwargs)
132
137
 
133
- def __call__(self, name, metadata, *args, **kwargs):
134
- cols = self.c
135
- self.c = []
136
- return sa.Table(name, metadata, *args, *cols, **kwargs)
138
+ @overload
139
+ def __call__(self, arg1: str, *args, **kwargs) -> sa.Table: ...
140
+ @overload
141
+ def __call__(self, arg1: sa.Column, *args, **kwargs) -> sa.Column: ...
142
+ @overload
143
+ def __call__(self, arg1: sa.Table, *args, **kwargs) -> sa.Table: ...
144
+ def __call__(self, arg1, *args, **kwargs):
145
+ if isinstance(arg1, str):
146
+ cols = self.c
147
+ self.c = []
148
+ return sa.Table(arg1, self.metadata, *args, *cols, **kwargs)
149
+ elif isinstance(arg1, sa.Column):
150
+ arg1.info["args"] = args
151
+ arg1.info["kwargs"] = kwargs
152
+ self.c.append(arg1)
153
+ return arg1
154
+ elif isinstance(arg1, sa.Table):
155
+ cols = self.c
156
+ self.c = []
157
+ return sa.Table(arg1.name, self.metadata, *args, *cols, **kwargs)
158
+ else:
159
+ raise TypeError(f"Expected a string or Column, got {type(arg1).__name__}")
@@ -0,0 +1,192 @@
1
+ Metadata-Version: 2.4
2
+ Name: sqla-fancy-core
3
+ Version: 1.0.0
4
+ Summary: SQLAlchemy core, but fancier
5
+ Project-URL: Homepage, https://github.com/sayanarijit/sqla-fancy-core
6
+ Author-email: Arijit Basu <sayanarijit@gmail.com>
7
+ Maintainer-email: Arijit Basu <sayanarijit@gmail.com>
8
+ License: MIT License
9
+
10
+ Copyright (c) 2023 Arijit Basu
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
29
+ License-File: LICENSE
30
+ Keywords: sql,sqlalchemy,sqlalchemy-core
31
+ Classifier: Intended Audience :: Developers
32
+ Classifier: License :: OSI Approved :: MIT License
33
+ Classifier: Programming Language :: Python :: 3
34
+ Requires-Python: >=3.7
35
+ Requires-Dist: sqlalchemy
36
+ Provides-Extra: test
37
+ Requires-Dist: flake8; extra == 'test'
38
+ Requires-Dist: pydantic; extra == 'test'
39
+ Requires-Dist: pytest; extra == 'test'
40
+ Description-Content-Type: text/markdown
41
+
42
+ # sqla-fancy-core
43
+
44
+ SQLAlchemy core, but fancier.
45
+
46
+ ### Basic Usage
47
+
48
+ ```python
49
+ import sqlalchemy as sa
50
+ from sqla_fancy_core import TableFactory
51
+
52
+ tf = TableFactory()
53
+
54
+ # Define a table
55
+ class Author:
56
+
57
+ id = tf.auto_id()
58
+ name = tf.string("name")
59
+ created_at = tf.created_at()
60
+ updated_at = tf.updated_at()
61
+
62
+ Table = tf("author")
63
+
64
+ # Or define it without losing type hints
65
+ class Book:
66
+ id = tf(sa.Column("id", sa.Integer, primary_key=True, autoincrement=True))
67
+ title = tf(sa.Column("title", sa.String(255), nullable=False))
68
+ author_id = tf(sa.Column("author_id", sa.Integer, sa.ForeignKey(Author.id)))
69
+ created_at = tf(
70
+ sa.Column(
71
+ "created_at",
72
+ sa.DateTime,
73
+ nullable=False,
74
+ server_default=sa.func.now(),
75
+ )
76
+ )
77
+ updated_at = tf(
78
+ sa.Column(
79
+ "updated_at",
80
+ sa.DateTime,
81
+ nullable=False,
82
+ server_default=sa.func.now(),
83
+ onupdate=sa.func.now(),
84
+ )
85
+ )
86
+
87
+ Table = tf(sa.Table("book", sa.MetaData()))
88
+
89
+ # Create the tables
90
+ engine = sa.create_engine("sqlite:///:memory:")
91
+ tf.metadata.create_all(engine)
92
+
93
+ with engine.connect() as conn:
94
+ # Insert author
95
+ qry = (
96
+ sa.insert(Author.Table)
97
+ .values({Author.name: "John Doe"})
98
+ .returning(Author.id)
99
+ )
100
+ author = next(conn.execute(qry).mappings())
101
+ author_id = author[Author.id]
102
+ assert author_id == 1
103
+
104
+ # Insert book
105
+ qry = (
106
+ sa.insert(Book.Table)
107
+ .values({Book.title: "My Book", Book.author_id: author_id})
108
+ .returning(Book.id)
109
+ )
110
+ book = next(conn.execute(qry).mappings())
111
+ assert book[Book.id] == 1
112
+
113
+ # Query the data
114
+ qry = sa.select(Author.name, Book.title).join(
115
+ Book.Table,
116
+ Book.author_id == Author.id,
117
+ )
118
+ result = conn.execute(qry).fetchall()
119
+ assert result == [("John Doe", "My Book")], result
120
+
121
+ # Create the tables
122
+ engine = sa.create_engine("sqlite:///:memory:")
123
+ tf.metadata.create_all(engine)
124
+
125
+ with engine.connect() as conn:
126
+ # Insert author
127
+ qry = (
128
+ sa.insert(Author.Table)
129
+ .values({Author.name: "John Doe"})
130
+ .returning(Author.id)
131
+ )
132
+ author = next(conn.execute(qry).mappings())
133
+ author_id = author[Author.id]
134
+ assert author_id == 1
135
+
136
+ # Insert book
137
+ qry = (
138
+ sa.insert(Book.Table)
139
+ .values({Book.title: "My Book", Book.author_id: author_id})
140
+ .returning(Book.id)
141
+ )
142
+ book = next(conn.execute(qry).mappings())
143
+ assert book[Book.id] == 1
144
+
145
+ # Query the data
146
+ qry = sa.select(Author.name, Book.title).join(
147
+ Book.Table,
148
+ Book.author_id == Author.id,
149
+ )
150
+ result = conn.execute(qry).fetchall()
151
+ assert result == [("John Doe", "My Book")], result
152
+ ```
153
+
154
+ ### With Pydantic Validation
155
+
156
+ ```python
157
+ from typing import Any
158
+ import sqlalchemy as sa
159
+ from pydantic import BaseModel, Field
160
+
161
+ from sqla_fancy_core import TableFactory
162
+
163
+ tf = TableFactory()
164
+
165
+ def field(col, default: Any = ...) -> Field:
166
+ return col.info["kwargs"]["field"](default)
167
+
168
+ # Define a table
169
+ class User:
170
+ name = tf(
171
+ sa.Column("name", sa.String),
172
+ field=lambda default: Field(default, max_length=5),
173
+ )
174
+ Table = tf("author")
175
+
176
+ # Define a pydantic schema
177
+ class CreateUser(BaseModel):
178
+ name: str = field(User.name)
179
+
180
+ # Define a pydantic schema
181
+ class UpdateUser(BaseModel):
182
+ name: str | None = field(User.name, None)
183
+
184
+ assert CreateUser(name="John").model_dump() == {"name": "John"}
185
+ assert UpdateUser(name="John").model_dump() == {"name": "John"}
186
+ assert UpdateUser().model_dump(exclude_unset=True) == {}
187
+
188
+ with pytest.raises(ValueError):
189
+ CreateUser()
190
+ with pytest.raises(ValueError):
191
+ UpdateUser(name="John Doe")
192
+ ```
@@ -0,0 +1,5 @@
1
+ sqla_fancy_core/__init__.py,sha256=GwPbjEPhM-mxFcsjZizCQ9dnUNgqBswCfwrI_u-JVfc,6376
2
+ sqla_fancy_core-1.0.0.dist-info/METADATA,sha256=1UBn6tJ7EK6TXKBdq6gUWtzStIqeHS3lsKDb9pkZBCE,5671
3
+ sqla_fancy_core-1.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
4
+ sqla_fancy_core-1.0.0.dist-info/licenses/LICENSE,sha256=XcYXJ0ipvwOn-nzko6p_xoCCbke8tAhmlIN04rUZDLk,1068
5
+ sqla_fancy_core-1.0.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.3.2
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,86 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: sqla-fancy-core
3
- Version: 0.2.0
4
- Summary: SQLAlchemy core, but fancier
5
- License: MIT
6
- Keywords: sql,sqlalchemy,sqlalchemy-core
7
- Author: Arijit Basu
8
- Author-email: sayanarijit@gmail.com
9
- Requires-Python: >=3.7,<4.0
10
- Classifier: License :: OSI Approved :: MIT License
11
- Classifier: Programming Language :: Python :: 3
12
- Classifier: Programming Language :: Python :: 3.7
13
- Classifier: Programming Language :: Python :: 3.8
14
- Classifier: Programming Language :: Python :: 3.9
15
- Classifier: Programming Language :: Python :: 3.10
16
- Classifier: Programming Language :: Python :: 3.11
17
- Requires-Dist: sqlalchemy
18
- Description-Content-Type: text/markdown
19
-
20
- # sqla-fancy-core
21
-
22
- SQLAlchemy core, but fancier.
23
-
24
- ```python
25
- import sqlalchemy as sa
26
-
27
- from sqla_fancy_core import TableFactory
28
-
29
- metadata = sa.MetaData()
30
- tf = TableFactory()
31
-
32
- # Define a table
33
- class Author:
34
-
35
- id = tf.auto_id()
36
- name = tf.string("name")
37
- created_at = tf.created_at()
38
- updated_at = tf.updated_at()
39
-
40
- Table = tf("author", metadata)
41
-
42
- # Define a table
43
- class Book:
44
-
45
- id = tf.auto_id()
46
- title = tf.string("title")
47
- author_id = tf.foreign_key("author_id", Author.id)
48
- created_at = tf.created_at()
49
- updated_at = tf.updated_at()
50
-
51
- Table = tf("book", metadata)
52
-
53
- # Create the tables
54
- engine = sa.create_engine("sqlite:///:memory:")
55
- metadata.create_all(engine)
56
-
57
- with engine.connect() as conn:
58
- # Insert author
59
- qry = (
60
- sa.insert(Author.Table)
61
- .values({Author.name: "John Doe"})
62
- .returning(Author.id)
63
- )
64
- author = next(conn.execute(qry))
65
- (author_id,) = author
66
- assert author_id == 1
67
-
68
- # Insert book
69
- qry = (
70
- sa.insert(Book.Table)
71
- .values({Book.title: "My Book", Book.author_id: author_id})
72
- .returning(Book.id)
73
- )
74
- book = next(conn.execute(qry))
75
- (book_id,) = book
76
- assert book_id == 1
77
-
78
- # Query the data
79
- qry = sa.select(Author.name, Book.title).join(
80
- Book.Table,
81
- Book.author_id == Author.id,
82
- )
83
- result = conn.execute(qry).fetchall()
84
- assert result == [("John Doe", "My Book")], result
85
- ```
86
-
@@ -1,5 +0,0 @@
1
- sqla_fancy_core/__init__.py,sha256=W9JptGiRc9guGhP--bUgNumEOzlcgumsxNyyYU0H9wY,5440
2
- sqla_fancy_core-0.2.0.dist-info/LICENSE,sha256=XcYXJ0ipvwOn-nzko6p_xoCCbke8tAhmlIN04rUZDLk,1068
3
- sqla_fancy_core-0.2.0.dist-info/WHEEL,sha256=vxFmldFsRN_Hx10GDvsdv1wroKq8r5Lzvjp6GZ4OO8c,88
4
- sqla_fancy_core-0.2.0.dist-info/METADATA,sha256=CyBVCb2pPAi3kHY7R0ZIR9fgi0F4edN6F_E9lmlnv8U,2093
5
- sqla_fancy_core-0.2.0.dist-info/RECORD,,