berryql 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.
- berryql/__init__.py +103 -0
- berryql/adapters/__init__.py +24 -0
- berryql/adapters/base.py +32 -0
- berryql/adapters/mssql.py +698 -0
- berryql/adapters/postgres.py +19 -0
- berryql/adapters/sqlite.py +29 -0
- berryql/core/__init__.py +11 -0
- berryql/core/analyzer.py +87 -0
- berryql/core/enum_utils.py +153 -0
- berryql/core/fields.py +429 -0
- berryql/core/filters.py +71 -0
- berryql/core/hydration.py +549 -0
- berryql/core/naming.py +104 -0
- berryql/core/selection.py +502 -0
- berryql/core/utils.py +375 -0
- berryql/mutations.py +1750 -0
- berryql/registry.py +4272 -0
- berryql/sql/builders.py +2353 -0
- berryql/sql/enum_helpers.py +111 -0
- berryql-0.1.0.dist-info/METADATA +493 -0
- berryql-0.1.0.dist-info/RECORD +24 -0
- berryql-0.1.0.dist-info/WHEEL +5 -0
- berryql-0.1.0.dist-info/licenses/LICENSE +21 -0
- berryql-0.1.0.dist-info/top_level.txt +1 -0
berryql/__init__.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""BerryQL public API and lightweight lazy exports.
|
|
2
|
+
|
|
3
|
+
This __init__ avoids importing heavy submodules at import time to prevent
|
|
4
|
+
circular imports when foundational layers (like database models) import
|
|
5
|
+
BerryQL utilities (e.g., enum helpers).
|
|
6
|
+
|
|
7
|
+
Exposes:
|
|
8
|
+
- get_active_schema, set_active_schema (without importing registry eagerly)
|
|
9
|
+
- Lazy attributes: BerrySchema, BerryType, BerryDomain, StrawberryConfig
|
|
10
|
+
- Lazy functions: field, relation, aggregate, count, custom, custom_object, domain, mutation
|
|
11
|
+
- enum_column (resolved lazily from .sql.enum_helpers)
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
_ACTIVE_SCHEMA: Any = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def set_active_schema(schema: Any) -> None:
|
|
21
|
+
global _ACTIVE_SCHEMA
|
|
22
|
+
_ACTIVE_SCHEMA = schema
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_active_schema() -> Any:
|
|
26
|
+
if _ACTIVE_SCHEMA is None:
|
|
27
|
+
raise RuntimeError("Active Berry schema not set. Ensure schema.py initialized it.")
|
|
28
|
+
return _ACTIVE_SCHEMA
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def __getattr__(name: str): # PEP 562 lazy exports
|
|
32
|
+
# Some IDEs/debuggers probe submodules via attribute access (pkg.registry).
|
|
33
|
+
# Return the actual submodule to avoid noisy AttributeError during introspection.
|
|
34
|
+
import importlib as _importlib
|
|
35
|
+
if name == 'registry':
|
|
36
|
+
return _importlib.import_module(__name__ + '.registry')
|
|
37
|
+
if name == 'mutations':
|
|
38
|
+
return _importlib.import_module(__name__ + '.mutations')
|
|
39
|
+
if name in {'BerrySchema', 'BerryType', 'BerryDomain', 'StrawberryConfig'}:
|
|
40
|
+
_registry = _importlib.import_module(__name__ + '.registry')
|
|
41
|
+
return getattr(_registry, name)
|
|
42
|
+
if name in {'field', 'relation', 'aggregate', 'count', 'custom', 'custom_object', 'domain', 'mutation', 'hooks', 'scope'}:
|
|
43
|
+
from .core import fields as _fields
|
|
44
|
+
if name not in {'hooks'}:
|
|
45
|
+
return getattr(_fields, name)
|
|
46
|
+
# hooks is provided by registry
|
|
47
|
+
_registry = _importlib.import_module(__name__ + '.registry')
|
|
48
|
+
return getattr(_registry, 'hooks')
|
|
49
|
+
if name == 'enum_column':
|
|
50
|
+
from .sql.enum_helpers import enum_column as _enum_column
|
|
51
|
+
return _enum_column
|
|
52
|
+
raise AttributeError(name)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
__all__ = [
|
|
56
|
+
'BerrySchema', 'BerryType', 'BerryDomain', 'StrawberryConfig',
|
|
57
|
+
'field', 'relation', 'aggregate', 'count', 'custom', 'custom_object', 'domain', 'mutation', 'hooks', 'scope',
|
|
58
|
+
'enum_column',
|
|
59
|
+
'get_active_schema', 'set_active_schema', 'registry', 'mutations',
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
# --- Runtime patch: mark Strawberry mutations with a stable flag ----------------------
|
|
63
|
+
# Some Strawberry versions do not reliably expose is_mutation on the public field object.
|
|
64
|
+
# We patch strawberry.mutation to set a stable __berry_is_mutation__ attribute on the
|
|
65
|
+
# resulting field (and on nested objects when present). This runs as soon as BerryQL is
|
|
66
|
+
# imported (schema loads BerryQL before domains are declared), so domain-level
|
|
67
|
+
# @strawberry.mutation decorators will carry the marker for precise classification.
|
|
68
|
+
try: # best-effort, no hard dependency on Strawberry internals
|
|
69
|
+
import strawberry as _strawberry # type: ignore
|
|
70
|
+
_orig_mutation = getattr(_strawberry, 'mutation', None)
|
|
71
|
+
if callable(_orig_mutation):
|
|
72
|
+
def _berry_marked_mutation(*args, **kwargs): # type: ignore
|
|
73
|
+
f = _orig_mutation(*args, **kwargs)
|
|
74
|
+
try:
|
|
75
|
+
setattr(f, '__berry_is_mutation__', True)
|
|
76
|
+
# Also try to tag nested bits Strawberry may attach
|
|
77
|
+
try:
|
|
78
|
+
fd = getattr(f, 'field_definition', None)
|
|
79
|
+
if fd is not None:
|
|
80
|
+
setattr(fd, '__berry_is_mutation__', True)
|
|
81
|
+
except Exception:
|
|
82
|
+
pass
|
|
83
|
+
try:
|
|
84
|
+
br = getattr(f, 'base_resolver', None)
|
|
85
|
+
if br is not None:
|
|
86
|
+
setattr(br, '__berry_is_mutation__', True)
|
|
87
|
+
except Exception:
|
|
88
|
+
pass
|
|
89
|
+
try:
|
|
90
|
+
rv = getattr(f, 'resolver', None)
|
|
91
|
+
if rv is not None:
|
|
92
|
+
setattr(rv, '__berry_is_mutation__', True)
|
|
93
|
+
except Exception:
|
|
94
|
+
pass
|
|
95
|
+
except Exception:
|
|
96
|
+
pass
|
|
97
|
+
return f
|
|
98
|
+
try:
|
|
99
|
+
setattr(_strawberry, 'mutation', _berry_marked_mutation)
|
|
100
|
+
except Exception:
|
|
101
|
+
pass
|
|
102
|
+
except Exception:
|
|
103
|
+
pass
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from .base import BaseAdapter
|
|
4
|
+
from .sqlite import SQLiteAdapter
|
|
5
|
+
from .postgres import PostgresAdapter
|
|
6
|
+
from .mssql import MSSQLAdapter
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_adapter(dialect_name: str) -> BaseAdapter:
|
|
10
|
+
dn = (dialect_name or '').lower()
|
|
11
|
+
if dn.startswith('postgres'):
|
|
12
|
+
return PostgresAdapter()
|
|
13
|
+
if dn.startswith('mssql') or 'pyodbc' in dn:
|
|
14
|
+
return MSSQLAdapter()
|
|
15
|
+
return SQLiteAdapter()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
'BaseAdapter',
|
|
20
|
+
'SQLiteAdapter',
|
|
21
|
+
'PostgresAdapter',
|
|
22
|
+
'MSSQLAdapter',
|
|
23
|
+
'get_adapter',
|
|
24
|
+
]
|
berryql/adapters/base.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
class BaseAdapter:
|
|
4
|
+
"""Base SQL adapter interface used by BerryQL builders."""
|
|
5
|
+
name = 'base'
|
|
6
|
+
def json_object(self, *args):
|
|
7
|
+
raise NotImplementedError
|
|
8
|
+
def json_array_agg(self, expr):
|
|
9
|
+
raise NotImplementedError
|
|
10
|
+
def json_array_coalesce(self, expr):
|
|
11
|
+
raise NotImplementedError
|
|
12
|
+
def supports_relation_pushdown(self) -> bool:
|
|
13
|
+
return True
|
|
14
|
+
|
|
15
|
+
# Table identifier helper; adapters can override for dialect-specific quoting/qualification
|
|
16
|
+
def table_ident(self, model_cls) -> str:
|
|
17
|
+
try:
|
|
18
|
+
# Prefer SQLAlchemy Table if available
|
|
19
|
+
tbl = getattr(model_cls, '__table__', None)
|
|
20
|
+
if tbl is not None:
|
|
21
|
+
schema = getattr(tbl, 'schema', None)
|
|
22
|
+
name = getattr(tbl, 'name', None) or getattr(model_cls, '__tablename__', None)
|
|
23
|
+
if schema:
|
|
24
|
+
return f"{schema}.{name}"
|
|
25
|
+
return str(name)
|
|
26
|
+
except Exception:
|
|
27
|
+
pass
|
|
28
|
+
# Fallback: use __tablename__
|
|
29
|
+
try:
|
|
30
|
+
return str(getattr(model_cls, '__tablename__'))
|
|
31
|
+
except Exception:
|
|
32
|
+
return ''
|