Skip to content

Commit 6e92682

Browse files
♻️ Extract workbench from projects to projects_nodes table 🗃️ (ITISFoundation#7010)
1 parent 272671c commit 6e92682

File tree

51 files changed

+673
-166
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+673
-166
lines changed

packages/models-library/src/models_library/api_schemas_webserver/projects_nodes.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from ..api_schemas_directorv2.dynamic_services import RetrieveDataOut
77
from ..basic_types import PortInt
8-
from ..projects_nodes import InputID, InputsDict
8+
from ..projects_nodes import InputID, InputsDict, PartialNode
99
from ..projects_nodes_io import NodeID
1010
from ..services import ServiceKey, ServicePortKey, ServiceVersion
1111
from ..services_enums import ServiceState
@@ -26,14 +26,26 @@ class NodeCreate(InputSchemaWithoutCamelCase):
2626

2727

2828
class NodePatch(InputSchemaWithoutCamelCase):
29-
service_key: ServiceKey | None = Field(default=None, alias="key")
30-
service_version: ServiceVersion | None = Field(default=None, alias="version")
31-
label: str | None = Field(default=None)
29+
service_key: Annotated[
30+
ServiceKey | None,
31+
Field(alias="key"),
32+
] = None
33+
service_version: Annotated[
34+
ServiceVersion | None,
35+
Field(alias="version"),
36+
] = None
37+
label: str | None = None
3238
inputs: Annotated[
3339
InputsDict, Field(default_factory=dict, json_schema_extra={"default": {}})
3440
]
35-
inputs_required: list[InputID] | None = Field(default=None, alias="inputsRequired")
36-
input_nodes: list[NodeID] | None = Field(default=None, alias="inputNodes")
41+
inputs_required: Annotated[
42+
list[InputID] | None,
43+
Field(alias="inputsRequired"),
44+
] = None
45+
input_nodes: Annotated[
46+
list[NodeID] | None,
47+
Field(alias="inputNodes"),
48+
] = None
3749
progress: Annotated[
3850
float | None,
3951
Field(
@@ -47,6 +59,13 @@ class NodePatch(InputSchemaWithoutCamelCase):
4759
str, Any
4860
] | None = None # NOTE: it is used by frontend for File Picker
4961

62+
def to_domain_model(self) -> PartialNode:
63+
data = self.model_dump(
64+
exclude_unset=True,
65+
by_alias=True,
66+
)
67+
return PartialNode.model_construct(**data)
68+
5069

5170
class NodeCreated(OutputSchema):
5271
node_id: NodeID

packages/models-library/src/models_library/projects_nodes.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,3 +274,9 @@ def _convert_from_enum(cls, v):
274274
extra="forbid",
275275
populate_by_name=True,
276276
)
277+
278+
279+
class PartialNode(Node):
280+
key: Annotated[ServiceKey, Field(default=None)]
281+
version: Annotated[ServiceVersion, Field(default=None)]
282+
label: Annotated[str, Field(default=None)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
"""extract workbench column
2+
3+
Revision ID: ecd4eadaa781
4+
Revises: a3a58471b0f1
5+
Create Date: 2025-01-21 13:13:18.256109+00:00
6+
7+
"""
8+
import sqlalchemy as sa
9+
from alembic import op
10+
from sqlalchemy.dialects import postgresql
11+
12+
# revision identifiers, used by Alembic.
13+
revision = "ecd4eadaa781"
14+
down_revision = "a3a58471b0f1"
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.add_column(
22+
"projects_nodes",
23+
sa.Column(
24+
"key",
25+
sa.String(),
26+
nullable=False,
27+
comment="Distinctive name (based on the Docker registry path)",
28+
),
29+
)
30+
op.add_column(
31+
"projects_nodes",
32+
sa.Column(
33+
"version", sa.String(), nullable=False, comment="Semantic version number"
34+
),
35+
)
36+
op.add_column(
37+
"projects_nodes",
38+
sa.Column(
39+
"label", sa.String(), nullable=False, comment="Short name used for display"
40+
),
41+
)
42+
op.add_column(
43+
"projects_nodes",
44+
sa.Column(
45+
"progress", sa.Numeric(), nullable=True, comment="Progress value (0-100)"
46+
),
47+
)
48+
op.add_column(
49+
"projects_nodes",
50+
sa.Column(
51+
"thumbnail",
52+
sa.String(),
53+
nullable=True,
54+
comment="Url of the latest screenshot",
55+
),
56+
)
57+
op.add_column(
58+
"projects_nodes",
59+
sa.Column(
60+
"input_access",
61+
postgresql.JSONB(astext_type=sa.Text()),
62+
nullable=True,
63+
comment="Map with key - access level pairs",
64+
),
65+
)
66+
op.add_column(
67+
"projects_nodes",
68+
sa.Column(
69+
"input_nodes",
70+
postgresql.JSONB(astext_type=sa.Text()),
71+
nullable=True,
72+
comment="IDs of the nodes where is connected to",
73+
),
74+
)
75+
op.add_column(
76+
"projects_nodes",
77+
sa.Column(
78+
"inputs",
79+
postgresql.JSONB(astext_type=sa.Text()),
80+
nullable=True,
81+
comment="Input properties values",
82+
),
83+
)
84+
op.add_column(
85+
"projects_nodes",
86+
sa.Column(
87+
"inputs_required",
88+
postgresql.JSONB(astext_type=sa.Text()),
89+
nullable=True,
90+
comment="Required input IDs",
91+
),
92+
)
93+
op.add_column(
94+
"projects_nodes",
95+
sa.Column(
96+
"inputs_units",
97+
postgresql.JSONB(astext_type=sa.Text()),
98+
nullable=True,
99+
comment="Input units",
100+
),
101+
)
102+
op.add_column(
103+
"projects_nodes",
104+
sa.Column(
105+
"output_nodes",
106+
postgresql.JSONB(astext_type=sa.Text()),
107+
nullable=True,
108+
comment="Node IDs of those connected to the output",
109+
),
110+
)
111+
op.add_column(
112+
"projects_nodes",
113+
sa.Column(
114+
"outputs",
115+
postgresql.JSONB(astext_type=sa.Text()),
116+
nullable=True,
117+
comment="Output properties values",
118+
),
119+
)
120+
op.add_column(
121+
"projects_nodes",
122+
sa.Column(
123+
"run_hash",
124+
sa.String(),
125+
nullable=True,
126+
comment="HEX digest of the resolved inputs + outputs hash at the time when the last outputs were generated",
127+
),
128+
)
129+
op.add_column(
130+
"projects_nodes",
131+
sa.Column(
132+
"state",
133+
postgresql.JSONB(astext_type=sa.Text()),
134+
nullable=True,
135+
comment="State",
136+
),
137+
)
138+
op.add_column(
139+
"projects_nodes",
140+
sa.Column(
141+
"parent",
142+
sa.String(),
143+
nullable=True,
144+
comment="Parent's (group-nodes) node ID",
145+
),
146+
)
147+
op.add_column(
148+
"projects_nodes",
149+
sa.Column(
150+
"boot_options",
151+
postgresql.JSONB(astext_type=sa.Text()),
152+
nullable=True,
153+
comment="Some services provide alternative parameters to be injected at boot time.The user selection should be stored here, and it will overwrite the services's defaults",
154+
),
155+
)
156+
# ### end Alembic commands ###
157+
158+
op.execute(
159+
"""
160+
UPDATE projects_nodes
161+
SET key = subquery.key,
162+
version = subquery.version,
163+
label = subquery.label,
164+
progress = subquery.progress::numeric,
165+
thumbnail = subquery.thumbnail,
166+
input_access = subquery.input_access::jsonb,
167+
input_nodes = subquery.input_nodes::jsonb,
168+
inputs = subquery.inputs::jsonb,
169+
inputs_required = subquery.inputs_required::jsonb,
170+
inputs_units = subquery.inputs_units::jsonb,
171+
output_nodes = subquery.output_nodes::jsonb,
172+
outputs = subquery.outputs::jsonb,
173+
run_hash = subquery.run_hash,
174+
state = subquery.state::jsonb,
175+
parent = subquery.parent,
176+
boot_options = subquery.boot_options::jsonb
177+
FROM (
178+
SELECT
179+
projects.uuid AS project_id,
180+
js.key AS node_id,
181+
js.value::jsonb ->> 'key' AS key,
182+
js.value::jsonb ->> 'label' AS label,
183+
js.value::jsonb ->> 'version' AS version,
184+
(js.value::jsonb ->> 'progress')::numeric AS progress,
185+
js.value::jsonb ->> 'thumbnail' AS thumbnail,
186+
js.value::jsonb ->> 'inputAccess' AS input_access,
187+
js.value::jsonb ->> 'inputNodes' AS input_nodes,
188+
js.value::jsonb ->> 'inputs' AS inputs,
189+
js.value::jsonb ->> 'inputsRequired' AS inputs_required,
190+
js.value::jsonb ->> 'inputsUnits' AS inputs_units,
191+
js.value::jsonb ->> 'outputNodes' AS output_nodes,
192+
js.value::jsonb ->> 'outputs' AS outputs,
193+
js.value::jsonb ->> 'runHash' AS run_hash,
194+
js.value::jsonb ->> 'state' AS state,
195+
js.value::jsonb ->> 'parent' AS parent,
196+
js.value::jsonb ->> 'bootOptions' AS boot_options
197+
FROM projects,
198+
json_each(projects.workbench) AS js
199+
) AS subquery
200+
WHERE projects_nodes.project_uuid = subquery.project_id
201+
AND projects_nodes.node_id = subquery.node_id;
202+
"""
203+
)
204+
op.alter_column("projects_nodes", "key", nullable=False)
205+
op.alter_column("projects_nodes", "version", nullable=False)
206+
op.alter_column("projects_nodes", "label", nullable=False)
207+
208+
209+
def downgrade():
210+
# ### commands auto generated by Alembic - please adjust! ###
211+
op.drop_column("projects_nodes", "boot_options")
212+
op.drop_column("projects_nodes", "parent")
213+
op.drop_column("projects_nodes", "state")
214+
op.drop_column("projects_nodes", "run_hash")
215+
op.drop_column("projects_nodes", "outputs")
216+
op.drop_column("projects_nodes", "output_nodes")
217+
op.drop_column("projects_nodes", "inputs_units")
218+
op.drop_column("projects_nodes", "inputs_required")
219+
op.drop_column("projects_nodes", "inputs")
220+
op.drop_column("projects_nodes", "input_nodes")
221+
op.drop_column("projects_nodes", "input_access")
222+
op.drop_column("projects_nodes", "thumbnail")
223+
op.drop_column("projects_nodes", "progress")
224+
op.drop_column("projects_nodes", "label")
225+
op.drop_column("projects_nodes", "version")
226+
op.drop_column("projects_nodes", "key")
227+
# ### end Alembic commands ###

0 commit comments

Comments
 (0)