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 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
+ ]
@@ -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 ''