iceaxe 0.7.1__cp313-cp313-macosx_11_0_arm64.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 iceaxe might be problematic. Click here for more details.
- iceaxe/__init__.py +20 -0
- iceaxe/__tests__/__init__.py +0 -0
- iceaxe/__tests__/benchmarks/__init__.py +0 -0
- iceaxe/__tests__/benchmarks/test_bulk_insert.py +45 -0
- iceaxe/__tests__/benchmarks/test_select.py +114 -0
- iceaxe/__tests__/conf_models.py +133 -0
- iceaxe/__tests__/conftest.py +204 -0
- iceaxe/__tests__/docker_helpers.py +208 -0
- iceaxe/__tests__/helpers.py +268 -0
- iceaxe/__tests__/migrations/__init__.py +0 -0
- iceaxe/__tests__/migrations/conftest.py +36 -0
- iceaxe/__tests__/migrations/test_action_sorter.py +237 -0
- iceaxe/__tests__/migrations/test_generator.py +140 -0
- iceaxe/__tests__/migrations/test_generics.py +91 -0
- iceaxe/__tests__/mountaineer/__init__.py +0 -0
- iceaxe/__tests__/mountaineer/dependencies/__init__.py +0 -0
- iceaxe/__tests__/mountaineer/dependencies/test_core.py +76 -0
- iceaxe/__tests__/schemas/__init__.py +0 -0
- iceaxe/__tests__/schemas/test_actions.py +1264 -0
- iceaxe/__tests__/schemas/test_cli.py +25 -0
- iceaxe/__tests__/schemas/test_db_memory_serializer.py +1525 -0
- iceaxe/__tests__/schemas/test_db_serializer.py +398 -0
- iceaxe/__tests__/schemas/test_db_stubs.py +190 -0
- iceaxe/__tests__/test_alias.py +83 -0
- iceaxe/__tests__/test_base.py +52 -0
- iceaxe/__tests__/test_comparison.py +383 -0
- iceaxe/__tests__/test_field.py +11 -0
- iceaxe/__tests__/test_helpers.py +9 -0
- iceaxe/__tests__/test_modifications.py +151 -0
- iceaxe/__tests__/test_queries.py +605 -0
- iceaxe/__tests__/test_queries_str.py +173 -0
- iceaxe/__tests__/test_session.py +1511 -0
- iceaxe/__tests__/test_text_search.py +287 -0
- iceaxe/alias_values.py +67 -0
- iceaxe/base.py +350 -0
- iceaxe/comparison.py +560 -0
- iceaxe/field.py +250 -0
- iceaxe/functions.py +906 -0
- iceaxe/generics.py +140 -0
- iceaxe/io.py +107 -0
- iceaxe/logging.py +91 -0
- iceaxe/migrations/__init__.py +5 -0
- iceaxe/migrations/action_sorter.py +98 -0
- iceaxe/migrations/cli.py +228 -0
- iceaxe/migrations/client_io.py +62 -0
- iceaxe/migrations/generator.py +404 -0
- iceaxe/migrations/migration.py +86 -0
- iceaxe/migrations/migrator.py +101 -0
- iceaxe/modifications.py +176 -0
- iceaxe/mountaineer/__init__.py +10 -0
- iceaxe/mountaineer/cli.py +74 -0
- iceaxe/mountaineer/config.py +46 -0
- iceaxe/mountaineer/dependencies/__init__.py +6 -0
- iceaxe/mountaineer/dependencies/core.py +67 -0
- iceaxe/postgres.py +133 -0
- iceaxe/py.typed +0 -0
- iceaxe/queries.py +1455 -0
- iceaxe/queries_str.py +294 -0
- iceaxe/schemas/__init__.py +0 -0
- iceaxe/schemas/actions.py +864 -0
- iceaxe/schemas/cli.py +30 -0
- iceaxe/schemas/db_memory_serializer.py +705 -0
- iceaxe/schemas/db_serializer.py +346 -0
- iceaxe/schemas/db_stubs.py +525 -0
- iceaxe/session.py +860 -0
- iceaxe/session_optimized.c +12035 -0
- iceaxe/session_optimized.cpython-313-darwin.so +0 -0
- iceaxe/session_optimized.pyx +212 -0
- iceaxe/sql_types.py +148 -0
- iceaxe/typing.py +73 -0
- iceaxe-0.7.1.dist-info/METADATA +261 -0
- iceaxe-0.7.1.dist-info/RECORD +75 -0
- iceaxe-0.7.1.dist-info/WHEEL +6 -0
- iceaxe-0.7.1.dist-info/licenses/LICENSE +21 -0
- iceaxe-0.7.1.dist-info/top_level.txt +1 -0
iceaxe/modifications.py
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import traceback
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Literal, Sequence, TypeVar
|
|
5
|
+
|
|
6
|
+
from iceaxe.base import TableBase
|
|
7
|
+
from iceaxe.logging import LOGGER
|
|
8
|
+
|
|
9
|
+
MODIFICATION_TRACKER_VERBOSITY = Literal["ERROR", "WARNING", "INFO"] | None
|
|
10
|
+
T = TypeVar("T", bound=TableBase)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class Modification:
|
|
15
|
+
"""
|
|
16
|
+
Tracks a single modification to a database model instance, including stack trace information.
|
|
17
|
+
|
|
18
|
+
This class stores both the full stack trace and a simplified user-specific stack trace
|
|
19
|
+
that excludes library code. This helps with debugging by showing where in the user's
|
|
20
|
+
code a modification was made.
|
|
21
|
+
|
|
22
|
+
:param instance: The model instance that was modified
|
|
23
|
+
:param stack_trace: The complete stack trace at the time of modification
|
|
24
|
+
:param user_stack_trace: The most relevant user code stack trace, excluding library code
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
instance: TableBase
|
|
28
|
+
|
|
29
|
+
# The full stack trace of the modification.
|
|
30
|
+
stack_trace: str
|
|
31
|
+
|
|
32
|
+
# Most specific line of the stack trace that is part of the user's code.
|
|
33
|
+
user_stack_trace: str
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def get_current_stack_trace(
|
|
37
|
+
package_allow_list: list[str] | None = None,
|
|
38
|
+
package_deny_list: list[str] | None = None,
|
|
39
|
+
) -> tuple[str, str]:
|
|
40
|
+
"""
|
|
41
|
+
Get both the full stack trace and the most specific user code stack trace.
|
|
42
|
+
|
|
43
|
+
The user stack trace filters out library code and frozen code to focus on
|
|
44
|
+
the most relevant user code location where a modification occurred.
|
|
45
|
+
|
|
46
|
+
:return: A tuple containing (full_stack_trace, user_stack_trace)
|
|
47
|
+
:rtype: tuple[str, str]
|
|
48
|
+
"""
|
|
49
|
+
stack = traceback.extract_stack()[:-1] # Remove the current frame
|
|
50
|
+
full_trace = "".join(traceback.format_list(stack))
|
|
51
|
+
|
|
52
|
+
# Find the most specific user code stack trace by filtering out library code
|
|
53
|
+
user_traces = [
|
|
54
|
+
frame
|
|
55
|
+
for frame in stack
|
|
56
|
+
if (
|
|
57
|
+
package_allow_list is None
|
|
58
|
+
or any(pkg in frame.filename for pkg in package_allow_list)
|
|
59
|
+
)
|
|
60
|
+
and (
|
|
61
|
+
package_deny_list is None
|
|
62
|
+
or not any(pkg in frame.filename for pkg in package_deny_list)
|
|
63
|
+
)
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
user_trace = ""
|
|
67
|
+
if user_traces:
|
|
68
|
+
user_trace = "".join(traceback.format_list([user_traces[-1]]))
|
|
69
|
+
|
|
70
|
+
return full_trace, user_trace
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class ModificationTracker:
|
|
74
|
+
"""
|
|
75
|
+
Tracks modifications to database model instances and manages their lifecycle.
|
|
76
|
+
|
|
77
|
+
This class maintains a record of all modified model instances that haven't been
|
|
78
|
+
committed yet. It provides functionality to track new modifications, handle commits,
|
|
79
|
+
and log any remaining uncommitted modifications.
|
|
80
|
+
|
|
81
|
+
The tracker organizes modifications by model class and prevents duplicate tracking
|
|
82
|
+
of the same instance. It also captures stack traces at the point of modification
|
|
83
|
+
to help with debugging.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
modified_models: dict[int, Modification]
|
|
87
|
+
"""
|
|
88
|
+
Dictionary mapping model classes to lists of their modifications
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
verbosity: MODIFICATION_TRACKER_VERBOSITY | None
|
|
92
|
+
"""
|
|
93
|
+
The logging level to use when reporting uncommitted modifications
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
def __init__(
|
|
97
|
+
self,
|
|
98
|
+
verbosity: MODIFICATION_TRACKER_VERBOSITY | None = None,
|
|
99
|
+
known_first_party: list[str] | None = None,
|
|
100
|
+
):
|
|
101
|
+
"""
|
|
102
|
+
Initialize a new ModificationTracker.
|
|
103
|
+
|
|
104
|
+
Creates an empty modification tracking dictionary and sets the initial
|
|
105
|
+
verbosity level to None.
|
|
106
|
+
"""
|
|
107
|
+
self.modified_models = {}
|
|
108
|
+
self.verbosity = verbosity
|
|
109
|
+
self.known_first_party = known_first_party
|
|
110
|
+
|
|
111
|
+
def track_modification(self, instance: TableBase) -> None:
|
|
112
|
+
"""
|
|
113
|
+
Track a modification to a model instance along with its stack trace.
|
|
114
|
+
|
|
115
|
+
This method records a modification to a model instance if it hasn't already
|
|
116
|
+
been tracked. It captures both the full stack trace and a user-specific
|
|
117
|
+
stack trace at the point of modification.
|
|
118
|
+
|
|
119
|
+
:param instance: The model instance that was modified
|
|
120
|
+
:type instance: TableBase
|
|
121
|
+
"""
|
|
122
|
+
# Get stack traces. By default we filter out all iceaxe code, but allow users to override this behavior
|
|
123
|
+
# if we want to still test this logic under test.
|
|
124
|
+
full_trace, user_trace = Modification.get_current_stack_trace(
|
|
125
|
+
package_allow_list=self.known_first_party,
|
|
126
|
+
package_deny_list=["iceaxe"] if not self.known_first_party else None,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# Only track if we haven't already tracked this instance
|
|
130
|
+
instance_id = id(instance)
|
|
131
|
+
if instance_id not in self.modified_models:
|
|
132
|
+
modification = Modification(
|
|
133
|
+
instance=instance, stack_trace=full_trace, user_stack_trace=user_trace
|
|
134
|
+
)
|
|
135
|
+
self.modified_models[instance_id] = modification
|
|
136
|
+
|
|
137
|
+
def clear_status(self, models: Sequence[TableBase]) -> None:
|
|
138
|
+
"""
|
|
139
|
+
Remove models that are about to be committed from tracking.
|
|
140
|
+
|
|
141
|
+
This method should be called before committing changes to the database.
|
|
142
|
+
It removes the specified models from tracking since they will no longer
|
|
143
|
+
be in an uncommitted state.
|
|
144
|
+
|
|
145
|
+
:param models: List of model instances that will be committed
|
|
146
|
+
:type models: list[TableBase]
|
|
147
|
+
"""
|
|
148
|
+
for instance in models:
|
|
149
|
+
instance_id = id(instance)
|
|
150
|
+
if instance_id in self.modified_models:
|
|
151
|
+
del self.modified_models[instance_id]
|
|
152
|
+
|
|
153
|
+
def log(self) -> None:
|
|
154
|
+
"""
|
|
155
|
+
Log all uncommitted modifications with their stack traces.
|
|
156
|
+
|
|
157
|
+
This method logs information about all tracked modifications that haven't
|
|
158
|
+
been committed yet. The logging level is determined by the tracker's
|
|
159
|
+
verbosity setting. At the INFO level, it includes the full stack trace
|
|
160
|
+
in addition to the user stack trace.
|
|
161
|
+
|
|
162
|
+
If verbosity is not set (None), this method does nothing.
|
|
163
|
+
"""
|
|
164
|
+
if not self.verbosity:
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
log_level = getattr(logging, self.verbosity)
|
|
168
|
+
LOGGER.setLevel(log_level) # Ensure logger will capture messages at this level
|
|
169
|
+
|
|
170
|
+
for mod in self.modified_models.values():
|
|
171
|
+
LOGGER.log(
|
|
172
|
+
log_level, f"Object modified locally but not committed: {mod.instance}"
|
|
173
|
+
)
|
|
174
|
+
LOGGER.log(log_level, f"Modified at:\n{mod.user_stack_trace}")
|
|
175
|
+
if self.verbosity == "INFO":
|
|
176
|
+
LOGGER.log(log_level, f"Full stack trace:\n{mod.stack_trace}")
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from iceaxe.mountaineer import (
|
|
2
|
+
dependencies as DatabaseDependencies, # noqa: F401
|
|
3
|
+
)
|
|
4
|
+
|
|
5
|
+
from .cli import (
|
|
6
|
+
apply_migration as apply_migration,
|
|
7
|
+
generate_migration as generate_migration,
|
|
8
|
+
rollback_migration as rollback_migration,
|
|
9
|
+
)
|
|
10
|
+
from .config import DatabaseConfig as DatabaseConfig
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Alternative entrypoints to migrations/cli that use Mountaineer configurations
|
|
3
|
+
to simplify the setup of the database connection.
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from mountaineer import ConfigBase, CoreDependencies, Depends
|
|
8
|
+
from mountaineer.dependencies import get_function_dependencies
|
|
9
|
+
|
|
10
|
+
from iceaxe.migrations.cli import handle_apply, handle_generate, handle_rollback
|
|
11
|
+
from iceaxe.mountaineer.config import DatabaseConfig
|
|
12
|
+
from iceaxe.mountaineer.dependencies.core import get_db_connection
|
|
13
|
+
from iceaxe.session import DBConnection
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def generate_migration(message: str | None = None):
|
|
17
|
+
async def _inner(
|
|
18
|
+
db_config: DatabaseConfig = Depends(
|
|
19
|
+
CoreDependencies.get_config_with_type(DatabaseConfig)
|
|
20
|
+
),
|
|
21
|
+
core_config: ConfigBase = Depends(
|
|
22
|
+
CoreDependencies.get_config_with_type(ConfigBase)
|
|
23
|
+
),
|
|
24
|
+
db_connection: DBConnection = Depends(get_db_connection),
|
|
25
|
+
):
|
|
26
|
+
if not core_config.PACKAGE:
|
|
27
|
+
raise ValueError("No package provided in the configuration")
|
|
28
|
+
|
|
29
|
+
await handle_generate(
|
|
30
|
+
package=core_config.PACKAGE,
|
|
31
|
+
db_connection=db_connection,
|
|
32
|
+
message=message,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
async with get_function_dependencies(callable=_inner) as values:
|
|
36
|
+
await _inner(**values)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
async def apply_migration():
|
|
40
|
+
async def _inner(
|
|
41
|
+
core_config: ConfigBase = Depends(
|
|
42
|
+
CoreDependencies.get_config_with_type(ConfigBase)
|
|
43
|
+
),
|
|
44
|
+
db_connection: DBConnection = Depends(get_db_connection),
|
|
45
|
+
):
|
|
46
|
+
if not core_config.PACKAGE:
|
|
47
|
+
raise ValueError("No package provided in the configuration")
|
|
48
|
+
|
|
49
|
+
await handle_apply(
|
|
50
|
+
package=core_config.PACKAGE,
|
|
51
|
+
db_connection=db_connection,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
async with get_function_dependencies(callable=_inner) as values:
|
|
55
|
+
await _inner(**values)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
async def rollback_migration():
|
|
59
|
+
async def _inner(
|
|
60
|
+
core_config: ConfigBase = Depends(
|
|
61
|
+
CoreDependencies.get_config_with_type(ConfigBase)
|
|
62
|
+
),
|
|
63
|
+
db_connection: DBConnection = Depends(get_db_connection),
|
|
64
|
+
):
|
|
65
|
+
if not core_config.PACKAGE:
|
|
66
|
+
raise ValueError("No package provided in the configuration")
|
|
67
|
+
|
|
68
|
+
await handle_rollback(
|
|
69
|
+
package=core_config.PACKAGE,
|
|
70
|
+
db_connection=db_connection,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
async with get_function_dependencies(callable=_inner) as values:
|
|
74
|
+
await _inner(**values)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from pydantic_settings import BaseSettings
|
|
2
|
+
|
|
3
|
+
from iceaxe.modifications import MODIFICATION_TRACKER_VERBOSITY
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DatabaseConfig(BaseSettings):
|
|
7
|
+
"""
|
|
8
|
+
Configuration settings for PostgreSQL database connection.
|
|
9
|
+
This class uses Pydantic's BaseSettings to manage environment-based configuration.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
POSTGRES_HOST: str
|
|
13
|
+
"""
|
|
14
|
+
The hostname where the PostgreSQL server is running.
|
|
15
|
+
This can be a domain name or IP address (e.g., 'localhost' or '127.0.0.1').
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
POSTGRES_USER: str
|
|
19
|
+
"""
|
|
20
|
+
The username to authenticate with the PostgreSQL server.
|
|
21
|
+
This user should have appropriate permissions for the database operations.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
POSTGRES_PASSWORD: str
|
|
25
|
+
"""
|
|
26
|
+
The password for authenticating the PostgreSQL user.
|
|
27
|
+
This should be kept secure and not exposed in code or version control.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
POSTGRES_DB: str
|
|
31
|
+
"""
|
|
32
|
+
The name of the PostgreSQL database to connect to.
|
|
33
|
+
This database should exist on the server before attempting connection.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
POSTGRES_PORT: int = 5432
|
|
37
|
+
"""
|
|
38
|
+
The port number where PostgreSQL server is listening.
|
|
39
|
+
Defaults to the standard PostgreSQL port 5432 if not specified.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
ICEAXE_UNCOMMITTED_VERBOSITY: MODIFICATION_TRACKER_VERBOSITY | None = None
|
|
43
|
+
"""
|
|
44
|
+
The verbosity level for uncommitted modifications.
|
|
45
|
+
If set to None, uncommitted modifications will not be tracked.
|
|
46
|
+
"""
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Optional compatibility layer for `mountaineer` dependency access.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import AsyncGenerator
|
|
7
|
+
|
|
8
|
+
import asyncpg
|
|
9
|
+
from mountaineer import CoreDependencies, Depends
|
|
10
|
+
|
|
11
|
+
from iceaxe.mountaineer.config import DatabaseConfig
|
|
12
|
+
from iceaxe.session import DBConnection
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def get_db_connection(
|
|
16
|
+
config: DatabaseConfig = Depends(
|
|
17
|
+
CoreDependencies.get_config_with_type(DatabaseConfig)
|
|
18
|
+
),
|
|
19
|
+
) -> AsyncGenerator[DBConnection, None]:
|
|
20
|
+
"""
|
|
21
|
+
A dependency that provides a database connection for use in FastAPI endpoints or other
|
|
22
|
+
dependency-injected contexts. The connection is automatically closed when the endpoint
|
|
23
|
+
finishes processing.
|
|
24
|
+
|
|
25
|
+
This dependency:
|
|
26
|
+
- Creates a new PostgreSQL connection using the provided configuration
|
|
27
|
+
- Wraps it in a DBConnection for ORM functionality
|
|
28
|
+
- Initializes the connection's type cache to support enums without per-connection
|
|
29
|
+
type introspection
|
|
30
|
+
- Automatically closes the connection when done
|
|
31
|
+
- Integrates with Mountaineer's dependency injection system
|
|
32
|
+
|
|
33
|
+
:param config: DatabaseConfig instance containing connection parameters.
|
|
34
|
+
Automatically injected by Mountaineer if not provided.
|
|
35
|
+
:return: An async generator yielding a DBConnection instance
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from fastapi import FastAPI, Depends
|
|
39
|
+
from iceaxe.mountaineer.dependencies import get_db_connection
|
|
40
|
+
from iceaxe.session import DBConnection
|
|
41
|
+
|
|
42
|
+
app = FastAPI()
|
|
43
|
+
|
|
44
|
+
# Basic usage in a FastAPI endpoint
|
|
45
|
+
@app.get("/users")
|
|
46
|
+
async def get_users(db: DBConnection = Depends(get_db_connection)):
|
|
47
|
+
users = await db.exec(select(User))
|
|
48
|
+
return users
|
|
49
|
+
```
|
|
50
|
+
"""
|
|
51
|
+
conn = await asyncpg.connect(
|
|
52
|
+
host=config.POSTGRES_HOST,
|
|
53
|
+
port=config.POSTGRES_PORT,
|
|
54
|
+
user=config.POSTGRES_USER,
|
|
55
|
+
password=config.POSTGRES_PASSWORD,
|
|
56
|
+
database=config.POSTGRES_DB,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
connection = DBConnection(
|
|
60
|
+
conn, uncommitted_verbosity=config.ICEAXE_UNCOMMITTED_VERBOSITY
|
|
61
|
+
)
|
|
62
|
+
await connection.initialize_types()
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
yield connection
|
|
66
|
+
finally:
|
|
67
|
+
await connection.close()
|
iceaxe/postgres.py
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
from typing import Literal
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class LexemePriority(StrEnum):
|
|
8
|
+
"""Enum representing text search lexeme priority weights in Postgres."""
|
|
9
|
+
|
|
10
|
+
HIGHEST = "A"
|
|
11
|
+
HIGH = "B"
|
|
12
|
+
LOW = "C"
|
|
13
|
+
LOWEST = "D"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class PostgresFieldBase(BaseModel):
|
|
17
|
+
"""
|
|
18
|
+
Extensions to python core types that specify addition arguments
|
|
19
|
+
used by Postgres.
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class PostgresDateTime(PostgresFieldBase):
|
|
27
|
+
"""
|
|
28
|
+
Extension to Python's datetime type that specifies additional Postgres-specific configuration.
|
|
29
|
+
Used to customize the timezone behavior of datetime fields in Postgres.
|
|
30
|
+
|
|
31
|
+
```python {{sticky: True}}
|
|
32
|
+
from iceaxe import Field, TableBase
|
|
33
|
+
class Event(TableBase):
|
|
34
|
+
id: int = Field(primary_key=True)
|
|
35
|
+
created_at: datetime = Field(postgres_config=PostgresDateTime(timezone=True))
|
|
36
|
+
```
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
timezone: bool = False
|
|
40
|
+
"""
|
|
41
|
+
Whether the datetime field should include timezone information in Postgres.
|
|
42
|
+
If True, maps to TIMESTAMP WITH TIME ZONE.
|
|
43
|
+
If False, maps to TIMESTAMP WITHOUT TIME ZONE.
|
|
44
|
+
Defaults to False.
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class PostgresTime(PostgresFieldBase):
|
|
50
|
+
"""
|
|
51
|
+
Extension to Python's time type that specifies additional Postgres-specific configuration.
|
|
52
|
+
Used to customize the timezone behavior of time fields in Postgres.
|
|
53
|
+
|
|
54
|
+
```python {{sticky: True}}
|
|
55
|
+
from iceaxe import Field, TableBase
|
|
56
|
+
class Schedule(TableBase):
|
|
57
|
+
id: int = Field(primary_key=True)
|
|
58
|
+
start_time: time = Field(postgres_config=PostgresTime(timezone=True))
|
|
59
|
+
```
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
timezone: bool = False
|
|
63
|
+
"""
|
|
64
|
+
Whether the time field should include timezone information in Postgres.
|
|
65
|
+
If True, maps to TIME WITH TIME ZONE.
|
|
66
|
+
If False, maps to TIME WITHOUT TIME ZONE.
|
|
67
|
+
Defaults to False.
|
|
68
|
+
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class PostgresFullText(PostgresFieldBase):
|
|
73
|
+
"""
|
|
74
|
+
Extension to Python's string type that specifies additional Postgres-specific configuration
|
|
75
|
+
for full-text search. Used to customize the behavior of text search fields in Postgres.
|
|
76
|
+
|
|
77
|
+
```python {{sticky: True}}
|
|
78
|
+
from iceaxe import TableBase, Field
|
|
79
|
+
from iceaxe.postgres import PostgresFullText, LexemePriority
|
|
80
|
+
|
|
81
|
+
class Article(TableBase):
|
|
82
|
+
id: int = Field(primary_key=True)
|
|
83
|
+
title: str = Field(postgres_config=PostgresFullText(
|
|
84
|
+
language="english",
|
|
85
|
+
weight=LexemePriority.HIGHEST # or "A"
|
|
86
|
+
))
|
|
87
|
+
content: str = Field(postgres_config=PostgresFullText(
|
|
88
|
+
language="english",
|
|
89
|
+
weight=LexemePriority.HIGH # or "B"
|
|
90
|
+
))
|
|
91
|
+
```
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
language: str = "english"
|
|
95
|
+
"""
|
|
96
|
+
The language to use for text search operations.
|
|
97
|
+
Defaults to 'english'.
|
|
98
|
+
"""
|
|
99
|
+
weight: Literal["A", "B", "C", "D"] | LexemePriority = LexemePriority.HIGHEST
|
|
100
|
+
"""
|
|
101
|
+
The weight to assign to matches in this column.
|
|
102
|
+
Can be specified either as a string literal ("A", "B", "C", "D") or using LexemePriority enum.
|
|
103
|
+
A/HIGHEST is highest priority, D/LOWEST is lowest priority.
|
|
104
|
+
Defaults to LexemePriority.HIGHEST (A).
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
ForeignKeyModifications = Literal[
|
|
109
|
+
"RESTRICT", "NO ACTION", "CASCADE", "SET DEFAULT", "SET NULL"
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class PostgresForeignKey(PostgresFieldBase):
|
|
114
|
+
"""
|
|
115
|
+
Extension to Python's ForeignKey type that specifies additional Postgres-specific configuration.
|
|
116
|
+
Used to customize the behavior of foreign key constraints in Postgres.
|
|
117
|
+
|
|
118
|
+
```python {{sticky: True}}
|
|
119
|
+
from iceaxe import TableBase, Field
|
|
120
|
+
|
|
121
|
+
class Office(TableBase):
|
|
122
|
+
id: int = Field(primary_key=True)
|
|
123
|
+
name: str
|
|
124
|
+
|
|
125
|
+
class Employee(TableBase):
|
|
126
|
+
id: int = Field(primary_key=True)
|
|
127
|
+
name: str
|
|
128
|
+
office_id: int = Field(foreign_key="office.id", postgres_config=PostgresForeignKey(on_delete="CASCADE", on_update="CASCADE"))
|
|
129
|
+
```
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
on_delete: ForeignKeyModifications = "NO ACTION"
|
|
133
|
+
on_update: ForeignKeyModifications = "NO ACTION"
|
iceaxe/py.typed
ADDED
|
File without changes
|