exdrf-rcv 0.1.17__tar.gz
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.
- exdrf_rcv-0.1.17/PKG-INFO +48 -0
- exdrf_rcv-0.1.17/README.md +20 -0
- exdrf_rcv-0.1.17/exdrf_rcv/__init__.py +30 -0
- exdrf_rcv-0.1.17/exdrf_rcv/__version__.py +24 -0
- exdrf_rcv-0.1.17/exdrf_rcv/models.py +435 -0
- exdrf_rcv-0.1.17/exdrf_rcv/plan.py +10 -0
- exdrf_rcv-0.1.17/exdrf_rcv/plan_resolve.py +291 -0
- exdrf_rcv-0.1.17/exdrf_rcv/py.typed +0 -0
- exdrf_rcv-0.1.17/exdrf_rcv.egg-info/PKG-INFO +48 -0
- exdrf_rcv-0.1.17/exdrf_rcv.egg-info/SOURCES.txt +16 -0
- exdrf_rcv-0.1.17/exdrf_rcv.egg-info/dependency_links.txt +1 -0
- exdrf_rcv-0.1.17/exdrf_rcv.egg-info/requires.txt +16 -0
- exdrf_rcv-0.1.17/exdrf_rcv.egg-info/top_level.txt +3 -0
- exdrf_rcv-0.1.17/pyproject.toml +62 -0
- exdrf_rcv-0.1.17/setup.cfg +4 -0
- exdrf_rcv-0.1.17/tests/models_test.py +121 -0
- exdrf_rcv-0.1.17/tests/package_import_test.py +21 -0
- exdrf_rcv-0.1.17/tests/plan_resolve_test.py +218 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: exdrf-rcv
|
|
3
|
+
Version: 0.1.17
|
|
4
|
+
Summary: Shared Python runtime for remote-controlled-view backends and exdrf-gen-al2rcv-generated modules.
|
|
5
|
+
Author-email: Nicu Tofan <nicu.tofan@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Classifier: Operating System :: OS Independent
|
|
8
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Typing :: Typed
|
|
11
|
+
Requires-Python: >=3.12.2
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: exdrf>=0.1.17
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: autoflake; extra == "dev"
|
|
16
|
+
Requires-Dist: black; extra == "dev"
|
|
17
|
+
Requires-Dist: build; extra == "dev"
|
|
18
|
+
Requires-Dist: flake8; extra == "dev"
|
|
19
|
+
Requires-Dist: isort; extra == "dev"
|
|
20
|
+
Requires-Dist: mypy; extra == "dev"
|
|
21
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
22
|
+
Requires-Dist: pyproject-flake8; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest-mock; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest; extra == "dev"
|
|
26
|
+
Requires-Dist: twine; extra == "dev"
|
|
27
|
+
Requires-Dist: wheel; extra == "dev"
|
|
28
|
+
|
|
29
|
+
# exdrf-rcv
|
|
30
|
+
|
|
31
|
+
The **remote-controlled-view (RCV)** stack renders **exdrf** resources and
|
|
32
|
+
related data into a user interface that the front end drives over HTTP.
|
|
33
|
+
|
|
34
|
+
**exdrf-rcv** is the **shared Python runtime** for RCV *backends*. It defines
|
|
35
|
+
**`RcvPlan`**, discriminated **`RcvField`** types, and helpers that
|
|
36
|
+
**`exdrf-gen-al2rcv`**-generated route modules import next to your FastAPI app.
|
|
37
|
+
|
|
38
|
+
The browser UI that consumes those endpoints lives in **fr-one** under
|
|
39
|
+
**`libs/rcv`**; this package stays on the **exdrf** / API side of that boundary.
|
|
40
|
+
|
|
41
|
+
Python **3.12.2+** is required. Install next to **exdrf** in the same
|
|
42
|
+
environment as **exdrf-gen-al2rcv** output.
|
|
43
|
+
|
|
44
|
+
## Related packages
|
|
45
|
+
|
|
46
|
+
- **exdrf-gen-al2rcv** — emits `{resource}_rcv_paths.py` scaffolds and root
|
|
47
|
+
**`api.py`** wired to your **`--get-db`** callable.
|
|
48
|
+
- **exdrf-gen-al2r** — sibling FastAPI router codegen; similar category layout.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# exdrf-rcv
|
|
2
|
+
|
|
3
|
+
The **remote-controlled-view (RCV)** stack renders **exdrf** resources and
|
|
4
|
+
related data into a user interface that the front end drives over HTTP.
|
|
5
|
+
|
|
6
|
+
**exdrf-rcv** is the **shared Python runtime** for RCV *backends*. It defines
|
|
7
|
+
**`RcvPlan`**, discriminated **`RcvField`** types, and helpers that
|
|
8
|
+
**`exdrf-gen-al2rcv`**-generated route modules import next to your FastAPI app.
|
|
9
|
+
|
|
10
|
+
The browser UI that consumes those endpoints lives in **fr-one** under
|
|
11
|
+
**`libs/rcv`**; this package stays on the **exdrf** / API side of that boundary.
|
|
12
|
+
|
|
13
|
+
Python **3.12.2+** is required. Install next to **exdrf** in the same
|
|
14
|
+
environment as **exdrf-gen-al2rcv** output.
|
|
15
|
+
|
|
16
|
+
## Related packages
|
|
17
|
+
|
|
18
|
+
- **exdrf-gen-al2rcv** — emits `{resource}_rcv_paths.py` scaffolds and root
|
|
19
|
+
**`api.py`** wired to your **`--get-db`** callable.
|
|
20
|
+
- **exdrf-gen-al2r** — sibling FastAPI router codegen; similar category layout.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Shared runtime for remote-controlled-view (RCV) backends.
|
|
2
|
+
|
|
3
|
+
``exdrf-gen-al2rcv`` emits modules that should import shared symbols from this
|
|
4
|
+
package as RCV behavior grows. The front-end RCV project is documented under
|
|
5
|
+
``fr-one`` ``libs/rcv``.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from exdrf_rcv.models import RcvField, RcvPlan, RcvResourceDataAccess
|
|
9
|
+
from exdrf_rcv.plan_resolve import (
|
|
10
|
+
RcvPlanCache,
|
|
11
|
+
RcvPlanCacheKey,
|
|
12
|
+
clear_rcv_plan_overrides,
|
|
13
|
+
default_rcv_plan_cache,
|
|
14
|
+
register_rcv_plan_override,
|
|
15
|
+
resolve_rcv_plan,
|
|
16
|
+
unregister_rcv_plan_override,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"RcvPlan",
|
|
21
|
+
"RcvField",
|
|
22
|
+
"RcvResourceDataAccess",
|
|
23
|
+
"RcvPlanCache",
|
|
24
|
+
"RcvPlanCacheKey",
|
|
25
|
+
"clear_rcv_plan_overrides",
|
|
26
|
+
"default_rcv_plan_cache",
|
|
27
|
+
"register_rcv_plan_override",
|
|
28
|
+
"resolve_rcv_plan",
|
|
29
|
+
"unregister_rcv_plan_override",
|
|
30
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Package version from PEP 621 or installed metadata."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from exdrf.pep621_version import distribution_version, version_tuple_from_string
|
|
8
|
+
|
|
9
|
+
_PYPROJECT = Path(__file__).resolve().parents[1] / "pyproject.toml"
|
|
10
|
+
_DIST_NAME = "exdrf-rcv"
|
|
11
|
+
|
|
12
|
+
__version__ = version = distribution_version(_DIST_NAME, _PYPROJECT)
|
|
13
|
+
__version_tuple__ = version_tuple = version_tuple_from_string(__version__)
|
|
14
|
+
|
|
15
|
+
__commit_id__ = commit_id = None
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"__version__",
|
|
19
|
+
"__version_tuple__",
|
|
20
|
+
"version",
|
|
21
|
+
"version_tuple",
|
|
22
|
+
"__commit_id__",
|
|
23
|
+
"commit_id",
|
|
24
|
+
]
|
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
"""Pydantic wire models for remote-controlled-view plans and field metadata.
|
|
2
|
+
|
|
3
|
+
``kind`` values mirror ``FIELD_TYPE_*`` in ``exdrf.constants``; ``data`` carries
|
|
4
|
+
type-specific options aligned with ``exdrf.field_types`` ``*Field`` /
|
|
5
|
+
``*Info`` shapes.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from datetime import date, datetime, time
|
|
11
|
+
from typing import Annotated, Any, Literal, Union
|
|
12
|
+
|
|
13
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
14
|
+
|
|
15
|
+
from exdrf.constants import (
|
|
16
|
+
FIELD_TYPE_BLOB,
|
|
17
|
+
FIELD_TYPE_BOOL,
|
|
18
|
+
FIELD_TYPE_DATE,
|
|
19
|
+
FIELD_TYPE_DT,
|
|
20
|
+
FIELD_TYPE_DURATION,
|
|
21
|
+
FIELD_TYPE_ENUM,
|
|
22
|
+
FIELD_TYPE_FILTER,
|
|
23
|
+
FIELD_TYPE_FLOAT,
|
|
24
|
+
FIELD_TYPE_FLOAT_LIST,
|
|
25
|
+
FIELD_TYPE_FORMATTED,
|
|
26
|
+
FIELD_TYPE_INT_LIST,
|
|
27
|
+
FIELD_TYPE_INTEGER,
|
|
28
|
+
FIELD_TYPE_REF_MANY_TO_MANY,
|
|
29
|
+
FIELD_TYPE_REF_MANY_TO_ONE,
|
|
30
|
+
FIELD_TYPE_REF_ONE_TO_MANY,
|
|
31
|
+
FIELD_TYPE_REF_ONE_TO_ONE,
|
|
32
|
+
FIELD_TYPE_SORT,
|
|
33
|
+
FIELD_TYPE_STRING,
|
|
34
|
+
FIELD_TYPE_STRING_LIST,
|
|
35
|
+
FIELD_TYPE_TIME,
|
|
36
|
+
RelType,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class RcvFieldBase(BaseModel):
|
|
41
|
+
"""Shared metadata for one field in an ``RcvPlan``.
|
|
42
|
+
|
|
43
|
+
Attributes:
|
|
44
|
+
name: Field name on the resource (snake_case).
|
|
45
|
+
title: Human-facing title when not inferred from ``name``.
|
|
46
|
+
description: Longer help text for the field.
|
|
47
|
+
category: Short logical grouping for layout.
|
|
48
|
+
pos_hint: UI ordering / placement hint from ``FieldInfo``.
|
|
49
|
+
required: Whether a value must be present for save/submit.
|
|
50
|
+
default: Wire default when omitted (type depends on ``kind``).
|
|
51
|
+
primary: Whether the field participates in record identity.
|
|
52
|
+
visible: Whether the field is shown to the user.
|
|
53
|
+
read_only: Whether the value is displayed but not editable.
|
|
54
|
+
nullable: Whether the underlying column allows null.
|
|
55
|
+
sortable: Whether list views may sort by this field.
|
|
56
|
+
filterable: Whether list views may filter by this field.
|
|
57
|
+
exportable: Whether user export may include this field.
|
|
58
|
+
qsearch: Whether quick-search uses this field.
|
|
59
|
+
resizable: Whether list column width is user-resizable.
|
|
60
|
+
derived: Optional ``(derivation_kind, source_field_name)`` tuple.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
model_config = ConfigDict(extra="forbid")
|
|
64
|
+
|
|
65
|
+
name: str
|
|
66
|
+
title: str | None = None
|
|
67
|
+
description: str | None = None
|
|
68
|
+
category: str | None = None
|
|
69
|
+
pos_hint: str | None = None
|
|
70
|
+
required: bool = False
|
|
71
|
+
default: Any | None = None
|
|
72
|
+
primary: bool | None = None
|
|
73
|
+
visible: bool | None = None
|
|
74
|
+
read_only: bool | None = None
|
|
75
|
+
nullable: bool | None = None
|
|
76
|
+
sortable: bool | None = None
|
|
77
|
+
filterable: bool | None = None
|
|
78
|
+
exportable: bool | None = None
|
|
79
|
+
qsearch: bool | None = None
|
|
80
|
+
resizable: bool | None = None
|
|
81
|
+
derived: tuple[str, str] | None = None
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class RcvEmptyData(BaseModel):
|
|
85
|
+
"""Placeholder ``data`` for field kinds without extra options."""
|
|
86
|
+
|
|
87
|
+
model_config = ConfigDict(extra="forbid")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class RcvBlobFieldData(BaseModel):
|
|
91
|
+
"""Options for ``FIELD_TYPE_BLOB`` (see ``BlobInfo``)."""
|
|
92
|
+
|
|
93
|
+
model_config = ConfigDict(extra="forbid")
|
|
94
|
+
|
|
95
|
+
mime_type: str | None = None
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class RcvBoolFieldData(BaseModel):
|
|
99
|
+
"""Options for ``FIELD_TYPE_BOOL`` (see ``BoolInfo``)."""
|
|
100
|
+
|
|
101
|
+
model_config = ConfigDict(extra="forbid")
|
|
102
|
+
|
|
103
|
+
true_str: str | None = None
|
|
104
|
+
false_str: str | None = None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class RcvStringFieldData(BaseModel):
|
|
108
|
+
"""Options for string-like kinds (see ``StrInfo`` / ``StrListInfo``)."""
|
|
109
|
+
|
|
110
|
+
model_config = ConfigDict(extra="forbid")
|
|
111
|
+
|
|
112
|
+
multiline: bool | None = None
|
|
113
|
+
min_length: int | None = None
|
|
114
|
+
max_length: int | None = None
|
|
115
|
+
enum_values: list[tuple[str, str]] = Field(default_factory=list)
|
|
116
|
+
no_dia_field: str | None = None
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class RcvFormattedFieldData(RcvStringFieldData):
|
|
120
|
+
"""Options for ``FIELD_TYPE_FORMATTED`` (see ``FormattedInfo``)."""
|
|
121
|
+
|
|
122
|
+
format: Literal["json", "html", "xml"] | None = None
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class RcvIntFieldData(BaseModel):
|
|
126
|
+
"""Options for ``FIELD_TYPE_INTEGER`` / ``FIELD_TYPE_INT_LIST``."""
|
|
127
|
+
|
|
128
|
+
model_config = ConfigDict(extra="forbid")
|
|
129
|
+
|
|
130
|
+
min: int | None = None
|
|
131
|
+
max: int | None = None
|
|
132
|
+
unit: str | None = None
|
|
133
|
+
unit_symbol: str | None = None
|
|
134
|
+
enum_values: list[tuple[int, str]] = Field(default_factory=list)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class RcvFloatFieldData(BaseModel):
|
|
138
|
+
"""Options for ``FIELD_TYPE_FLOAT`` / ``FIELD_TYPE_FLOAT_LIST``."""
|
|
139
|
+
|
|
140
|
+
model_config = ConfigDict(extra="forbid")
|
|
141
|
+
|
|
142
|
+
min: float | None = None
|
|
143
|
+
max: float | None = None
|
|
144
|
+
precision: int | None = None
|
|
145
|
+
scale: int | None = None
|
|
146
|
+
unit: str | None = None
|
|
147
|
+
unit_symbol: str | None = None
|
|
148
|
+
enum_values: list[tuple[float, str]] = Field(default_factory=list)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class RcvDateFieldData(BaseModel):
|
|
152
|
+
"""Options for ``FIELD_TYPE_DATE`` (see ``DateInfo`` + ``DateField``)."""
|
|
153
|
+
|
|
154
|
+
model_config = ConfigDict(extra="forbid")
|
|
155
|
+
|
|
156
|
+
min: date | None = None
|
|
157
|
+
max: date | None = None
|
|
158
|
+
format: str | None = None
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class RcvDateTimeFieldData(BaseModel):
|
|
162
|
+
"""Options for ``FIELD_TYPE_DT`` (``DateTimeInfo`` / ``DateTimeField``)."""
|
|
163
|
+
|
|
164
|
+
model_config = ConfigDict(extra="forbid")
|
|
165
|
+
|
|
166
|
+
min: datetime | None = None
|
|
167
|
+
max: datetime | None = None
|
|
168
|
+
format: str | None = None
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class RcvTimeFieldData(BaseModel):
|
|
172
|
+
"""Options for ``FIELD_TYPE_TIME`` (see ``TimeInfo`` + ``TimeField``)."""
|
|
173
|
+
|
|
174
|
+
model_config = ConfigDict(extra="forbid")
|
|
175
|
+
|
|
176
|
+
min: time | None = None
|
|
177
|
+
max: time | None = None
|
|
178
|
+
format: str | None = None
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class RcvDurationFieldData(BaseModel):
|
|
182
|
+
"""Options for ``FIELD_TYPE_DURATION`` (see ``DurationInfo``)."""
|
|
183
|
+
|
|
184
|
+
model_config = ConfigDict(extra="forbid")
|
|
185
|
+
|
|
186
|
+
min: float | None = None
|
|
187
|
+
max: float | None = None
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class RcvEnumFieldData(BaseModel):
|
|
191
|
+
"""Options for ``FIELD_TYPE_ENUM`` (see ``EnumInfo`` / ``EnumField``)."""
|
|
192
|
+
|
|
193
|
+
model_config = ConfigDict(extra="forbid")
|
|
194
|
+
|
|
195
|
+
enum_values: list[str] = Field(default_factory=list)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class RcvRefFieldData(BaseModel):
|
|
199
|
+
"""Options for relation kinds (see ``RelExtraInfo`` / ``RefBaseField``)."""
|
|
200
|
+
|
|
201
|
+
model_config = ConfigDict(extra="forbid")
|
|
202
|
+
|
|
203
|
+
ref: str
|
|
204
|
+
direction: RelType | None = None
|
|
205
|
+
subordinate: bool | None = None
|
|
206
|
+
expect_lots: bool | None = None
|
|
207
|
+
provides: list[str] = Field(default_factory=list)
|
|
208
|
+
depends_on: list[tuple[str, str]] = Field(default_factory=list)
|
|
209
|
+
bridge: str | None = None
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class RcvBlobField(RcvFieldBase):
|
|
213
|
+
"""RCV descriptor for a blob column."""
|
|
214
|
+
|
|
215
|
+
kind: Literal["blob"] = FIELD_TYPE_BLOB
|
|
216
|
+
data: RcvBlobFieldData = Field(default_factory=RcvBlobFieldData)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class RcvBoolField(RcvFieldBase):
|
|
220
|
+
"""RCV descriptor for a boolean column."""
|
|
221
|
+
|
|
222
|
+
kind: Literal["bool"] = FIELD_TYPE_BOOL
|
|
223
|
+
data: RcvBoolFieldData = Field(default_factory=RcvBoolFieldData)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
class RcvDateField(RcvFieldBase):
|
|
227
|
+
"""RCV descriptor for a date column."""
|
|
228
|
+
|
|
229
|
+
kind: Literal["date"] = FIELD_TYPE_DATE
|
|
230
|
+
data: RcvDateFieldData = Field(default_factory=RcvDateFieldData)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class RcvDateTimeField(RcvFieldBase):
|
|
234
|
+
"""RCV descriptor for a date-time column."""
|
|
235
|
+
|
|
236
|
+
kind: Literal["date-time"] = FIELD_TYPE_DT
|
|
237
|
+
data: RcvDateTimeFieldData = Field(default_factory=RcvDateTimeFieldData)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class RcvDurationField(RcvFieldBase):
|
|
241
|
+
"""RCV descriptor for a duration column."""
|
|
242
|
+
|
|
243
|
+
kind: Literal["duration"] = FIELD_TYPE_DURATION
|
|
244
|
+
data: RcvDurationFieldData = Field(default_factory=RcvDurationFieldData)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
class RcvEnumField(RcvFieldBase):
|
|
248
|
+
"""RCV descriptor for an enum-like column."""
|
|
249
|
+
|
|
250
|
+
kind: Literal["enum"] = FIELD_TYPE_ENUM
|
|
251
|
+
data: RcvEnumFieldData = Field(default_factory=RcvEnumFieldData)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
class RcvFilterField(RcvFieldBase):
|
|
255
|
+
"""RCV descriptor for a filter pseudo-field."""
|
|
256
|
+
|
|
257
|
+
kind: Literal["filter"] = FIELD_TYPE_FILTER
|
|
258
|
+
data: RcvEmptyData = Field(default_factory=RcvEmptyData)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class RcvFloatField(RcvFieldBase):
|
|
262
|
+
"""RCV descriptor for a float column."""
|
|
263
|
+
|
|
264
|
+
kind: Literal["float"] = FIELD_TYPE_FLOAT
|
|
265
|
+
data: RcvFloatFieldData = Field(default_factory=RcvFloatFieldData)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
class RcvFloatListField(RcvFieldBase):
|
|
269
|
+
"""RCV descriptor for a float list column."""
|
|
270
|
+
|
|
271
|
+
kind: Literal["float-list"] = FIELD_TYPE_FLOAT_LIST
|
|
272
|
+
data: RcvFloatFieldData = Field(default_factory=RcvFloatFieldData)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class RcvFormattedField(RcvFieldBase):
|
|
276
|
+
"""RCV descriptor for formatted (rich text / markup) string columns."""
|
|
277
|
+
|
|
278
|
+
kind: Literal["formatted"] = FIELD_TYPE_FORMATTED
|
|
279
|
+
data: RcvFormattedFieldData = Field(default_factory=RcvFormattedFieldData)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
class RcvIntField(RcvFieldBase):
|
|
283
|
+
"""RCV descriptor for an integer column."""
|
|
284
|
+
|
|
285
|
+
kind: Literal["integer"] = FIELD_TYPE_INTEGER
|
|
286
|
+
data: RcvIntFieldData = Field(default_factory=RcvIntFieldData)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class RcvIntListField(RcvFieldBase):
|
|
290
|
+
"""RCV descriptor for an integer list column."""
|
|
291
|
+
|
|
292
|
+
kind: Literal["int-list"] = FIELD_TYPE_INT_LIST
|
|
293
|
+
data: RcvIntFieldData = Field(default_factory=RcvIntFieldData)
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
class RcvManyToManyField(RcvFieldBase):
|
|
297
|
+
"""RCV descriptor for a many-to-many relation field."""
|
|
298
|
+
|
|
299
|
+
kind: Literal["many-to-many"] = FIELD_TYPE_REF_MANY_TO_MANY
|
|
300
|
+
data: RcvRefFieldData
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
class RcvManyToOneField(RcvFieldBase):
|
|
304
|
+
"""RCV descriptor for a many-to-one relation field."""
|
|
305
|
+
|
|
306
|
+
kind: Literal["many-to-one"] = FIELD_TYPE_REF_MANY_TO_ONE
|
|
307
|
+
data: RcvRefFieldData
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
class RcvOneToManyField(RcvFieldBase):
|
|
311
|
+
"""RCV descriptor for a one-to-many relation field."""
|
|
312
|
+
|
|
313
|
+
kind: Literal["one-to-many"] = FIELD_TYPE_REF_ONE_TO_MANY
|
|
314
|
+
data: RcvRefFieldData
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
class RcvOneToOneField(RcvFieldBase):
|
|
318
|
+
"""RCV descriptor for a one-to-one relation field."""
|
|
319
|
+
|
|
320
|
+
kind: Literal["one-to-one"] = FIELD_TYPE_REF_ONE_TO_ONE
|
|
321
|
+
data: RcvRefFieldData
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
class RcvStringField(RcvFieldBase):
|
|
325
|
+
"""RCV descriptor for a string column."""
|
|
326
|
+
|
|
327
|
+
kind: Literal["string"] = FIELD_TYPE_STRING
|
|
328
|
+
data: RcvStringFieldData = Field(default_factory=RcvStringFieldData)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
class RcvStringListField(RcvFieldBase):
|
|
332
|
+
"""RCV descriptor for a string list column."""
|
|
333
|
+
|
|
334
|
+
kind: Literal["string-list"] = FIELD_TYPE_STRING_LIST
|
|
335
|
+
data: RcvStringFieldData = Field(default_factory=RcvStringFieldData)
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
class RcvSortField(RcvFieldBase):
|
|
339
|
+
"""RCV descriptor for a sort pseudo-field."""
|
|
340
|
+
|
|
341
|
+
kind: Literal["sort"] = FIELD_TYPE_SORT
|
|
342
|
+
data: RcvEmptyData = Field(default_factory=RcvEmptyData)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
class RcvTimeField(RcvFieldBase):
|
|
346
|
+
"""RCV descriptor for a time-of-day column."""
|
|
347
|
+
|
|
348
|
+
kind: Literal["time"] = FIELD_TYPE_TIME
|
|
349
|
+
data: RcvTimeFieldData = Field(default_factory=RcvTimeFieldData)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
RcvField = Annotated[
|
|
353
|
+
Union[
|
|
354
|
+
RcvBlobField,
|
|
355
|
+
RcvBoolField,
|
|
356
|
+
RcvDateField,
|
|
357
|
+
RcvDateTimeField,
|
|
358
|
+
RcvDurationField,
|
|
359
|
+
RcvEnumField,
|
|
360
|
+
RcvFilterField,
|
|
361
|
+
RcvFloatField,
|
|
362
|
+
RcvFloatListField,
|
|
363
|
+
RcvFormattedField,
|
|
364
|
+
RcvIntField,
|
|
365
|
+
RcvIntListField,
|
|
366
|
+
RcvManyToManyField,
|
|
367
|
+
RcvManyToOneField,
|
|
368
|
+
RcvOneToManyField,
|
|
369
|
+
RcvOneToOneField,
|
|
370
|
+
RcvSortField,
|
|
371
|
+
RcvStringField,
|
|
372
|
+
RcvStringListField,
|
|
373
|
+
RcvTimeField,
|
|
374
|
+
],
|
|
375
|
+
Field(discriminator="kind"),
|
|
376
|
+
]
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
class RcvResourceDataAccess(BaseModel):
|
|
380
|
+
"""Where and how to load row payloads for this plan over HTTP.
|
|
381
|
+
|
|
382
|
+
Used for list data, edit/view refresh, and similar flows. The client should
|
|
383
|
+
prepend its API base (including ``root_path``) to ``url_pattern`` when
|
|
384
|
+
building the final request URL.
|
|
385
|
+
|
|
386
|
+
Attributes:
|
|
387
|
+
url_pattern: Path under the API root, typically an exdrf-gen-al2r list
|
|
388
|
+
GET path such as ``/classic/{category}/{resource_plural}/``. May later include
|
|
389
|
+
placeholders (for example ``{record_id}``) documented alongside
|
|
390
|
+
those features.
|
|
391
|
+
requires_org_id: When true, the client must include an ``org_id`` query
|
|
392
|
+
parameter (or the convention documented for this deployment) when
|
|
393
|
+
calling ``url_pattern``.
|
|
394
|
+
requires_town_id: When true, the client must include a ``town_id`` query
|
|
395
|
+
parameter when calling ``url_pattern``.
|
|
396
|
+
"""
|
|
397
|
+
|
|
398
|
+
model_config = ConfigDict(extra="forbid")
|
|
399
|
+
|
|
400
|
+
url_pattern: str
|
|
401
|
+
requires_org_id: bool = False
|
|
402
|
+
requires_town_id: bool = False
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
class RcvPlan(BaseModel):
|
|
406
|
+
"""A plan for rendering a resource, record and view type.
|
|
407
|
+
|
|
408
|
+
Attributes:
|
|
409
|
+
category: The category of the resource. In most cases this will be the
|
|
410
|
+
same as the value passed by the front-end.
|
|
411
|
+
resource: The name of the resource. In most cases this will be the
|
|
412
|
+
same as the value passed by the front-end.
|
|
413
|
+
record_id: The ID of the record. In most cases this will be the
|
|
414
|
+
same as the value passed by the front-end.
|
|
415
|
+
view_type: The type of view that is requested. In most cases this
|
|
416
|
+
will be the same as the value passed by the front-end.
|
|
417
|
+
render_type: The type of renderer to use. When a generated module omits
|
|
418
|
+
``RCV_RENDER_TYPE`` or sets it to the placeholder ``"default"``,
|
|
419
|
+
:func:`exdrf_rcv.plan_resolve.resolve_rcv_plan` sets this to the
|
|
420
|
+
same value as ``view_type``.
|
|
421
|
+
fields: The fields to render.
|
|
422
|
+
resource_data_access: Optional hint for loading tabular row data or
|
|
423
|
+
refreshing a record from HTTP; omitted when the generated module
|
|
424
|
+
does not define ``RCV_RESOURCE_DATA_ACCESS``.
|
|
425
|
+
"""
|
|
426
|
+
|
|
427
|
+
model_config = ConfigDict(extra="forbid")
|
|
428
|
+
|
|
429
|
+
category: str | None = None
|
|
430
|
+
resource: str | None = None
|
|
431
|
+
record_id: int | None = None
|
|
432
|
+
view_type: str | None = None
|
|
433
|
+
render_type: str
|
|
434
|
+
fields: list[RcvField]
|
|
435
|
+
resource_data_access: RcvResourceDataAccess | None = None
|