Flowfile 0.3.9__py3-none-any.whl → 0.5.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.
- flowfile/__init__.py +8 -1
- flowfile/api.py +1 -3
- flowfile/web/static/assets/{CloudConnectionManager-c97c25f8.js → CloudConnectionManager-0dfba9f2.js} +2 -2
- flowfile/web/static/assets/{CloudStorageReader-f1ff509e.js → CloudStorageReader-d5b1b6c9.js} +11 -78
- flowfile/web/static/assets/{CloudStorageWriter-034f8b78.js → CloudStorageWriter-00d87aad.js} +12 -79
- flowfile/web/static/assets/{CloudStorageWriter-49c9a4b2.css → CloudStorageWriter-b0ee067f.css} +24 -24
- flowfile/web/static/assets/ColumnSelector-4685e75d.js +83 -0
- flowfile/web/static/assets/ColumnSelector-47996a16.css +10 -0
- flowfile/web/static/assets/ContextMenu-23e909da.js +41 -0
- flowfile/web/static/assets/{SettingsSection-9c836ecc.css → ContextMenu-4c74eef1.css} +0 -21
- flowfile/web/static/assets/ContextMenu-63cfa99b.css +26 -0
- flowfile/web/static/assets/ContextMenu-70ae0c79.js +41 -0
- flowfile/web/static/assets/ContextMenu-c13f91d0.css +26 -0
- flowfile/web/static/assets/ContextMenu-f149cf7c.js +41 -0
- flowfile/web/static/assets/{CrossJoin-41efa4cb.css → CrossJoin-1119d18e.css} +18 -18
- flowfile/web/static/assets/{CrossJoin-9e156ebe.js → CrossJoin-702a3edd.js} +14 -84
- flowfile/web/static/assets/CustomNode-74a37f74.css +32 -0
- flowfile/web/static/assets/CustomNode-b1519993.js +211 -0
- flowfile/web/static/assets/{DatabaseConnectionSettings-d5c625b3.js → DatabaseConnectionSettings-6f3e4ea5.js} +3 -3
- flowfile/web/static/assets/{DatabaseManager-265adc5e.js → DatabaseManager-cf5ef661.js} +2 -2
- flowfile/web/static/assets/{DatabaseReader-f50c6558.css → DatabaseReader-ae61773c.css} +0 -27
- flowfile/web/static/assets/{DatabaseReader-0b10551e.js → DatabaseReader-d38c7295.js} +14 -114
- flowfile/web/static/assets/{DatabaseWriter-c17c6916.js → DatabaseWriter-b04ef46a.js} +13 -74
- flowfile/web/static/assets/{ExploreData-5bdae813.css → ExploreData-2d0cf4db.css} +8 -14
- flowfile/web/static/assets/ExploreData-5fa10ed8.js +192 -0
- flowfile/web/static/assets/{ExternalSource-3a66556c.js → ExternalSource-d39af878.js} +8 -79
- flowfile/web/static/assets/{Filter-91ad87e7.js → Filter-9b6d08db.js} +12 -85
- flowfile/web/static/assets/{Filter-a9d08ba1.css → Filter-f62091b3.css} +3 -3
- flowfile/web/static/assets/{Formula-3c395ab1.js → Formula-6b04fb1d.js} +20 -87
- flowfile/web/static/assets/{Formula-29f19d21.css → Formula-bb96803d.css} +4 -4
- flowfile/web/static/assets/{FuzzyMatch-6857de82.css → FuzzyMatch-1010f966.css} +42 -42
- flowfile/web/static/assets/{FuzzyMatch-2df0d230.js → FuzzyMatch-999521f4.js} +16 -87
- flowfile/web/static/assets/{GraphSolver-d285877f.js → GraphSolver-17dd2198.js} +13 -159
- flowfile/web/static/assets/GraphSolver-f0cb7bfb.css +22 -0
- flowfile/web/static/assets/{GroupBy-0bd1cc6b.js → GroupBy-6b039e18.js} +12 -75
- flowfile/web/static/assets/{Unique-b5615727.css → GroupBy-b9505323.css} +8 -8
- flowfile/web/static/assets/{Join-5a78a203.js → Join-24d0f113.js} +15 -85
- flowfile/web/static/assets/{Join-f45eff22.css → Join-fd79b451.css} +20 -20
- flowfile/web/static/assets/{ManualInput-a71b52c6.css → ManualInput-3246a08d.css} +20 -20
- flowfile/web/static/assets/{ManualInput-93aef9d6.js → ManualInput-34639209.js} +11 -82
- flowfile/web/static/assets/MultiSelect-0e8724a3.js +5 -0
- flowfile/web/static/assets/MultiSelect.vue_vue_type_script_setup_true_lang-b0e538c2.js +63 -0
- flowfile/web/static/assets/NumericInput-3d63a470.js +5 -0
- flowfile/web/static/assets/NumericInput.vue_vue_type_script_setup_true_lang-e0edeccc.js +35 -0
- flowfile/web/static/assets/Output-283fe388.css +37 -0
- flowfile/web/static/assets/{Output-411ecaee.js → Output-edea9802.js} +62 -273
- flowfile/web/static/assets/{Pivot-89db4b04.js → Pivot-61d19301.js} +14 -138
- flowfile/web/static/assets/Pivot-cf333e3d.css +22 -0
- flowfile/web/static/assets/PivotValidation-891ddfb0.css +13 -0
- flowfile/web/static/assets/PivotValidation-c46cd420.css +13 -0
- flowfile/web/static/assets/PivotValidation-de9f43fe.js +61 -0
- flowfile/web/static/assets/PivotValidation-f97fec5b.js +61 -0
- flowfile/web/static/assets/{PolarsCode-a9f974f8.js → PolarsCode-bc3c9984.js} +13 -80
- flowfile/web/static/assets/Read-64a3f259.js +218 -0
- flowfile/web/static/assets/Read-e808b239.css +62 -0
- flowfile/web/static/assets/RecordCount-3d5039be.js +53 -0
- flowfile/web/static/assets/{RecordId-55ae7d36.js → RecordId-597510e0.js} +8 -80
- flowfile/web/static/assets/SQLQueryComponent-36cef432.css +27 -0
- flowfile/web/static/assets/SQLQueryComponent-df51adbe.js +38 -0
- flowfile/web/static/assets/{Sample-b4a18476.js → Sample-4be0a507.js} +8 -77
- flowfile/web/static/assets/{SecretManager-b066d13a.js → SecretManager-4839be57.js} +2 -2
- flowfile/web/static/assets/{Select-727688dc.js → Select-9b72f201.js} +11 -85
- flowfile/web/static/assets/SettingsSection-2e4d03c4.css +21 -0
- flowfile/web/static/assets/SettingsSection-5c696bee.css +20 -0
- flowfile/web/static/assets/SettingsSection-71e6b7e3.css +21 -0
- flowfile/web/static/assets/SettingsSection-7ded385d.js +45 -0
- flowfile/web/static/assets/{SettingsSection-695ac487.js → SettingsSection-e1e9c953.js} +2 -40
- flowfile/web/static/assets/SettingsSection-f0f75a42.js +53 -0
- flowfile/web/static/assets/SingleSelect-6c777aac.js +5 -0
- flowfile/web/static/assets/SingleSelect.vue_vue_type_script_setup_true_lang-33e3ff9b.js +62 -0
- flowfile/web/static/assets/SliderInput-7cb93e62.js +40 -0
- flowfile/web/static/assets/SliderInput-b8fb6a8c.css +4 -0
- flowfile/web/static/assets/{GroupBy-ab1ea74b.css → Sort-3643d625.css} +8 -8
- flowfile/web/static/assets/{Sort-be3339a8.js → Sort-6cbde21a.js} +12 -97
- flowfile/web/static/assets/TextInput-d9a40c11.js +5 -0
- flowfile/web/static/assets/TextInput.vue_vue_type_script_setup_true_lang-5896c375.js +32 -0
- flowfile/web/static/assets/{TextToRows-c92d1ec2.css → TextToRows-5d2c1190.css} +9 -9
- flowfile/web/static/assets/{TextToRows-7b8998da.js → TextToRows-c4fcbf4d.js} +14 -83
- flowfile/web/static/assets/ToggleSwitch-4ef91d19.js +5 -0
- flowfile/web/static/assets/ToggleSwitch.vue_vue_type_script_setup_true_lang-38478c20.js +31 -0
- flowfile/web/static/assets/{UnavailableFields-8b0cb48e.js → UnavailableFields-a03f512c.js} +2 -2
- flowfile/web/static/assets/{Union-8d9ac7f9.css → Union-af6c3d9b.css} +6 -6
- flowfile/web/static/assets/Union-bfe9b996.js +77 -0
- flowfile/web/static/assets/{Unique-af5a80b4.js → Unique-5d023a27.js} +23 -104
- flowfile/web/static/assets/{Sort-7ccfa0fe.css → Unique-f9fb0809.css} +8 -8
- flowfile/web/static/assets/Unpivot-1e422df3.css +30 -0
- flowfile/web/static/assets/{Unpivot-5195d411.js → Unpivot-91cc5354.js} +12 -166
- flowfile/web/static/assets/UnpivotValidation-0d240eeb.css +13 -0
- flowfile/web/static/assets/UnpivotValidation-7ee2de44.js +51 -0
- flowfile/web/static/assets/{ExploreData-18a4fe52.js → VueGraphicWalker-e51b9924.js} +4 -264
- flowfile/web/static/assets/VueGraphicWalker-ed5ab88b.css +6 -0
- flowfile/web/static/assets/{api-cb00cce6.js → api-c1bad5ca.js} +1 -1
- flowfile/web/static/assets/{api-023d1733.js → api-cf1221f0.js} +1 -1
- flowfile/web/static/assets/{designer-2197d782.css → designer-8da3ba3a.css} +859 -201
- flowfile/web/static/assets/{designer-6c322d8e.js → designer-9633482a.js} +2297 -733
- flowfile/web/static/assets/{documentation-4d1fafe1.js → documentation-ca400224.js} +1 -1
- flowfile/web/static/assets/{dropDown-0b46dd77.js → dropDown-614b998d.js} +1 -1
- flowfile/web/static/assets/{fullEditor-ec4e4f95.js → fullEditor-f7971590.js} +2 -2
- flowfile/web/static/assets/{genericNodeSettings-def5879b.js → genericNodeSettings-4fe5f36b.js} +3 -3
- flowfile/web/static/assets/{index-681a3ed0.css → index-50508d4d.css} +8 -0
- flowfile/web/static/assets/{index-683fc198.js → index-5429bbf8.js} +208 -31
- flowfile/web/static/assets/nodeInput-5d0d6b79.js +41 -0
- flowfile/web/static/assets/outputCsv-076b85ab.js +86 -0
- flowfile/web/static/assets/{Output-48f81019.css → outputCsv-9cc59e0b.css} +0 -143
- flowfile/web/static/assets/outputExcel-0fd17dbe.js +56 -0
- flowfile/web/static/assets/outputExcel-b41305c0.css +102 -0
- flowfile/web/static/assets/outputParquet-b61e0847.js +31 -0
- flowfile/web/static/assets/outputParquet-cf8cf3f2.css +4 -0
- flowfile/web/static/assets/readCsv-a8bb8b61.js +179 -0
- flowfile/web/static/assets/readCsv-c767cb37.css +52 -0
- flowfile/web/static/assets/readExcel-67b4aee0.js +201 -0
- flowfile/web/static/assets/readExcel-806d2826.css +64 -0
- flowfile/web/static/assets/readParquet-48c81530.css +19 -0
- flowfile/web/static/assets/readParquet-92ce1dbc.js +23 -0
- flowfile/web/static/assets/{secretApi-baceb6f9.js → secretApi-68435402.js} +1 -1
- flowfile/web/static/assets/{selectDynamic-de91449a.js → selectDynamic-92e25ee3.js} +7 -7
- flowfile/web/static/assets/{selectDynamic-b062bc9b.css → selectDynamic-aa913ff4.css} +16 -16
- flowfile/web/static/assets/user-defined-icon-0ae16c90.png +0 -0
- flowfile/web/static/assets/{vue-codemirror.esm-dc5e3348.js → vue-codemirror.esm-41b0e0d7.js} +65 -36
- flowfile/web/static/assets/{vue-content-loader.es-ba94b82f.js → vue-content-loader.es-2c8e608f.js} +1 -1
- flowfile/web/static/index.html +2 -2
- {flowfile-0.3.9.dist-info → flowfile-0.5.1.dist-info}/METADATA +5 -3
- {flowfile-0.3.9.dist-info → flowfile-0.5.1.dist-info}/RECORD +191 -121
- {flowfile-0.3.9.dist-info → flowfile-0.5.1.dist-info}/WHEEL +1 -1
- {flowfile-0.3.9.dist-info → flowfile-0.5.1.dist-info}/entry_points.txt +1 -0
- flowfile_core/__init__.py +3 -0
- flowfile_core/configs/flow_logger.py +5 -13
- flowfile_core/configs/node_store/__init__.py +30 -0
- flowfile_core/configs/node_store/nodes.py +383 -99
- flowfile_core/configs/node_store/user_defined_node_registry.py +193 -0
- flowfile_core/configs/settings.py +2 -1
- flowfile_core/database/connection.py +5 -21
- flowfile_core/fileExplorer/funcs.py +239 -121
- flowfile_core/flowfile/analytics/analytics_processor.py +1 -0
- flowfile_core/flowfile/code_generator/code_generator.py +62 -64
- flowfile_core/flowfile/flow_data_engine/create/funcs.py +73 -56
- flowfile_core/flowfile/flow_data_engine/flow_data_engine.py +77 -86
- flowfile_core/flowfile/flow_data_engine/flow_file_column/interface.py +4 -0
- flowfile_core/flowfile/flow_data_engine/flow_file_column/main.py +19 -34
- flowfile_core/flowfile/flow_data_engine/flow_file_column/type_registry.py +36 -0
- flowfile_core/flowfile/flow_data_engine/fuzzy_matching/prepare_for_fuzzy_match.py +23 -23
- flowfile_core/flowfile/flow_data_engine/join/utils.py +1 -1
- flowfile_core/flowfile/flow_data_engine/join/verify_integrity.py +9 -4
- flowfile_core/flowfile/flow_data_engine/subprocess_operations/subprocess_operations.py +212 -86
- flowfile_core/flowfile/flow_data_engine/utils.py +2 -0
- flowfile_core/flowfile/flow_graph.py +240 -54
- flowfile_core/flowfile/flow_node/flow_node.py +48 -13
- flowfile_core/flowfile/flow_node/models.py +2 -1
- flowfile_core/flowfile/handler.py +24 -5
- flowfile_core/flowfile/manage/compatibility_enhancements.py +404 -41
- flowfile_core/flowfile/manage/io_flowfile.py +394 -0
- flowfile_core/flowfile/node_designer/__init__.py +47 -0
- flowfile_core/flowfile/node_designer/_type_registry.py +197 -0
- flowfile_core/flowfile/node_designer/custom_node.py +371 -0
- flowfile_core/flowfile/node_designer/ui_components.py +277 -0
- flowfile_core/flowfile/schema_callbacks.py +17 -10
- flowfile_core/flowfile/setting_generator/settings.py +15 -10
- flowfile_core/main.py +5 -1
- flowfile_core/routes/routes.py +73 -30
- flowfile_core/routes/user_defined_components.py +55 -0
- flowfile_core/schemas/cloud_storage_schemas.py +0 -2
- flowfile_core/schemas/input_schema.py +228 -65
- flowfile_core/schemas/output_model.py +5 -2
- flowfile_core/schemas/schemas.py +153 -35
- flowfile_core/schemas/transform_schema.py +1083 -412
- flowfile_core/schemas/yaml_types.py +103 -0
- flowfile_core/types.py +156 -0
- flowfile_core/utils/validate_setup.py +3 -1
- flowfile_frame/__init__.py +3 -1
- flowfile_frame/flow_frame.py +31 -24
- flowfile_frame/flow_frame_methods.py +12 -9
- flowfile_worker/__init__.py +9 -35
- flowfile_worker/create/__init__.py +3 -21
- flowfile_worker/create/funcs.py +68 -56
- flowfile_worker/create/models.py +130 -62
- flowfile_worker/main.py +5 -2
- flowfile_worker/routes.py +52 -13
- shared/__init__.py +15 -0
- shared/storage_config.py +258 -0
- tools/migrate/README.md +56 -0
- tools/migrate/__init__.py +12 -0
- tools/migrate/__main__.py +131 -0
- tools/migrate/legacy_schemas.py +621 -0
- tools/migrate/migrate.py +598 -0
- tools/migrate/tests/__init__.py +0 -0
- tools/migrate/tests/conftest.py +23 -0
- tools/migrate/tests/test_migrate.py +627 -0
- tools/migrate/tests/test_migration_e2e.py +1010 -0
- tools/migrate/tests/test_node_migrations.py +813 -0
- flowfile/web/static/assets/GraphSolver-17fd26db.css +0 -68
- flowfile/web/static/assets/Pivot-f415e85f.css +0 -35
- flowfile/web/static/assets/Read-80dc1675.css +0 -197
- flowfile/web/static/assets/Read-c3b1929c.js +0 -701
- flowfile/web/static/assets/RecordCount-4e95f98e.js +0 -122
- flowfile/web/static/assets/Union-89fd73dc.js +0 -146
- flowfile/web/static/assets/Unpivot-246e9bbd.css +0 -77
- flowfile/web/static/assets/nodeTitle-a16db7c3.js +0 -227
- flowfile/web/static/assets/nodeTitle-f4b12bcb.css +0 -134
- flowfile_core/flowfile/manage/open_flowfile.py +0 -135
- {flowfile-0.3.9.dist-info → flowfile-0.5.1.dist-info/licenses}/LICENSE +0 -0
- /flowfile_core/flowfile/manage/manage_flowfile.py → /tools/__init__.py +0 -0
|
@@ -0,0 +1,621 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Legacy schema definitions for loading old flowfile pickles.
|
|
3
|
+
|
|
4
|
+
These definitions mirror the OLD schema structure BEFORE the migration to the new
|
|
5
|
+
discriminated union table_settings format.
|
|
6
|
+
|
|
7
|
+
OLD structure:
|
|
8
|
+
- ReceivedTable: All fields flat (delimiter, encoding, sheet_name all at top level)
|
|
9
|
+
- OutputSettings: Separate output_csv_table, output_parquet_table, output_excel_table fields
|
|
10
|
+
|
|
11
|
+
NEW structure:
|
|
12
|
+
- ReceivedTable: Has nested table_settings with discriminated union
|
|
13
|
+
- OutputSettings: Has single table_settings field with discriminated union
|
|
14
|
+
|
|
15
|
+
DO NOT USE THESE IN PRODUCTION CODE - use the actual schemas from flowfile_core.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from dataclasses import dataclass, field
|
|
19
|
+
from typing import List, Optional, Set, Any, Literal, Dict, Tuple
|
|
20
|
+
from pydantic import BaseModel, Field
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# =============================================================================
|
|
24
|
+
# OLD INPUT/OUTPUT SCHEMAS (before table_settings migration)
|
|
25
|
+
# These mirror the structure that exists in old pickle files
|
|
26
|
+
# =============================================================================
|
|
27
|
+
|
|
28
|
+
class MinimalFieldInfo(BaseModel):
|
|
29
|
+
"""Represents the most basic information about a data field (column)."""
|
|
30
|
+
name: str
|
|
31
|
+
data_type: str = "String"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class OutputCsvTable(BaseModel):
|
|
35
|
+
"""OLD: Settings for writing a CSV file."""
|
|
36
|
+
file_type: str = 'csv'
|
|
37
|
+
delimiter: str = ','
|
|
38
|
+
encoding: str = 'utf-8'
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class OutputParquetTable(BaseModel):
|
|
42
|
+
"""OLD: Settings for writing a Parquet file."""
|
|
43
|
+
file_type: str = 'parquet'
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class OutputExcelTable(BaseModel):
|
|
47
|
+
"""OLD: Settings for writing an Excel file."""
|
|
48
|
+
file_type: str = 'excel'
|
|
49
|
+
sheet_name: str = 'Sheet1'
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class OutputSettings(BaseModel):
|
|
53
|
+
"""OLD OutputSettings structure with SEPARATE table fields.
|
|
54
|
+
|
|
55
|
+
This is the OLD format where CSV, Parquet, and Excel settings
|
|
56
|
+
were stored in separate fields rather than a unified table_settings.
|
|
57
|
+
"""
|
|
58
|
+
name: str
|
|
59
|
+
directory: str
|
|
60
|
+
file_type: str
|
|
61
|
+
fields: Optional[List[str]] = Field(default_factory=list)
|
|
62
|
+
write_mode: str = 'overwrite'
|
|
63
|
+
# OLD: Separate fields for each output type
|
|
64
|
+
output_csv_table: Optional[OutputCsvTable] = Field(default_factory=OutputCsvTable)
|
|
65
|
+
output_parquet_table: OutputParquetTable = Field(default_factory=OutputParquetTable)
|
|
66
|
+
output_excel_table: OutputExcelTable = Field(default_factory=OutputExcelTable)
|
|
67
|
+
abs_file_path: Optional[str] = None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class ReceivedTable(BaseModel):
|
|
71
|
+
"""OLD ReceivedTable structure with FLAT fields.
|
|
72
|
+
|
|
73
|
+
This is the OLD format where all settings (CSV, Excel, Parquet)
|
|
74
|
+
were stored as flat fields on the model rather than nested in table_settings.
|
|
75
|
+
"""
|
|
76
|
+
# Metadata fields
|
|
77
|
+
id: Optional[int] = None
|
|
78
|
+
name: Optional[str] = None
|
|
79
|
+
path: str = ''
|
|
80
|
+
directory: Optional[str] = None
|
|
81
|
+
analysis_file_available: bool = False
|
|
82
|
+
status: Optional[str] = None
|
|
83
|
+
file_type: Optional[str] = None
|
|
84
|
+
fields: List[MinimalFieldInfo] = Field(default_factory=list)
|
|
85
|
+
abs_file_path: Optional[str] = None
|
|
86
|
+
|
|
87
|
+
# OLD: CSV/JSON fields at top level (not nested)
|
|
88
|
+
reference: str = ''
|
|
89
|
+
starting_from_line: int = 0
|
|
90
|
+
delimiter: str = ','
|
|
91
|
+
has_headers: bool = True
|
|
92
|
+
encoding: Optional[str] = 'utf-8'
|
|
93
|
+
parquet_ref: Optional[str] = None
|
|
94
|
+
row_delimiter: str = '\n'
|
|
95
|
+
quote_char: str = '"'
|
|
96
|
+
infer_schema_length: int = 10_000
|
|
97
|
+
truncate_ragged_lines: bool = False
|
|
98
|
+
ignore_errors: bool = False
|
|
99
|
+
|
|
100
|
+
# OLD: Excel fields at top level (not nested)
|
|
101
|
+
sheet_name: Optional[str] = None
|
|
102
|
+
start_row: int = 0
|
|
103
|
+
start_column: int = 0
|
|
104
|
+
end_row: int = 0
|
|
105
|
+
end_column: int = 0
|
|
106
|
+
type_inference: bool = False
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# =============================================================================
|
|
110
|
+
# FLOW AND NODE SCHEMAS (Pydantic - structure unchanged, just re-exported)
|
|
111
|
+
# =============================================================================
|
|
112
|
+
|
|
113
|
+
class FlowGraphConfig(BaseModel):
|
|
114
|
+
"""Configuration model for a flow graph's basic properties."""
|
|
115
|
+
flow_id: int = 1
|
|
116
|
+
description: Optional[str] = None
|
|
117
|
+
save_location: Optional[str] = None
|
|
118
|
+
name: str = ''
|
|
119
|
+
path: str = ''
|
|
120
|
+
execution_mode: str = 'Performance'
|
|
121
|
+
execution_location: str = 'local'
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class FlowSettings(FlowGraphConfig):
|
|
125
|
+
"""Extends FlowGraphConfig with additional operational settings."""
|
|
126
|
+
auto_save: bool = False
|
|
127
|
+
modified_on: Optional[float] = None
|
|
128
|
+
show_detailed_progress: bool = True
|
|
129
|
+
is_running: bool = False
|
|
130
|
+
is_canceled: bool = False
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class NodeBase(BaseModel):
|
|
134
|
+
"""Base model for all nodes in a FlowGraph."""
|
|
135
|
+
flow_id: int
|
|
136
|
+
node_id: int
|
|
137
|
+
cache_results: Optional[bool] = False
|
|
138
|
+
pos_x: Optional[float] = 0
|
|
139
|
+
pos_y: Optional[float] = 0
|
|
140
|
+
is_setup: Optional[bool] = True
|
|
141
|
+
description: Optional[str] = ''
|
|
142
|
+
user_id: Optional[int] = None
|
|
143
|
+
is_flow_output: Optional[bool] = False
|
|
144
|
+
is_user_defined: Optional[bool] = False
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class NodeSingleInput(NodeBase):
|
|
148
|
+
"""A base model for any node that takes a single data input."""
|
|
149
|
+
depending_on_id: Optional[int] = -1
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class NodeMultiInput(NodeBase):
|
|
153
|
+
"""A base model for any node that takes multiple data inputs."""
|
|
154
|
+
depending_on_ids: Optional[List[int]] = Field(default_factory=lambda: [-1])
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class NodeRead(NodeBase):
|
|
158
|
+
"""Settings for a node that reads data from a file."""
|
|
159
|
+
received_file: ReceivedTable
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class NodeSelect(NodeSingleInput):
|
|
163
|
+
"""Settings for a node that selects, renames, and reorders columns."""
|
|
164
|
+
keep_missing: bool = True
|
|
165
|
+
select_input: List[Any] = Field(default_factory=list)
|
|
166
|
+
sorted_by: Optional[str] = 'none'
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class NodeFilter(NodeSingleInput):
|
|
170
|
+
"""Settings for a node that filters rows based on a condition."""
|
|
171
|
+
filter_input: Any = None
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class NodeFormula(NodeSingleInput):
|
|
175
|
+
"""Settings for a node that applies a formula to create/modify a column."""
|
|
176
|
+
function: Any = None
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class NodeJoin(NodeMultiInput):
|
|
180
|
+
"""Settings for a node that performs a standard SQL-style join."""
|
|
181
|
+
auto_generate_selection: bool = True
|
|
182
|
+
verify_integrity: bool = True
|
|
183
|
+
join_input: Any = None
|
|
184
|
+
auto_keep_all: bool = True
|
|
185
|
+
auto_keep_right: bool = True
|
|
186
|
+
auto_keep_left: bool = True
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class NodeCrossJoin(NodeMultiInput):
|
|
190
|
+
"""Settings for a node that performs a cross join."""
|
|
191
|
+
auto_generate_selection: bool = True
|
|
192
|
+
verify_integrity: bool = True
|
|
193
|
+
cross_join_input: Any = None
|
|
194
|
+
auto_keep_all: bool = True
|
|
195
|
+
auto_keep_right: bool = True
|
|
196
|
+
auto_keep_left: bool = True
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class NodeFuzzyMatch(NodeMultiInput):
|
|
200
|
+
"""Settings for a node that performs a fuzzy join."""
|
|
201
|
+
auto_generate_selection: bool = True
|
|
202
|
+
verify_integrity: bool = True
|
|
203
|
+
join_input: Any = None # FuzzyMatchInput
|
|
204
|
+
auto_keep_all: bool = True
|
|
205
|
+
auto_keep_right: bool = True
|
|
206
|
+
auto_keep_left: bool = True
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class NodePolarsCode(NodeMultiInput):
|
|
210
|
+
"""Settings for a node that executes arbitrary Polars code."""
|
|
211
|
+
polars_code_input: Any = None
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class NodeOutput(NodeSingleInput):
|
|
215
|
+
"""Settings for a node that writes its input to a file."""
|
|
216
|
+
output_settings: OutputSettings
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class NodeGroupBy(NodeSingleInput):
|
|
220
|
+
"""Settings for a node that performs a group-by and aggregation."""
|
|
221
|
+
groupby_input: Any = None
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class NodeSort(NodeSingleInput):
|
|
225
|
+
"""Settings for a node that sorts the data."""
|
|
226
|
+
sort_input: List[Any] = Field(default_factory=list)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
class NodeUnion(NodeMultiInput):
|
|
230
|
+
"""Settings for a node that concatenates multiple inputs."""
|
|
231
|
+
union_input: Any = None
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class NodeUnique(NodeSingleInput):
|
|
235
|
+
"""Settings for a node that returns unique rows."""
|
|
236
|
+
unique_input: Any = None
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class NodePivot(NodeSingleInput):
|
|
240
|
+
"""Settings for a node that pivots data."""
|
|
241
|
+
pivot_input: Any = None
|
|
242
|
+
output_fields: Optional[List[MinimalFieldInfo]] = None
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class NodeUnpivot(NodeSingleInput):
|
|
246
|
+
"""Settings for a node that unpivots data."""
|
|
247
|
+
unpivot_input: Any = None
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class NodeRecordId(NodeSingleInput):
|
|
251
|
+
"""Settings for adding a record ID column."""
|
|
252
|
+
record_id_input: Any = None
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class NodeTextToRows(NodeSingleInput):
|
|
256
|
+
"""Settings for splitting text into rows."""
|
|
257
|
+
text_to_rows_input: Any = None
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class NodeGraphSolver(NodeSingleInput):
|
|
261
|
+
"""Settings for graph-solving operations."""
|
|
262
|
+
graph_solver_input: Any = None
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
class NodeSample(NodeSingleInput):
|
|
266
|
+
"""Settings for sampling data."""
|
|
267
|
+
sample_size: int = 1000
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
class NodePromise(NodeBase):
|
|
271
|
+
"""A placeholder node not yet configured."""
|
|
272
|
+
is_setup: bool = False
|
|
273
|
+
node_type: str = ''
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
class DatabaseConnection(BaseModel):
|
|
277
|
+
"""Defines database connection parameters."""
|
|
278
|
+
database_type: str = "postgresql"
|
|
279
|
+
username: Optional[str] = None
|
|
280
|
+
password_ref: Optional[str] = None
|
|
281
|
+
host: Optional[str] = None
|
|
282
|
+
port: Optional[int] = None
|
|
283
|
+
database: Optional[str] = None
|
|
284
|
+
url: Optional[str] = None
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
class DatabaseSettings(BaseModel):
|
|
288
|
+
"""Defines settings for reading from a database."""
|
|
289
|
+
connection_mode: Optional[str] = 'inline'
|
|
290
|
+
database_connection: Optional[DatabaseConnection] = None
|
|
291
|
+
database_connection_name: Optional[str] = None
|
|
292
|
+
schema_name: Optional[str] = None
|
|
293
|
+
table_name: Optional[str] = None
|
|
294
|
+
query: Optional[str] = None
|
|
295
|
+
query_mode: str = 'table'
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class NodeDatabaseReader(NodeBase):
|
|
299
|
+
"""Settings for reading from a database."""
|
|
300
|
+
database_settings: DatabaseSettings
|
|
301
|
+
fields: Optional[List[MinimalFieldInfo]] = None
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
class NodeInformation(BaseModel):
|
|
305
|
+
"""Stores the state and configuration of a node instance."""
|
|
306
|
+
id: Optional[int] = None
|
|
307
|
+
type: Optional[str] = None
|
|
308
|
+
is_setup: Optional[bool] = None
|
|
309
|
+
description: Optional[str] = ''
|
|
310
|
+
x_position: Optional[int] = 0
|
|
311
|
+
y_position: Optional[int] = 0
|
|
312
|
+
left_input_id: Optional[int] = None
|
|
313
|
+
right_input_id: Optional[int] = None
|
|
314
|
+
input_ids: Optional[List[int]] = Field(default_factory=lambda: [-1])
|
|
315
|
+
outputs: Optional[List[int]] = Field(default_factory=lambda: [-1])
|
|
316
|
+
setting_input: Optional[Any] = None
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
class FlowInformation(BaseModel):
|
|
320
|
+
"""Represents the complete state of a flow."""
|
|
321
|
+
flow_id: int
|
|
322
|
+
flow_name: Optional[str] = ''
|
|
323
|
+
flow_settings: Optional[FlowSettings] = None
|
|
324
|
+
data: Dict[int, NodeInformation] = Field(default_factory=dict)
|
|
325
|
+
node_starts: List[int] = Field(default_factory=list)
|
|
326
|
+
node_connections: List[Tuple[int, int]] = Field(default_factory=list)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
# =============================================================================
|
|
330
|
+
# TRANSFORM SCHEMAS (dataclasses - these changed from @dataclass to BaseModel)
|
|
331
|
+
# =============================================================================
|
|
332
|
+
|
|
333
|
+
@dataclass
|
|
334
|
+
class SelectInput:
|
|
335
|
+
"""Defines how a single column should be selected, renamed, or type-cast."""
|
|
336
|
+
old_name: str
|
|
337
|
+
original_position: Optional[int] = None
|
|
338
|
+
new_name: Optional[str] = None
|
|
339
|
+
data_type: Optional[str] = None
|
|
340
|
+
data_type_change: Optional[bool] = False
|
|
341
|
+
join_key: Optional[bool] = False
|
|
342
|
+
is_altered: Optional[bool] = False
|
|
343
|
+
position: Optional[int] = None
|
|
344
|
+
is_available: Optional[bool] = True
|
|
345
|
+
keep: Optional[bool] = True
|
|
346
|
+
|
|
347
|
+
def __post_init__(self):
|
|
348
|
+
if self.new_name is None:
|
|
349
|
+
self.new_name = self.old_name
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
@dataclass
|
|
353
|
+
class FieldInput:
|
|
354
|
+
"""Represents a single field with its name and data type."""
|
|
355
|
+
name: str
|
|
356
|
+
data_type: Optional[str] = None
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
@dataclass
|
|
360
|
+
class FunctionInput:
|
|
361
|
+
"""Defines a formula to be applied."""
|
|
362
|
+
field: FieldInput = None
|
|
363
|
+
function: str = ''
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
@dataclass
|
|
367
|
+
class BasicFilter:
|
|
368
|
+
"""Defines a simple, single-condition filter."""
|
|
369
|
+
field: str = ''
|
|
370
|
+
filter_type: str = ''
|
|
371
|
+
filter_value: str = ''
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
@dataclass
|
|
375
|
+
class FilterInput:
|
|
376
|
+
"""Defines the settings for a filter operation."""
|
|
377
|
+
advanced_filter: str = ''
|
|
378
|
+
basic_filter: BasicFilter = None
|
|
379
|
+
filter_type: str = 'basic'
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
@dataclass
|
|
383
|
+
class SelectInputs:
|
|
384
|
+
"""A container for a list of SelectInput objects."""
|
|
385
|
+
renames: List[SelectInput] = field(default_factory=list)
|
|
386
|
+
|
|
387
|
+
@property
|
|
388
|
+
def old_cols(self) -> Set:
|
|
389
|
+
return set(v.old_name for v in self.renames if v.keep)
|
|
390
|
+
|
|
391
|
+
@property
|
|
392
|
+
def new_cols(self) -> Set:
|
|
393
|
+
return set(v.new_name for v in self.renames if v.keep)
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
@dataclass
|
|
397
|
+
class JoinInputs:
|
|
398
|
+
"""Extends SelectInputs with functionality specific to join operations."""
|
|
399
|
+
renames: List[SelectInput] = field(default_factory=list)
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
@dataclass
|
|
403
|
+
class JoinMap:
|
|
404
|
+
"""Defines a single mapping between a left and right column for a join key."""
|
|
405
|
+
left_col: str = None
|
|
406
|
+
right_col: str = None
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
@dataclass
|
|
410
|
+
class CrossJoinInput:
|
|
411
|
+
"""Defines the settings for a cross join operation."""
|
|
412
|
+
left_select: Any = None
|
|
413
|
+
right_select: Any = None
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
@dataclass
|
|
417
|
+
class JoinInput:
|
|
418
|
+
"""Defines the settings for a standard SQL-style join."""
|
|
419
|
+
join_mapping: List[JoinMap] = field(default_factory=list)
|
|
420
|
+
left_select: Any = None
|
|
421
|
+
right_select: Any = None
|
|
422
|
+
how: str = 'inner'
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
@dataclass
|
|
426
|
+
class FuzzyMapping:
|
|
427
|
+
"""Defines a fuzzy match column mapping with threshold."""
|
|
428
|
+
left_col: str = None
|
|
429
|
+
right_col: str = None
|
|
430
|
+
threshold_score: int = 80
|
|
431
|
+
fuzzy_type: str = 'levenshtein'
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
@dataclass
|
|
435
|
+
class FuzzyMatchInput:
|
|
436
|
+
"""Extends JoinInput with settings specific to fuzzy matching."""
|
|
437
|
+
join_mapping: List[FuzzyMapping] = field(default_factory=list)
|
|
438
|
+
left_select: Any = None
|
|
439
|
+
right_select: Any = None
|
|
440
|
+
how: str = 'inner'
|
|
441
|
+
aggregate_output: bool = False
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
@dataclass
|
|
445
|
+
class AggColl:
|
|
446
|
+
"""Represents a single aggregation operation."""
|
|
447
|
+
old_name: str = None
|
|
448
|
+
agg: str = None
|
|
449
|
+
new_name: Optional[str] = None
|
|
450
|
+
output_type: Optional[str] = None
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
@dataclass
|
|
454
|
+
class GroupByInput:
|
|
455
|
+
"""Represents the input for a group by operation."""
|
|
456
|
+
agg_cols: List[AggColl] = field(default_factory=list)
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
@dataclass
|
|
460
|
+
class PivotInput:
|
|
461
|
+
"""Defines the settings for a pivot operation."""
|
|
462
|
+
index_columns: List[str] = field(default_factory=list)
|
|
463
|
+
pivot_column: str = None
|
|
464
|
+
value_col: str = None
|
|
465
|
+
aggregations: List[str] = field(default_factory=list)
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
@dataclass
|
|
469
|
+
class SortByInput:
|
|
470
|
+
"""Defines a single sort condition on a column."""
|
|
471
|
+
column: str = None
|
|
472
|
+
how: str = 'asc'
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
@dataclass
|
|
476
|
+
class RecordIdInput:
|
|
477
|
+
"""Defines settings for adding a record ID column."""
|
|
478
|
+
output_column_name: str = 'record_id'
|
|
479
|
+
offset: int = 1
|
|
480
|
+
group_by: Optional[bool] = False
|
|
481
|
+
group_by_columns: Optional[List[str]] = field(default_factory=list)
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
@dataclass
|
|
485
|
+
class TextToRowsInput:
|
|
486
|
+
"""Defines settings for splitting a text column into multiple rows."""
|
|
487
|
+
column_to_split: str = None
|
|
488
|
+
output_column_name: Optional[str] = None
|
|
489
|
+
split_by_fixed_value: Optional[bool] = True
|
|
490
|
+
split_fixed_value: Optional[str] = ','
|
|
491
|
+
split_by_column: Optional[str] = None
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
@dataclass
|
|
495
|
+
class UnpivotInput:
|
|
496
|
+
"""Defines settings for an unpivot operation."""
|
|
497
|
+
index_columns: Optional[List[str]] = field(default_factory=list)
|
|
498
|
+
value_columns: Optional[List[str]] = field(default_factory=list)
|
|
499
|
+
data_type_selector: Optional[Literal['float', 'all', 'date', 'numeric', 'string']] = None
|
|
500
|
+
data_type_selector_mode: Optional[Literal['data_type', 'column']] = 'column'
|
|
501
|
+
|
|
502
|
+
def __post_init__(self):
|
|
503
|
+
if self.index_columns is None:
|
|
504
|
+
self.index_columns = []
|
|
505
|
+
if self.value_columns is None:
|
|
506
|
+
self.value_columns = []
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
@dataclass
|
|
510
|
+
class UnionInput:
|
|
511
|
+
"""Defines settings for a union operation."""
|
|
512
|
+
mode: Literal['selective', 'relaxed'] = 'relaxed'
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
@dataclass
|
|
516
|
+
class UniqueInput:
|
|
517
|
+
"""Defines settings for a uniqueness operation."""
|
|
518
|
+
columns: Optional[List[str]] = None
|
|
519
|
+
strategy: str = "any"
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
@dataclass
|
|
523
|
+
class GraphSolverInput:
|
|
524
|
+
"""Defines settings for a graph-solving operation."""
|
|
525
|
+
col_from: str = None
|
|
526
|
+
col_to: str = None
|
|
527
|
+
output_column_name: Optional[str] = 'graph_group'
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
@dataclass
|
|
531
|
+
class PolarsCodeInput:
|
|
532
|
+
"""A simple container for user-provided Polars code."""
|
|
533
|
+
polars_code: str = ''
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
@dataclass
|
|
537
|
+
class SampleInput:
|
|
538
|
+
"""Defines settings for sampling rows."""
|
|
539
|
+
n: Optional[int] = None
|
|
540
|
+
fraction: Optional[float] = None
|
|
541
|
+
with_replacement: bool = False
|
|
542
|
+
shuffle: bool = False
|
|
543
|
+
seed: Optional[int] = None
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
# =============================================================================
|
|
547
|
+
# CLASS NAME MAPPING for pickle.Unpickler.find_class
|
|
548
|
+
# Maps class names to their legacy implementations for unpickling
|
|
549
|
+
# =============================================================================
|
|
550
|
+
|
|
551
|
+
LEGACY_CLASS_MAP = {
|
|
552
|
+
# Transform schema dataclasses
|
|
553
|
+
'SelectInput': SelectInput,
|
|
554
|
+
'FieldInput': FieldInput,
|
|
555
|
+
'FunctionInput': FunctionInput,
|
|
556
|
+
'BasicFilter': BasicFilter,
|
|
557
|
+
'FilterInput': FilterInput,
|
|
558
|
+
'SelectInputs': SelectInputs,
|
|
559
|
+
'JoinInputs': JoinInputs,
|
|
560
|
+
'JoinMap': JoinMap,
|
|
561
|
+
'CrossJoinInput': CrossJoinInput,
|
|
562
|
+
'JoinInput': JoinInput,
|
|
563
|
+
'FuzzyMapping': FuzzyMapping,
|
|
564
|
+
'FuzzyMatchInput': FuzzyMatchInput,
|
|
565
|
+
'AggColl': AggColl,
|
|
566
|
+
'GroupByInput': GroupByInput,
|
|
567
|
+
'PivotInput': PivotInput,
|
|
568
|
+
'SortByInput': SortByInput,
|
|
569
|
+
'RecordIdInput': RecordIdInput,
|
|
570
|
+
'TextToRowsInput': TextToRowsInput,
|
|
571
|
+
'UnpivotInput': UnpivotInput,
|
|
572
|
+
'UnionInput': UnionInput,
|
|
573
|
+
'UniqueInput': UniqueInput,
|
|
574
|
+
'GraphSolverInput': GraphSolverInput,
|
|
575
|
+
'PolarsCodeInput': PolarsCodeInput,
|
|
576
|
+
'SampleInput': SampleInput,
|
|
577
|
+
|
|
578
|
+
# OLD Input/Output schemas (before table_settings)
|
|
579
|
+
'ReceivedTable': ReceivedTable,
|
|
580
|
+
'OutputSettings': OutputSettings,
|
|
581
|
+
'OutputCsvTable': OutputCsvTable,
|
|
582
|
+
'OutputParquetTable': OutputParquetTable,
|
|
583
|
+
'OutputExcelTable': OutputExcelTable,
|
|
584
|
+
'MinimalFieldInfo': MinimalFieldInfo,
|
|
585
|
+
|
|
586
|
+
# Flow and Node schemas
|
|
587
|
+
'FlowSettings': FlowSettings,
|
|
588
|
+
'FlowGraphConfig': FlowGraphConfig,
|
|
589
|
+
'FlowInformation': FlowInformation,
|
|
590
|
+
'NodeInformation': NodeInformation,
|
|
591
|
+
'NodeBase': NodeBase,
|
|
592
|
+
'NodeSingleInput': NodeSingleInput,
|
|
593
|
+
'NodeMultiInput': NodeMultiInput,
|
|
594
|
+
'NodeRead': NodeRead,
|
|
595
|
+
'NodeSelect': NodeSelect,
|
|
596
|
+
'NodeFilter': NodeFilter,
|
|
597
|
+
'NodeFormula': NodeFormula,
|
|
598
|
+
'NodeJoin': NodeJoin,
|
|
599
|
+
'NodeCrossJoin': NodeCrossJoin,
|
|
600
|
+
'NodeFuzzyMatch': NodeFuzzyMatch,
|
|
601
|
+
'NodePolarsCode': NodePolarsCode,
|
|
602
|
+
'NodeOutput': NodeOutput,
|
|
603
|
+
'NodeGroupBy': NodeGroupBy,
|
|
604
|
+
'NodeSort': NodeSort,
|
|
605
|
+
'NodeUnion': NodeUnion,
|
|
606
|
+
'NodeUnique': NodeUnique,
|
|
607
|
+
'NodePivot': NodePivot,
|
|
608
|
+
'NodeUnpivot': NodeUnpivot,
|
|
609
|
+
'NodeRecordId': NodeRecordId,
|
|
610
|
+
'NodeTextToRows': NodeTextToRows,
|
|
611
|
+
'NodeGraphSolver': NodeGraphSolver,
|
|
612
|
+
'NodeSample': NodeSample,
|
|
613
|
+
'NodePromise': NodePromise,
|
|
614
|
+
'DatabaseConnection': DatabaseConnection,
|
|
615
|
+
'DatabaseSettings': DatabaseSettings,
|
|
616
|
+
'NodeDatabaseReader': NodeDatabaseReader,
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
# Export all classes
|
|
621
|
+
__all__ = list(LEGACY_CLASS_MAP.keys()) + ['LEGACY_CLASS_MAP']
|