pyrsql 0.0.1__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.
Files changed (74) hide show
  1. pyrsql/__init__.py +63 -0
  2. pyrsql/adapters/__init__.py +3 -0
  3. pyrsql/adapters/fastapi/__init__.py +15 -0
  4. pyrsql/adapters/fastapi/config.py +76 -0
  5. pyrsql/adapters/fastapi/criteria.py +56 -0
  6. pyrsql/adapters/fastapi/dependency.py +217 -0
  7. pyrsql/adapters/fastapi/errors.py +107 -0
  8. pyrsql/api.py +76 -0
  9. pyrsql/core/__init__.py +45 -0
  10. pyrsql/core/compiler.py +81 -0
  11. pyrsql/core/conversion.py +206 -0
  12. pyrsql/core/custom.py +14 -0
  13. pyrsql/core/field_policy.py +97 -0
  14. pyrsql/core/joins.py +11 -0
  15. pyrsql/core/json/__init__.py +19 -0
  16. pyrsql/core/json/options.py +31 -0
  17. pyrsql/core/json/path.py +35 -0
  18. pyrsql/core/json/query.py +39 -0
  19. pyrsql/core/json/values.py +72 -0
  20. pyrsql/core/options.py +416 -0
  21. pyrsql/core/page.py +115 -0
  22. pyrsql/core/procedure_policy.py +61 -0
  23. pyrsql/core/query.py +160 -0
  24. pyrsql/core/sort.py +153 -0
  25. pyrsql/integrations/__init__.py +8 -0
  26. pyrsql/integrations/fastapi/__init__.py +8 -0
  27. pyrsql/integrations/fastapi/sqlalchemy.py +251 -0
  28. pyrsql/orms/__init__.py +15 -0
  29. pyrsql/orms/base.py +99 -0
  30. pyrsql/orms/sqlalchemy/__init__.py +39 -0
  31. pyrsql/orms/sqlalchemy/coercion.py +57 -0
  32. pyrsql/orms/sqlalchemy/compiled.py +56 -0
  33. pyrsql/orms/sqlalchemy/compiled_page.py +40 -0
  34. pyrsql/orms/sqlalchemy/compiled_sort.py +56 -0
  35. pyrsql/orms/sqlalchemy/custom.py +25 -0
  36. pyrsql/orms/sqlalchemy/errors.py +17 -0
  37. pyrsql/orms/sqlalchemy/introspection.py +107 -0
  38. pyrsql/orms/sqlalchemy/json_path.py +351 -0
  39. pyrsql/orms/sqlalchemy/orm.py +65 -0
  40. pyrsql/orms/sqlalchemy/resolver.py +202 -0
  41. pyrsql/orms/sqlalchemy/sorter.py +173 -0
  42. pyrsql/orms/sqlalchemy/statement.py +40 -0
  43. pyrsql/orms/sqlalchemy/translator.py +560 -0
  44. pyrsql/orms/sqlalchemy/type_inference.py +27 -0
  45. pyrsql/orms/sqlalchemy/types.py +64 -0
  46. pyrsql/parsing/__init__.py +32 -0
  47. pyrsql/parsing/ast.py +61 -0
  48. pyrsql/parsing/errors.py +25 -0
  49. pyrsql/parsing/lexer.py +264 -0
  50. pyrsql/parsing/limits.py +15 -0
  51. pyrsql/parsing/operators.py +201 -0
  52. pyrsql/parsing/parser.py +292 -0
  53. pyrsql/parsing/source.py +48 -0
  54. pyrsql/parsing/tokens.py +30 -0
  55. pyrsql/py.typed +0 -0
  56. pyrsql/selector/__init__.py +30 -0
  57. pyrsql/selector/analyzer.py +58 -0
  58. pyrsql/selector/ast.py +31 -0
  59. pyrsql/selector/parser.py +130 -0
  60. pyrsql/selector/semantic.py +34 -0
  61. pyrsql/semantic/__init__.py +23 -0
  62. pyrsql/semantic/analyzer.py +116 -0
  63. pyrsql/semantic/ast.py +35 -0
  64. pyrsql/semantic/errors.py +40 -0
  65. pyrsql/sorting/__init__.py +26 -0
  66. pyrsql/sorting/analyzer.py +74 -0
  67. pyrsql/sorting/ast.py +46 -0
  68. pyrsql/sorting/errors.py +21 -0
  69. pyrsql/sorting/limits.py +15 -0
  70. pyrsql/sorting/parser.py +150 -0
  71. pyrsql/sorting/semantic.py +15 -0
  72. pyrsql-0.0.1.dist-info/METADATA +72 -0
  73. pyrsql-0.0.1.dist-info/RECORD +74 -0
  74. pyrsql-0.0.1.dist-info/WHEEL +4 -0
pyrsql/__init__.py ADDED
@@ -0,0 +1,63 @@
1
+ """Public package interface for pyrsql."""
2
+
3
+ # pylint: disable=redefined-builtin
4
+
5
+ import pyrsql.api as api
6
+ from pyrsql.core.compiler import (
7
+ CompilationResult,
8
+ PageCompilationResult,
9
+ SortCompilationResult,
10
+ )
11
+ from pyrsql.core.conversion import (
12
+ FieldValueConverterSet,
13
+ ValueConverter,
14
+ ValueConverterRegistry,
15
+ )
16
+ from pyrsql.core.custom import CustomPredicateDefinition
17
+ from pyrsql.core.field_policy import FieldPolicySet
18
+ from pyrsql.core.json.options import JSONOptions
19
+ from pyrsql.core.json.path import JSONPath
20
+ from pyrsql.core.json.query import JSONPathComparison
21
+ from pyrsql.core.json.values import JSONScalarNormalizer, JSONScalarValue
22
+ from pyrsql.core.options import QueryOptions, SortOptions
23
+ from pyrsql.core.page import PageRequest
24
+ from pyrsql.core.procedure_policy import ProcedureAccessPolicy
25
+ from pyrsql.core.query import Query
26
+ from pyrsql.core.sort import Sort
27
+ from pyrsql.integrations import (
28
+ FastAPISQLAlchemyIntegration,
29
+ SQLAlchemyPaginatedSelect,
30
+ )
31
+ from pyrsql.orms.base import ORM
32
+
33
+ parse = api.parse
34
+ compile = api.compile
35
+ apply = api.apply
36
+
37
+ __all__ = [
38
+ "ORM",
39
+ "CompilationResult",
40
+ "CustomPredicateDefinition",
41
+ "FieldPolicySet",
42
+ "FieldValueConverterSet",
43
+ "FastAPISQLAlchemyIntegration",
44
+ "JSONOptions",
45
+ "JSONPath",
46
+ "JSONPathComparison",
47
+ "JSONScalarNormalizer",
48
+ "JSONScalarValue",
49
+ "PageCompilationResult",
50
+ "PageRequest",
51
+ "ProcedureAccessPolicy",
52
+ "Query",
53
+ "QueryOptions",
54
+ "Sort",
55
+ "SortCompilationResult",
56
+ "SortOptions",
57
+ "SQLAlchemyPaginatedSelect",
58
+ "ValueConverter",
59
+ "ValueConverterRegistry",
60
+ "apply",
61
+ "compile",
62
+ "parse",
63
+ ]
@@ -0,0 +1,3 @@
1
+ """Framework adapter implementations for pyrsql."""
2
+
3
+ __all__: list[str] = []
@@ -0,0 +1,15 @@
1
+ """FastAPI adapter for pyrsql request extraction and error translation."""
2
+
3
+ from pyrsql.adapters.fastapi.config import FastAPICriteriaConfig
4
+ from pyrsql.adapters.fastapi.criteria import RequestCriteria
5
+ from pyrsql.adapters.fastapi.dependency import (
6
+ CriteriaDependency,
7
+ criteria_dependency,
8
+ )
9
+
10
+ __all__ = [
11
+ "CriteriaDependency",
12
+ "FastAPICriteriaConfig",
13
+ "RequestCriteria",
14
+ "criteria_dependency",
15
+ ]
@@ -0,0 +1,76 @@
1
+ """Configuration objects for the FastAPI adapter."""
2
+
3
+ from dataclasses import dataclass, field
4
+
5
+ from pyrsql.core.options import QueryOptions, SortOptions
6
+
7
+ _DEFAULT_FILTER_PARAMETER = "filter"
8
+ _DEFAULT_SORT_PARAMETER = "sort"
9
+ _DEFAULT_PAGE_PARAMETER = "page"
10
+ _DEFAULT_SIZE_PARAMETER = "size"
11
+
12
+
13
+ @dataclass(frozen=True, slots=True)
14
+ class FastAPICriteriaConfig:
15
+ """Configures FastAPI query parameter extraction for pyrsql.
16
+
17
+ Attributes:
18
+ filter_parameter: Query parameter used for filtering expressions.
19
+ sort_parameter: Query parameter used for sort expressions.
20
+ page_parameter: Query parameter used for page numbers.
21
+ size_parameter: Query parameter used for page size.
22
+ default_page_size: Default size used when only a page number is given.
23
+ max_page_size: Maximum accepted page size.
24
+ one_based_paging: Whether page numbers start at 1 instead of 0.
25
+ query_options: Query parsing and semantic configuration.
26
+ sort_options: Sort parsing and semantic configuration.
27
+ """
28
+
29
+ filter_parameter: str = _DEFAULT_FILTER_PARAMETER
30
+ sort_parameter: str = _DEFAULT_SORT_PARAMETER
31
+ page_parameter: str = _DEFAULT_PAGE_PARAMETER
32
+ size_parameter: str = _DEFAULT_SIZE_PARAMETER
33
+ default_page_size: int | None = None
34
+ max_page_size: int | None = None
35
+ one_based_paging: bool = False
36
+ query_options: QueryOptions = field(default_factory=QueryOptions)
37
+ sort_options: SortOptions = field(default_factory=SortOptions)
38
+
39
+ def __post_init__(self) -> None:
40
+ """Validates adapter configuration invariants.
41
+
42
+ Raises:
43
+ ValueError: If parameter names are empty, duplicated, or paging
44
+ limits are inconsistent.
45
+ """
46
+ parameter_names = (
47
+ self.filter_parameter,
48
+ self.sort_parameter,
49
+ self.page_parameter,
50
+ self.size_parameter,
51
+ )
52
+ normalized_names = tuple(name.strip() for name in parameter_names)
53
+ if any(not name for name in normalized_names):
54
+ raise ValueError("FastAPI parameter names must not be empty.")
55
+ if len(set(normalized_names)) != len(normalized_names):
56
+ raise ValueError("FastAPI parameter names must be unique.")
57
+ if self.default_page_size is not None and self.default_page_size <= 0:
58
+ raise ValueError("default_page_size must be greater than 0.")
59
+ if self.max_page_size is not None and self.max_page_size <= 0:
60
+ raise ValueError("max_page_size must be greater than 0.")
61
+ if (
62
+ self.default_page_size is not None
63
+ and self.max_page_size is not None
64
+ and self.default_page_size > self.max_page_size
65
+ ):
66
+ raise ValueError("default_page_size must not exceed max_page_size.")
67
+
68
+ @property
69
+ def minimum_page_number(self) -> int:
70
+ """The minimum accepted page number for the adapter."""
71
+ return 1 if self.one_based_paging else 0
72
+
73
+ @property
74
+ def default_page_number(self) -> int:
75
+ """The page number used when only size is provided."""
76
+ return 1 if self.one_based_paging else 0
@@ -0,0 +1,56 @@
1
+ """FastAPI request criteria objects."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+ from pyrsql.core.page import PageRequest
7
+ from pyrsql.core.query import Query
8
+ from pyrsql.core.sort import Sort
9
+ from pyrsql.orms.base import ORM
10
+
11
+
12
+ @dataclass(frozen=True, slots=True)
13
+ class RequestCriteria:
14
+ """Represents request-derived pyrsql criteria for a FastAPI endpoint."""
15
+
16
+ query: Query | None = None
17
+ sort: Sort | None = None
18
+ page_request: PageRequest | None = None
19
+
20
+ @property
21
+ def is_empty(self) -> bool:
22
+ """Indicates whether no query components are present."""
23
+ return (
24
+ self.query is None
25
+ and self.sort is None
26
+ and self.page_request is None
27
+ )
28
+
29
+ def apply(
30
+ self,
31
+ target: Any,
32
+ model: type[Any],
33
+ *,
34
+ orm: ORM,
35
+ ) -> Any:
36
+ """Applies the criteria to an ORM-specific target."""
37
+ current_target = target
38
+ if self.query is not None:
39
+ current_target = self.query.apply(
40
+ current_target,
41
+ model,
42
+ orm=orm,
43
+ )
44
+ if self.sort is not None:
45
+ current_target = self.sort.apply(
46
+ current_target,
47
+ model,
48
+ orm=orm,
49
+ )
50
+ if self.page_request is not None:
51
+ current_target = self.page_request.apply(
52
+ current_target,
53
+ model,
54
+ orm=orm,
55
+ )
56
+ return current_target
@@ -0,0 +1,217 @@
1
+ """Dependency factories for FastAPI request integration."""
2
+
3
+ from collections.abc import Callable
4
+ from inspect import Signature, signature
5
+ from typing import Annotated, Any
6
+
7
+ try:
8
+ from fastapi import HTTPException, Query
9
+ except ImportError as error: # pragma: no cover - import guard
10
+ raise ImportError(
11
+ "FastAPI support requires installing the 'fastapi' extra: "
12
+ "pip install pyrsql[fastapi]"
13
+ ) from error
14
+
15
+ from pyrsql.adapters.fastapi.config import FastAPICriteriaConfig
16
+ from pyrsql.adapters.fastapi.criteria import RequestCriteria
17
+ from pyrsql.adapters.fastapi.errors import (
18
+ FastAPIAdapterErrorPayload,
19
+ build_page_error_payload,
20
+ build_query_error_payload,
21
+ build_sort_error_payload,
22
+ )
23
+ from pyrsql.core.page import PageRequest
24
+ from pyrsql.core.query import Query as PyrsqlQuery
25
+ from pyrsql.core.sort import Sort as PyrsqlSort
26
+ from pyrsql.parsing.errors import ParseError
27
+ from pyrsql.semantic.errors import SemanticError
28
+ from pyrsql.sorting.errors import (
29
+ SortFieldBlacklistedError,
30
+ SortFieldNotWhitelistedError,
31
+ SortFunctionBlacklistedError,
32
+ SortFunctionNotWhitelistedError,
33
+ SortParseError,
34
+ )
35
+
36
+ _QUERY_ERROR_TYPES = (ParseError, SemanticError)
37
+ _SORT_ERROR_TYPES = (
38
+ SortParseError,
39
+ SortFieldNotWhitelistedError,
40
+ SortFieldBlacklistedError,
41
+ SortFunctionNotWhitelistedError,
42
+ SortFunctionBlacklistedError,
43
+ )
44
+ _DEFAULT_FASTAPI_CRITERIA_CONFIG = FastAPICriteriaConfig()
45
+
46
+
47
+ def _raise_http_error(payload: FastAPIAdapterErrorPayload) -> None:
48
+ """Raises a standardized FastAPI HTTP exception for adapter failures."""
49
+ raise HTTPException(
50
+ status_code=422,
51
+ detail={
52
+ "parameter": payload.parameter,
53
+ "type": payload.error_type,
54
+ "message": payload.message,
55
+ },
56
+ )
57
+
58
+
59
+ def _build_page_request(
60
+ *,
61
+ config: FastAPICriteriaConfig,
62
+ page_value: int | None,
63
+ size_value: int | None,
64
+ ) -> PageRequest | None:
65
+ """Builds a page request from validated FastAPI query params."""
66
+ resolved_page_size = size_value or config.default_page_size
67
+
68
+ if page_value is None:
69
+ if resolved_page_size is None:
70
+ return None
71
+ resolved_page_number = config.default_page_number
72
+ else:
73
+ resolved_page_number = page_value
74
+
75
+ if resolved_page_size is None:
76
+ _raise_http_error(
77
+ build_page_error_payload(
78
+ config.size_parameter,
79
+ error_type="page_configuration_error",
80
+ message=(
81
+ f"'{config.size_parameter}' is required when "
82
+ f"'{config.page_parameter}' is provided."
83
+ ),
84
+ )
85
+ )
86
+
87
+ if resolved_page_size is None:
88
+ raise ValueError("resolved_page_size cannot be None")
89
+
90
+ if config.one_based_paging:
91
+ if resolved_page_number <= 0:
92
+ _raise_http_error(
93
+ build_page_error_payload(
94
+ config.page_parameter,
95
+ error_type="page_validation_error",
96
+ message=(
97
+ f"'{config.page_parameter}' must be greater than 0 "
98
+ "when one_based_paging is enabled."
99
+ ),
100
+ )
101
+ )
102
+ resolved_page_number -= 1
103
+
104
+ return PageRequest.of(resolved_page_number, resolved_page_size)
105
+
106
+
107
+ def _build_criteria_callable(
108
+ config: FastAPICriteriaConfig,
109
+ ) -> Callable[..., RequestCriteria]:
110
+ """Builds the concrete dependency callable for a fixed configuration."""
111
+
112
+ def dependency(
113
+ filter_value: Annotated[
114
+ str | None,
115
+ Query(alias=config.filter_parameter),
116
+ ] = None,
117
+ sort_value: Annotated[
118
+ str | None,
119
+ Query(alias=config.sort_parameter),
120
+ ] = None,
121
+ page_value: Annotated[
122
+ int | None,
123
+ Query(
124
+ alias=config.page_parameter,
125
+ ge=config.minimum_page_number,
126
+ ),
127
+ ] = None,
128
+ size_value: Annotated[
129
+ int | None,
130
+ Query(
131
+ alias=config.size_parameter,
132
+ gt=0,
133
+ le=config.max_page_size,
134
+ ),
135
+ ] = None,
136
+ ) -> RequestCriteria:
137
+ query = None
138
+ sort = None
139
+
140
+ if filter_value:
141
+ try:
142
+ query = PyrsqlQuery.parse(
143
+ filter_value,
144
+ options=config.query_options,
145
+ )
146
+ except _QUERY_ERROR_TYPES as error:
147
+ _raise_http_error(
148
+ build_query_error_payload(config.filter_parameter, error)
149
+ )
150
+
151
+ if sort_value:
152
+ try:
153
+ sort = PyrsqlSort.parse(
154
+ sort_value,
155
+ options=config.sort_options,
156
+ )
157
+ except _SORT_ERROR_TYPES as error:
158
+ _raise_http_error(
159
+ build_sort_error_payload(config.sort_parameter, error)
160
+ )
161
+
162
+ page_request = _build_page_request(
163
+ config=config,
164
+ page_value=page_value,
165
+ size_value=size_value,
166
+ )
167
+
168
+ return RequestCriteria(
169
+ query=query,
170
+ sort=sort,
171
+ page_request=page_request,
172
+ )
173
+
174
+ return dependency
175
+
176
+
177
+ class CriteriaDependency:
178
+ """Callable FastAPI dependency object that resolves request criteria.
179
+
180
+ The generated signature exposes FastAPI query parameters and returns a
181
+ parsed RequestCriteria object.
182
+ """
183
+
184
+ def __init__(
185
+ self,
186
+ config: FastAPICriteriaConfig | None = None,
187
+ ) -> None:
188
+ """Creates a dependency object for the provided FastAPI config.
189
+
190
+ Args:
191
+ config: Optional FastAPI criteria configuration.
192
+ """
193
+ self.config = config or _DEFAULT_FASTAPI_CRITERIA_CONFIG
194
+ self._dependency = _build_criteria_callable(self.config)
195
+ self.__signature__: Signature = signature(self._dependency)
196
+
197
+ def __call__(self, *args: Any, **kwargs: Any) -> RequestCriteria:
198
+ """Delegates FastAPI dependency resolution to the generated callable.
199
+
200
+ Returns:
201
+ Parsed request criteria for the incoming FastAPI query params.
202
+ """
203
+ return self._dependency(*args, **kwargs)
204
+
205
+
206
+ def criteria_dependency(
207
+ config: FastAPICriteriaConfig | None = None,
208
+ ) -> CriteriaDependency:
209
+ """Builds a FastAPI dependency object that returns parsed criteria.
210
+
211
+ Args:
212
+ config: Optional FastAPI criteria configuration.
213
+
214
+ Returns:
215
+ A callable FastAPI dependency object.
216
+ """
217
+ return CriteriaDependency(config)
@@ -0,0 +1,107 @@
1
+ """FastAPI adapter error helpers."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from pyrsql.parsing.errors import ParseError
6
+ from pyrsql.semantic.errors import SemanticError
7
+ from pyrsql.sorting.errors import (
8
+ SortFieldBlacklistedError,
9
+ SortFieldNotWhitelistedError,
10
+ SortFunctionBlacklistedError,
11
+ SortFunctionNotWhitelistedError,
12
+ SortParseError,
13
+ )
14
+
15
+
16
+ @dataclass(frozen=True, slots=True)
17
+ class FastAPIAdapterErrorPayload:
18
+ """Structured adapter error payload for HTTP translation.
19
+
20
+ Attributes:
21
+ parameter: Name of the query parameter associated with the failure.
22
+ error_type: Stable machine-readable error category.
23
+ message: Human-readable error message.
24
+ """
25
+
26
+ parameter: str
27
+ error_type: str
28
+ message: str
29
+
30
+
31
+ def build_query_error_payload(
32
+ parameter_name: str,
33
+ error: ParseError | SemanticError,
34
+ ) -> FastAPIAdapterErrorPayload:
35
+ """Builds a payload for a filter/query parsing or semantic failure.
36
+
37
+ Args:
38
+ parameter_name: Query parameter name associated with the failure.
39
+ error: Parsing or semantic error raised by pyrsql.
40
+
41
+ Returns:
42
+ A normalized FastAPI error payload.
43
+ """
44
+ error_type = "query_parse_error"
45
+ if isinstance(error, SemanticError):
46
+ error_type = "query_semantic_error"
47
+ return FastAPIAdapterErrorPayload(
48
+ parameter=parameter_name,
49
+ error_type=error_type,
50
+ message=str(error),
51
+ )
52
+
53
+
54
+ def build_sort_error_payload(
55
+ parameter_name: str,
56
+ error: Exception,
57
+ ) -> FastAPIAdapterErrorPayload:
58
+ """Builds a payload for a sort parsing or semantic failure.
59
+
60
+ Args:
61
+ parameter_name: Query parameter name associated with the failure.
62
+ error: Sorting error raised by pyrsql.
63
+
64
+ Returns:
65
+ A normalized FastAPI error payload.
66
+ """
67
+ error_type = "sort_error"
68
+ if isinstance(error, SortParseError):
69
+ error_type = "sort_parse_error"
70
+ elif isinstance(
71
+ error,
72
+ (
73
+ SortFieldNotWhitelistedError,
74
+ SortFieldBlacklistedError,
75
+ SortFunctionNotWhitelistedError,
76
+ SortFunctionBlacklistedError,
77
+ ),
78
+ ):
79
+ error_type = "sort_semantic_error"
80
+ return FastAPIAdapterErrorPayload(
81
+ parameter=parameter_name,
82
+ error_type=error_type,
83
+ message=str(error),
84
+ )
85
+
86
+
87
+ def build_page_error_payload(
88
+ parameter_name: str,
89
+ *,
90
+ error_type: str,
91
+ message: str,
92
+ ) -> FastAPIAdapterErrorPayload:
93
+ """Builds a payload for page-related adapter validation failures.
94
+
95
+ Args:
96
+ parameter_name: Query parameter name associated with the failure.
97
+ error_type: Machine-readable error category.
98
+ message: Human-readable error message.
99
+
100
+ Returns:
101
+ A normalized FastAPI error payload.
102
+ """
103
+ return FastAPIAdapterErrorPayload(
104
+ parameter=parameter_name,
105
+ error_type=error_type,
106
+ message=message,
107
+ )
pyrsql/api.py ADDED
@@ -0,0 +1,76 @@
1
+ """ORM-neutral high-level API for pyrsql."""
2
+
3
+ # pylint: disable=redefined-builtin
4
+
5
+ from typing import Any
6
+
7
+ from pyrsql.core.compiler import CompilationResult
8
+ from pyrsql.core.options import QueryOptions
9
+ from pyrsql.core.query import Query
10
+ from pyrsql.orms.base import ORM
11
+
12
+
13
+ def parse(query_text: str, *, options: QueryOptions | None = None) -> Query:
14
+ """Parses raw RSQL text into a query object.
15
+
16
+ Args:
17
+ query_text: Raw RSQL text to parse.
18
+ options: Optional query configuration.
19
+
20
+ Returns:
21
+ A parsed query object.
22
+ """
23
+ return Query.parse(query_text, options=options)
24
+
25
+
26
+ def compile(
27
+ query_text: str,
28
+ *,
29
+ orm: ORM,
30
+ options: QueryOptions | None = None,
31
+ ) -> CompilationResult:
32
+ """Compiles raw RSQL text using the provided ORM.
33
+
34
+ Args:
35
+ query_text: Raw RSQL text to compile.
36
+ orm: ORM adapter used to compile the query.
37
+ options: Optional query configuration.
38
+
39
+ Returns:
40
+ The ORM-specific compilation result.
41
+ """
42
+ return parse(query_text, options=options).compile(orm=orm)
43
+
44
+
45
+ def apply(
46
+ target: Any,
47
+ model: type[Any],
48
+ query_text: str,
49
+ *,
50
+ orm: ORM,
51
+ options: QueryOptions | None = None,
52
+ ) -> Any:
53
+ """Applies raw RSQL text to an ORM-specific target.
54
+
55
+ Args:
56
+ target: ORM-specific target to mutate.
57
+ model: ORM model class used to resolve the query.
58
+ query_text: Raw RSQL text to apply.
59
+ orm: ORM adapter used to compile the query.
60
+ options: Optional query configuration.
61
+
62
+ Returns:
63
+ The value returned by the ORM-specific apply operation.
64
+ """
65
+ return compile(
66
+ query_text,
67
+ orm=orm,
68
+ options=options,
69
+ ).apply(target=target, model=model)
70
+
71
+
72
+ __all__ = [
73
+ "apply",
74
+ "compile",
75
+ "parse",
76
+ ]
@@ -0,0 +1,45 @@
1
+ """Core ORM-agnostic pyrsql types."""
2
+
3
+ from pyrsql.core.compiler import (
4
+ CompilationResult,
5
+ PageCompilationResult,
6
+ SortCompilationResult,
7
+ )
8
+ from pyrsql.core.conversion import (
9
+ FieldValueConverterSet,
10
+ ValueConverter,
11
+ ValueConverterRegistry,
12
+ )
13
+ from pyrsql.core.custom import CustomPredicateDefinition
14
+ from pyrsql.core.field_policy import FieldPolicySet
15
+ from pyrsql.core.json.options import JSONOptions
16
+ from pyrsql.core.json.path import JSONPath
17
+ from pyrsql.core.json.query import JSONPathComparison
18
+ from pyrsql.core.json.values import JSONScalarNormalizer, JSONScalarValue
19
+ from pyrsql.core.options import QueryOptions, SortOptions
20
+ from pyrsql.core.page import PageRequest
21
+ from pyrsql.core.procedure_policy import ProcedureAccessPolicy
22
+ from pyrsql.core.query import Query
23
+ from pyrsql.core.sort import Sort
24
+
25
+ __all__ = [
26
+ "CompilationResult",
27
+ "CustomPredicateDefinition",
28
+ "FieldPolicySet",
29
+ "FieldValueConverterSet",
30
+ "JSONOptions",
31
+ "JSONPath",
32
+ "JSONPathComparison",
33
+ "JSONScalarNormalizer",
34
+ "JSONScalarValue",
35
+ "PageCompilationResult",
36
+ "PageRequest",
37
+ "ProcedureAccessPolicy",
38
+ "Query",
39
+ "QueryOptions",
40
+ "Sort",
41
+ "SortCompilationResult",
42
+ "SortOptions",
43
+ "ValueConverter",
44
+ "ValueConverterRegistry",
45
+ ]