meerschaum 3.0.0rc4__py3-none-any.whl → 3.0.0rc8__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.
- meerschaum/_internal/arguments/_parser.py +14 -2
- meerschaum/_internal/cli/__init__.py +6 -0
- meerschaum/_internal/cli/daemons.py +103 -0
- meerschaum/_internal/cli/entry.py +220 -0
- meerschaum/_internal/cli/workers.py +435 -0
- meerschaum/_internal/docs/index.py +1 -2
- meerschaum/_internal/entry.py +44 -8
- meerschaum/_internal/shell/Shell.py +115 -24
- meerschaum/_internal/shell/__init__.py +4 -1
- meerschaum/_internal/static.py +4 -1
- meerschaum/_internal/term/TermPageHandler.py +1 -2
- meerschaum/_internal/term/__init__.py +40 -6
- meerschaum/_internal/term/tools.py +33 -8
- meerschaum/actions/__init__.py +6 -4
- meerschaum/actions/api.py +39 -11
- meerschaum/actions/attach.py +1 -0
- meerschaum/actions/delete.py +4 -2
- meerschaum/actions/edit.py +27 -8
- meerschaum/actions/login.py +8 -8
- meerschaum/actions/register.py +13 -7
- meerschaum/actions/reload.py +22 -5
- meerschaum/actions/restart.py +14 -0
- meerschaum/actions/show.py +69 -4
- meerschaum/actions/start.py +135 -14
- meerschaum/actions/stop.py +36 -3
- meerschaum/actions/sync.py +6 -1
- meerschaum/api/__init__.py +35 -13
- meerschaum/api/_events.py +2 -2
- meerschaum/api/_oauth2.py +47 -4
- meerschaum/api/dash/callbacks/dashboard.py +29 -0
- meerschaum/api/dash/callbacks/jobs.py +3 -2
- meerschaum/api/dash/callbacks/login.py +10 -1
- meerschaum/api/dash/callbacks/register.py +9 -2
- meerschaum/api/dash/pages/login.py +2 -2
- meerschaum/api/dash/pipes.py +72 -36
- meerschaum/api/dash/webterm.py +14 -6
- meerschaum/api/models/_pipes.py +7 -1
- meerschaum/api/resources/static/js/terminado.js +3 -0
- meerschaum/api/resources/static/js/xterm-addon-unicode11.js +2 -0
- meerschaum/api/resources/templates/termpage.html +1 -0
- meerschaum/api/routes/_jobs.py +23 -11
- meerschaum/api/routes/_login.py +73 -5
- meerschaum/api/routes/_pipes.py +6 -4
- meerschaum/api/routes/_webterm.py +3 -3
- meerschaum/config/__init__.py +60 -13
- meerschaum/config/_default.py +89 -61
- meerschaum/config/_edit.py +10 -8
- meerschaum/config/_formatting.py +2 -0
- meerschaum/config/_patch.py +4 -2
- meerschaum/config/_paths.py +127 -12
- meerschaum/config/_read_config.py +32 -12
- meerschaum/config/_version.py +1 -1
- meerschaum/config/environment.py +262 -0
- meerschaum/config/stack/__init__.py +7 -5
- meerschaum/connectors/_Connector.py +1 -2
- meerschaum/connectors/__init__.py +37 -2
- meerschaum/connectors/api/_APIConnector.py +1 -1
- meerschaum/connectors/api/_jobs.py +11 -0
- meerschaum/connectors/api/_pipes.py +7 -1
- meerschaum/connectors/instance/_plugins.py +9 -1
- meerschaum/connectors/instance/_tokens.py +20 -3
- meerschaum/connectors/instance/_users.py +8 -1
- meerschaum/connectors/parse.py +1 -1
- meerschaum/connectors/sql/_create_engine.py +3 -0
- meerschaum/connectors/sql/_pipes.py +93 -79
- meerschaum/connectors/sql/_users.py +8 -1
- meerschaum/connectors/valkey/_ValkeyConnector.py +3 -3
- meerschaum/connectors/valkey/_pipes.py +7 -5
- meerschaum/core/Pipe/__init__.py +45 -71
- meerschaum/core/Pipe/_attributes.py +66 -90
- meerschaum/core/Pipe/_cache.py +555 -0
- meerschaum/core/Pipe/_clear.py +0 -11
- meerschaum/core/Pipe/_data.py +0 -50
- meerschaum/core/Pipe/_deduplicate.py +0 -13
- meerschaum/core/Pipe/_delete.py +12 -21
- meerschaum/core/Pipe/_drop.py +11 -23
- meerschaum/core/Pipe/_dtypes.py +1 -1
- meerschaum/core/Pipe/_index.py +8 -14
- meerschaum/core/Pipe/_sync.py +12 -18
- meerschaum/core/Plugin/_Plugin.py +7 -1
- meerschaum/core/Token/_Token.py +1 -1
- meerschaum/core/User/_User.py +1 -2
- meerschaum/jobs/_Executor.py +88 -4
- meerschaum/jobs/_Job.py +146 -36
- meerschaum/jobs/systemd.py +7 -2
- meerschaum/plugins/__init__.py +277 -81
- meerschaum/utils/daemon/Daemon.py +197 -42
- meerschaum/utils/daemon/FileDescriptorInterceptor.py +0 -1
- meerschaum/utils/daemon/RotatingFile.py +63 -36
- meerschaum/utils/daemon/StdinFile.py +53 -13
- meerschaum/utils/daemon/__init__.py +18 -5
- meerschaum/utils/daemon/_names.py +6 -3
- meerschaum/utils/debug.py +34 -4
- meerschaum/utils/dtypes/__init__.py +5 -1
- meerschaum/utils/formatting/__init__.py +4 -1
- meerschaum/utils/formatting/_jobs.py +1 -1
- meerschaum/utils/formatting/_pipes.py +47 -46
- meerschaum/utils/formatting/_shell.py +33 -9
- meerschaum/utils/misc.py +22 -38
- meerschaum/utils/packages/__init__.py +15 -13
- meerschaum/utils/packages/_packages.py +1 -0
- meerschaum/utils/pipes.py +33 -5
- meerschaum/utils/process.py +1 -1
- meerschaum/utils/prompt.py +172 -143
- meerschaum/utils/sql.py +12 -2
- meerschaum/utils/threading.py +42 -0
- meerschaum/utils/venv/__init__.py +2 -0
- meerschaum/utils/warnings.py +19 -13
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc8.dist-info}/METADATA +3 -1
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc8.dist-info}/RECORD +116 -110
- meerschaum/config/_environment.py +0 -145
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc8.dist-info}/WHEEL +0 -0
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc8.dist-info}/entry_points.txt +0 -0
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc8.dist-info}/licenses/LICENSE +0 -0
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc8.dist-info}/licenses/NOTICE +0 -0
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc8.dist-info}/top_level.txt +0 -0
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc8.dist-info}/zip-safe +0 -0
@@ -146,7 +146,7 @@ def fetch_pipes_keys(
|
|
146
146
|
location_keys: Optional[List[str]] = None,
|
147
147
|
tags: Optional[List[str]] = None,
|
148
148
|
params: Optional[Dict[str, Any]] = None,
|
149
|
-
debug: bool = False
|
149
|
+
debug: bool = False,
|
150
150
|
) -> List[
|
151
151
|
Tuple[str, str, Union[str, None], Dict[str, Any]]
|
152
152
|
]:
|
@@ -251,16 +251,18 @@ def fetch_pipes_keys(
|
|
251
251
|
) for key, val in _params.items()
|
252
252
|
if not isinstance(val, (list, tuple)) and key in pipes_tbl.c
|
253
253
|
]
|
254
|
+
if self.flavor in json_flavors:
|
255
|
+
sqlalchemy_dialects = mrsm.attempt_import('sqlalchemy.dialects', lazy=False)
|
256
|
+
JSONB = sqlalchemy_dialects.postgresql.JSONB
|
257
|
+
else:
|
258
|
+
JSONB = sqlalchemy.String
|
259
|
+
|
254
260
|
select_cols = (
|
255
261
|
[
|
256
262
|
pipes_tbl.c.connector_keys,
|
257
263
|
pipes_tbl.c.metric_key,
|
258
264
|
pipes_tbl.c.location_key,
|
259
|
-
|
260
|
-
pipes_tbl.c.parameters['tags']
|
261
|
-
if self.flavor in json_flavors
|
262
|
-
else pipes_tbl.c.parameters
|
263
|
-
),
|
265
|
+
pipes_tbl.c.parameters,
|
264
266
|
]
|
265
267
|
)
|
266
268
|
|
@@ -278,13 +280,12 @@ def fetch_pipes_keys(
|
|
278
280
|
|
279
281
|
ors, nands = [], []
|
280
282
|
if self.flavor in json_flavors:
|
281
|
-
from sqlalchemy.dialects import postgresql
|
282
283
|
for _in_tags, _ex_tags in in_ex_tag_groups:
|
283
284
|
if _in_tags:
|
284
285
|
ors.append(
|
285
286
|
sqlalchemy.and_(
|
286
287
|
pipes_tbl.c['parameters']['tags'].cast(
|
287
|
-
|
288
|
+
JSONB
|
288
289
|
).contains(_in_tags)
|
289
290
|
)
|
290
291
|
)
|
@@ -293,7 +294,7 @@ def fetch_pipes_keys(
|
|
293
294
|
sqlalchemy.not_(
|
294
295
|
sqlalchemy.and_(
|
295
296
|
pipes_tbl.c['parameters']['tags'].cast(
|
296
|
-
|
297
|
+
JSONB
|
297
298
|
).contains([xt])
|
298
299
|
)
|
299
300
|
)
|
@@ -376,6 +377,9 @@ def create_indices(
|
|
376
377
|
"""
|
377
378
|
Create a pipe's indices.
|
378
379
|
"""
|
380
|
+
if pipe.__dict__.get('_skip_check_indices', False):
|
381
|
+
return True
|
382
|
+
|
379
383
|
if debug:
|
380
384
|
dprint(f"Creating indices for {pipe}...")
|
381
385
|
|
@@ -385,7 +389,7 @@ def create_indices(
|
|
385
389
|
|
386
390
|
cols_to_include = set((columns or []) + (indices or [])) or None
|
387
391
|
|
388
|
-
|
392
|
+
pipe._clear_cache_key('_columns_indices', debug=debug)
|
389
393
|
ix_queries = {
|
390
394
|
col: queries
|
391
395
|
for col, queries in self.get_create_index_queries(pipe, debug=debug).items()
|
@@ -461,7 +465,7 @@ def get_pipe_index_names(self, pipe: mrsm.Pipe) -> Dict[str, str]:
|
|
461
465
|
-------
|
462
466
|
A dictionary of index keys to column names.
|
463
467
|
"""
|
464
|
-
from meerschaum.utils.sql import DEFAULT_SCHEMA_FLAVORS
|
468
|
+
from meerschaum.utils.sql import DEFAULT_SCHEMA_FLAVORS, truncate_item_name
|
465
469
|
_parameters = pipe.parameters
|
466
470
|
_index_template = _parameters.get('index_template', "IX_{schema_str}{target}_{column_names}")
|
467
471
|
_schema = self.get_pipe_schema(pipe)
|
@@ -502,7 +506,7 @@ def get_pipe_index_names(self, pipe: mrsm.Pipe) -> Dict[str, str]:
|
|
502
506
|
continue
|
503
507
|
seen_index_names[index_name] = ix
|
504
508
|
return {
|
505
|
-
ix: index_name
|
509
|
+
ix: truncate_item_name(index_name, flavor=self.flavor)
|
506
510
|
for index_name, ix in seen_index_names.items()
|
507
511
|
}
|
508
512
|
|
@@ -1503,7 +1507,7 @@ def get_pipe_attributes(
|
|
1503
1507
|
"""
|
1504
1508
|
from meerschaum.connectors.sql.tables import get_tables
|
1505
1509
|
from meerschaum.utils.packages import attempt_import
|
1506
|
-
sqlalchemy = attempt_import('sqlalchemy')
|
1510
|
+
sqlalchemy = attempt_import('sqlalchemy', lazy=False)
|
1507
1511
|
|
1508
1512
|
if pipe.get_id(debug=debug) is None:
|
1509
1513
|
return {}
|
@@ -1514,16 +1518,16 @@ def get_pipe_attributes(
|
|
1514
1518
|
q = sqlalchemy.select(pipes_tbl).where(pipes_tbl.c.pipe_id == pipe.id)
|
1515
1519
|
if debug:
|
1516
1520
|
dprint(q)
|
1517
|
-
|
1518
|
-
|
1521
|
+
rows = (
|
1522
|
+
self.exec(q, silent=True, debug=debug).mappings().all()
|
1519
1523
|
if self.flavor != 'duckdb'
|
1520
|
-
else self.read(q, debug=debug).to_dict(orient='records')
|
1524
|
+
else self.read(q, debug=debug).to_dict(orient='records')
|
1521
1525
|
)
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1526
|
+
if not rows:
|
1527
|
+
return {}
|
1528
|
+
attributes = dict(rows[0])
|
1529
|
+
except Exception:
|
1530
|
+
warn(traceback.format_exc())
|
1527
1531
|
return {}
|
1528
1532
|
|
1529
1533
|
### handle non-PostgreSQL databases (text vs JSON)
|
@@ -1678,8 +1682,9 @@ def sync_pipe(
|
|
1678
1682
|
UPDATE_QUERIES,
|
1679
1683
|
get_reset_autoincrement_queries,
|
1680
1684
|
)
|
1681
|
-
from meerschaum.utils.dtypes import
|
1685
|
+
from meerschaum.utils.dtypes import get_current_timestamp
|
1682
1686
|
from meerschaum.utils.dtypes.sql import get_db_type_from_pd_type
|
1687
|
+
from meerschaum.utils.dataframe import get_special_cols
|
1683
1688
|
from meerschaum import Pipe
|
1684
1689
|
import time
|
1685
1690
|
import copy
|
@@ -1691,6 +1696,7 @@ def sync_pipe(
|
|
1691
1696
|
|
1692
1697
|
start = time.perf_counter()
|
1693
1698
|
pipe_name = sql_item_name(pipe.target, self.flavor, schema=self.get_pipe_schema(pipe))
|
1699
|
+
dtypes = pipe.get_dtypes(debug=debug)
|
1694
1700
|
|
1695
1701
|
if not pipe.temporary and not pipe.get_id(debug=debug):
|
1696
1702
|
register_tuple = pipe.register(debug=debug)
|
@@ -1707,6 +1713,7 @@ def sync_pipe(
|
|
1707
1713
|
df,
|
1708
1714
|
chunksize=chunksize,
|
1709
1715
|
safe_copy=kw.get('safe_copy', False),
|
1716
|
+
dtypes=dtypes,
|
1710
1717
|
debug=debug,
|
1711
1718
|
)
|
1712
1719
|
|
@@ -1719,35 +1726,18 @@ def sync_pipe(
|
|
1719
1726
|
### Check for new columns.
|
1720
1727
|
add_cols_queries = self.get_add_columns_queries(pipe, df, debug=debug)
|
1721
1728
|
if add_cols_queries:
|
1722
|
-
|
1723
|
-
|
1729
|
+
pipe._clear_cache_key('_columns_types', debug=debug)
|
1730
|
+
pipe._clear_cache_key('_columns_indices', debug=debug)
|
1724
1731
|
if not self.exec_queries(add_cols_queries, debug=debug):
|
1725
1732
|
warn(f"Failed to add new columns to {pipe}.")
|
1726
1733
|
|
1727
1734
|
alter_cols_queries = self.get_alter_columns_queries(pipe, df, debug=debug)
|
1728
1735
|
if alter_cols_queries:
|
1729
|
-
|
1730
|
-
|
1736
|
+
pipe._clear_cache_key('_columns_types', debug=debug)
|
1737
|
+
pipe._clear_cache_key('_columns_types', debug=debug)
|
1731
1738
|
if not self.exec_queries(alter_cols_queries, debug=debug):
|
1732
1739
|
warn(f"Failed to alter columns for {pipe}.")
|
1733
1740
|
|
1734
|
-
### NOTE: Oracle SQL < 23c (2023) and SQLite does not support booleans,
|
1735
|
-
### so infer bools and persist them to `dtypes`.
|
1736
|
-
if self.flavor in ('oracle', 'sqlite', 'mysql', 'mariadb'):
|
1737
|
-
pipe_dtypes = pipe.get_dtypes(infer=False, debug=debug)
|
1738
|
-
new_bool_cols = {
|
1739
|
-
col: 'bool[pyarrow]'
|
1740
|
-
for col, typ in df.dtypes.items()
|
1741
|
-
if col not in pipe_dtypes
|
1742
|
-
and are_dtypes_equal(str(typ), 'bool')
|
1743
|
-
}
|
1744
|
-
pipe_dtypes.update(new_bool_cols)
|
1745
|
-
pipe.dtypes = pipe_dtypes
|
1746
|
-
if new_bool_cols and not pipe.temporary:
|
1747
|
-
infer_bool_success, infer_bool_msg = pipe.edit(debug=debug)
|
1748
|
-
if not infer_bool_success:
|
1749
|
-
return infer_bool_success, infer_bool_msg
|
1750
|
-
|
1751
1741
|
upsert = pipe.parameters.get('upsert', False) and (self.flavor + '-upsert') in UPDATE_QUERIES
|
1752
1742
|
if upsert:
|
1753
1743
|
check_existing = False
|
@@ -1776,7 +1766,7 @@ def sync_pipe(
|
|
1776
1766
|
if 'name' in kw:
|
1777
1767
|
kw.pop('name')
|
1778
1768
|
|
1779
|
-
### Insert new data into
|
1769
|
+
### Insert new data into the target table.
|
1780
1770
|
unseen_kw = copy.deepcopy(kw)
|
1781
1771
|
unseen_kw.update({
|
1782
1772
|
'name': pipe.target,
|
@@ -1797,7 +1787,7 @@ def sync_pipe(
|
|
1797
1787
|
is_new
|
1798
1788
|
and primary_key
|
1799
1789
|
and primary_key
|
1800
|
-
not in
|
1790
|
+
not in dtypes
|
1801
1791
|
and primary_key not in unseen_df.columns
|
1802
1792
|
)
|
1803
1793
|
)
|
@@ -1897,6 +1887,14 @@ def sync_pipe(
|
|
1897
1887
|
label=('update' if not upsert else 'upsert'),
|
1898
1888
|
)
|
1899
1889
|
self._log_temporary_tables_creation(temp_target, create=(not pipe.temporary), debug=debug)
|
1890
|
+
update_dtypes = {
|
1891
|
+
**{
|
1892
|
+
col: str(typ)
|
1893
|
+
for col, typ in update_df.dtypes.items()
|
1894
|
+
},
|
1895
|
+
**get_special_cols(update_df)
|
1896
|
+
}
|
1897
|
+
|
1900
1898
|
temp_pipe = Pipe(
|
1901
1899
|
pipe.connector_keys.replace(':', '_') + '_', pipe.metric_key, pipe.location_key,
|
1902
1900
|
instance=pipe.instance_keys,
|
@@ -1905,34 +1903,30 @@ def sync_pipe(
|
|
1905
1903
|
for ix_key, ix in pipe.columns.items()
|
1906
1904
|
if ix and ix in update_df.columns
|
1907
1905
|
},
|
1908
|
-
dtypes=
|
1909
|
-
col: typ
|
1910
|
-
for col, typ in pipe.dtypes.items()
|
1911
|
-
if col in update_df.columns
|
1912
|
-
},
|
1906
|
+
dtypes=update_dtypes,
|
1913
1907
|
target=temp_target,
|
1914
1908
|
temporary=True,
|
1915
1909
|
enforce=False,
|
1916
1910
|
static=True,
|
1917
1911
|
autoincrement=False,
|
1912
|
+
cache=False,
|
1918
1913
|
parameters={
|
1919
1914
|
'schema': self.internal_schema,
|
1920
1915
|
'hypertable': False,
|
1921
1916
|
},
|
1922
1917
|
)
|
1923
|
-
|
1924
|
-
col: get_db_type_from_pd_type(
|
1925
|
-
|
1926
|
-
self.flavor,
|
1927
|
-
)
|
1928
|
-
for col, typ in update_df.dtypes.items()
|
1918
|
+
_temp_columns_types = {
|
1919
|
+
col: get_db_type_from_pd_type(typ, self.flavor)
|
1920
|
+
for col, typ in update_dtypes.items()
|
1929
1921
|
}
|
1930
|
-
|
1931
|
-
temp_pipe.
|
1932
|
-
|
1922
|
+
temp_pipe._cache_value('_columns_types', _temp_columns_types, memory_only=True, debug=debug)
|
1923
|
+
temp_pipe._cache_value('_skip_check_indices', True, memory_only=True, debug=debug)
|
1924
|
+
now_ts = get_current_timestamp('ms', as_int=True) / 1000
|
1925
|
+
temp_pipe._cache_value('_columns_types_timestamp', now_ts, memory_only=True, debug=debug)
|
1933
1926
|
temp_success, temp_msg = temp_pipe.sync(update_df, check_existing=False, debug=debug)
|
1934
1927
|
if not temp_success:
|
1935
1928
|
return temp_success, temp_msg
|
1929
|
+
|
1936
1930
|
existing_cols = pipe.get_columns_types(debug=debug)
|
1937
1931
|
join_cols = [
|
1938
1932
|
col
|
@@ -1955,6 +1949,8 @@ def sync_pipe(
|
|
1955
1949
|
upsert=upsert,
|
1956
1950
|
schema=self.get_pipe_schema(pipe),
|
1957
1951
|
patch_schema=self.internal_schema,
|
1952
|
+
target_cols_types=pipe.get_columns_types(debug=debug),
|
1953
|
+
patch_cols_types=_temp_columns_types,
|
1958
1954
|
datetime_col=(dt_col if dt_col in update_df.columns else None),
|
1959
1955
|
identity_insert=(autoincrement and primary_key in update_df.columns),
|
1960
1956
|
null_indices=pipe.null_indices,
|
@@ -2242,13 +2238,13 @@ def sync_pipe_inplace(
|
|
2242
2238
|
|
2243
2239
|
add_cols_queries = self.get_add_columns_queries(pipe, new_cols, debug=debug)
|
2244
2240
|
if add_cols_queries:
|
2245
|
-
|
2246
|
-
|
2241
|
+
pipe._clear_cache_key('_columns_types', debug=debug)
|
2242
|
+
pipe._clear_cache_key('_columns_indices', debug=debug)
|
2247
2243
|
self.exec_queries(add_cols_queries, debug=debug)
|
2248
2244
|
|
2249
2245
|
alter_cols_queries = self.get_alter_columns_queries(pipe, new_cols, debug=debug)
|
2250
2246
|
if alter_cols_queries:
|
2251
|
-
|
2247
|
+
pipe._clear_cache_key('_columns_types', debug=debug)
|
2252
2248
|
self.exec_queries(alter_cols_queries, debug=debug)
|
2253
2249
|
|
2254
2250
|
insert_queries = [
|
@@ -2551,6 +2547,8 @@ def sync_pipe_inplace(
|
|
2551
2547
|
upsert=upsert,
|
2552
2548
|
schema=self.get_pipe_schema(pipe),
|
2553
2549
|
patch_schema=internal_schema,
|
2550
|
+
target_cols_types=pipe.get_columns_types(debug=debug),
|
2551
|
+
patch_cols_types=delta_cols_types,
|
2554
2552
|
datetime_col=pipe.columns.get('datetime', None),
|
2555
2553
|
flavor=self.flavor,
|
2556
2554
|
null_indices=pipe.null_indices,
|
@@ -3041,6 +3039,7 @@ def get_pipe_table(
|
|
3041
3039
|
from meerschaum.utils.sql import get_sqlalchemy_table
|
3042
3040
|
if not pipe.exists(debug=debug):
|
3043
3041
|
return None
|
3042
|
+
|
3044
3043
|
return get_sqlalchemy_table(
|
3045
3044
|
pipe.target,
|
3046
3045
|
connector=self,
|
@@ -3098,9 +3097,11 @@ def get_pipe_columns_types(
|
|
3098
3097
|
pipe_table = self.get_pipe_table(pipe, debug=debug)
|
3099
3098
|
if pipe_table is None:
|
3100
3099
|
return {}
|
3100
|
+
|
3101
3101
|
if debug:
|
3102
|
-
dprint(
|
3102
|
+
dprint("Found columns:")
|
3103
3103
|
mrsm.pprint(dict(pipe_table.columns))
|
3104
|
+
|
3104
3105
|
for col in pipe_table.columns:
|
3105
3106
|
table_columns[str(col.name)] = str(col.type)
|
3106
3107
|
except Exception as e:
|
@@ -3132,6 +3133,7 @@ def get_pipe_columns_indices(
|
|
3132
3133
|
"""
|
3133
3134
|
if pipe.__dict__.get('_skip_check_indices', False):
|
3134
3135
|
return {}
|
3136
|
+
|
3135
3137
|
from meerschaum.utils.sql import get_table_cols_indices
|
3136
3138
|
return get_table_cols_indices(
|
3137
3139
|
pipe.target,
|
@@ -3186,7 +3188,6 @@ def get_add_columns_queries(
|
|
3186
3188
|
get_db_type_from_pd_type,
|
3187
3189
|
)
|
3188
3190
|
from meerschaum.utils.misc import flatten_list
|
3189
|
-
table_obj = self.get_pipe_table(pipe, debug=debug)
|
3190
3191
|
is_dask = 'dask' in df.__module__ if not isinstance(df, dict) else False
|
3191
3192
|
if is_dask:
|
3192
3193
|
df = df.partitions[0].compute()
|
@@ -3210,9 +3211,6 @@ def get_add_columns_queries(
|
|
3210
3211
|
elif isinstance(val, str):
|
3211
3212
|
df_cols_types[col] = 'str'
|
3212
3213
|
db_cols_types = {
|
3213
|
-
col: get_pd_type_from_db_type(str(typ.type))
|
3214
|
-
for col, typ in table_obj.columns.items()
|
3215
|
-
} if table_obj is not None else {
|
3216
3214
|
col: get_pd_type_from_db_type(typ)
|
3217
3215
|
for col, typ in get_table_cols_types(
|
3218
3216
|
pipe.target,
|
@@ -3308,7 +3306,6 @@ def get_alter_columns_queries(
|
|
3308
3306
|
get_db_type_from_pd_type,
|
3309
3307
|
)
|
3310
3308
|
from meerschaum.utils.misc import flatten_list, generate_password, items_str
|
3311
|
-
table_obj = self.get_pipe_table(pipe, debug=debug)
|
3312
3309
|
target = pipe.target
|
3313
3310
|
session_id = generate_password(3)
|
3314
3311
|
numeric_cols = (
|
@@ -3329,9 +3326,6 @@ def get_alter_columns_queries(
|
|
3329
3326
|
else df
|
3330
3327
|
)
|
3331
3328
|
db_cols_types = {
|
3332
|
-
col: get_pd_type_from_db_type(str(typ.type))
|
3333
|
-
for col, typ in table_obj.columns.items()
|
3334
|
-
} if table_obj is not None else {
|
3335
3329
|
col: get_pd_type_from_db_type(typ)
|
3336
3330
|
for col, typ in get_table_cols_types(
|
3337
3331
|
pipe.target,
|
@@ -3340,7 +3334,7 @@ def get_alter_columns_queries(
|
|
3340
3334
|
debug=debug,
|
3341
3335
|
).items()
|
3342
3336
|
}
|
3343
|
-
pipe_dtypes = pipe.
|
3337
|
+
pipe_dtypes = pipe.get_dtypes(debug=debug)
|
3344
3338
|
pipe_bool_cols = [col for col, typ in pipe_dtypes.items() if are_dtypes_equal(str(typ), 'bool')]
|
3345
3339
|
pd_db_df_aliases = {
|
3346
3340
|
'int': 'bool',
|
@@ -3352,6 +3346,7 @@ def get_alter_columns_queries(
|
|
3352
3346
|
pd_db_df_aliases.update({
|
3353
3347
|
'int': 'numeric',
|
3354
3348
|
'date': 'datetime',
|
3349
|
+
'numeric': 'int',
|
3355
3350
|
})
|
3356
3351
|
|
3357
3352
|
altered_cols = {
|
@@ -3362,14 +3357,32 @@ def get_alter_columns_queries(
|
|
3362
3357
|
}
|
3363
3358
|
|
3364
3359
|
if debug and altered_cols:
|
3365
|
-
dprint(
|
3360
|
+
dprint("Columns to be altered:")
|
3366
3361
|
mrsm.pprint(altered_cols)
|
3367
3362
|
|
3363
|
+
### NOTE: Special columns (numerics, bools, etc.) are captured and cached upon detection.
|
3364
|
+
new_special_cols = pipe._get_cached_value('new_special_cols', debug=debug) or {}
|
3365
|
+
new_special_db_cols_types = {
|
3366
|
+
col: (db_cols_types.get(col, 'object'), typ)
|
3367
|
+
for col, typ in new_special_cols.items()
|
3368
|
+
}
|
3369
|
+
if debug:
|
3370
|
+
dprint("Cached new special columns:")
|
3371
|
+
mrsm.pprint(new_special_cols)
|
3372
|
+
dprint("New special columns db types:")
|
3373
|
+
mrsm.pprint(new_special_db_cols_types)
|
3374
|
+
|
3375
|
+
altered_cols.update(new_special_db_cols_types)
|
3376
|
+
|
3368
3377
|
### NOTE: Sometimes bools are coerced into ints or floats.
|
3369
3378
|
altered_cols_to_ignore = set()
|
3370
3379
|
for col, (db_typ, df_typ) in altered_cols.items():
|
3371
3380
|
for db_alias, df_alias in pd_db_df_aliases.items():
|
3372
|
-
if
|
3381
|
+
if (
|
3382
|
+
db_alias in db_typ.lower()
|
3383
|
+
and df_alias in df_typ.lower()
|
3384
|
+
and col not in new_special_cols
|
3385
|
+
):
|
3373
3386
|
altered_cols_to_ignore.add(col)
|
3374
3387
|
|
3375
3388
|
### Oracle's bool handling sometimes mixes NUMBER and INT.
|
@@ -3392,7 +3405,7 @@ def get_alter_columns_queries(
|
|
3392
3405
|
altered_cols_to_ignore.add(bool_col)
|
3393
3406
|
|
3394
3407
|
if debug and altered_cols_to_ignore:
|
3395
|
-
dprint(
|
3408
|
+
dprint("Ignoring the following altered columns (false positives).")
|
3396
3409
|
mrsm.pprint(altered_cols_to_ignore)
|
3397
3410
|
|
3398
3411
|
for col in altered_cols_to_ignore:
|
@@ -3439,12 +3452,12 @@ def get_alter_columns_queries(
|
|
3439
3452
|
+ sql_item_name(target, self.flavor, self.get_pipe_schema(pipe))
|
3440
3453
|
+ " (\n"
|
3441
3454
|
)
|
3442
|
-
for col_name,
|
3455
|
+
for col_name, col_typ in db_cols_types.items():
|
3443
3456
|
create_query += (
|
3444
3457
|
sql_item_name(col_name, self.flavor, None)
|
3445
3458
|
+ " "
|
3446
3459
|
+ (
|
3447
|
-
|
3460
|
+
col_typ
|
3448
3461
|
if col_name not in altered_cols
|
3449
3462
|
else altered_cols_types[col_name]
|
3450
3463
|
)
|
@@ -3458,12 +3471,12 @@ def get_alter_columns_queries(
|
|
3458
3471
|
+ ' ('
|
3459
3472
|
+ ', '.join([
|
3460
3473
|
sql_item_name(col_name, self.flavor, None)
|
3461
|
-
for col_name
|
3474
|
+
for col_name in db_cols_types
|
3462
3475
|
])
|
3463
3476
|
+ ')'
|
3464
3477
|
+ "\nSELECT\n"
|
3465
3478
|
)
|
3466
|
-
for col_name
|
3479
|
+
for col_name in db_cols_types:
|
3467
3480
|
new_col_str = (
|
3468
3481
|
sql_item_name(col_name, self.flavor, None)
|
3469
3482
|
if col_name not in altered_cols
|
@@ -3476,6 +3489,7 @@ def get_alter_columns_queries(
|
|
3476
3489
|
)
|
3477
3490
|
)
|
3478
3491
|
insert_query += new_col_str + ",\n"
|
3492
|
+
|
3479
3493
|
insert_query = insert_query[:-2] + (
|
3480
3494
|
f"\nFROM {sql_item_name(temp_table_name, self.flavor, self.get_pipe_schema(pipe))}"
|
3481
3495
|
)
|
@@ -16,9 +16,15 @@ def get_users_pipe(self) -> mrsm.Pipe:
|
|
16
16
|
"""
|
17
17
|
Return the internal metadata pipe for users management.
|
18
18
|
"""
|
19
|
-
|
19
|
+
if '_users_pipe' in self.__dict__:
|
20
|
+
return self._users_pipe
|
21
|
+
|
22
|
+
cache_connector = self.__dict__.get('_cache_connector', None)
|
23
|
+
self._users_pipe = mrsm.Pipe(
|
20
24
|
'mrsm', 'users',
|
21
25
|
temporary=True,
|
26
|
+
cache=True,
|
27
|
+
cache_connector_keys=cache_connector,
|
22
28
|
static=True,
|
23
29
|
null_indices=False,
|
24
30
|
enforce=False,
|
@@ -36,6 +42,7 @@ def get_users_pipe(self) -> mrsm.Pipe:
|
|
36
42
|
'unique': 'username',
|
37
43
|
},
|
38
44
|
)
|
45
|
+
return self._users_pipe
|
39
46
|
|
40
47
|
|
41
48
|
def register_user(
|
@@ -140,13 +140,13 @@ class ValkeyConnector(InstanceConnector):
|
|
140
140
|
|
141
141
|
return uri
|
142
142
|
|
143
|
-
def set(self, key: str, value: Any, **kwargs: Any) ->
|
143
|
+
def set(self, key: str, value: Any, **kwargs: Any) -> bool:
|
144
144
|
"""
|
145
145
|
Set the `key` to `value`.
|
146
146
|
"""
|
147
147
|
return self.client.set(key, value, **kwargs)
|
148
148
|
|
149
|
-
def get(self, key: str) -> Union[str, None]:
|
149
|
+
def get(self, key: str, decode: bool = True) -> Union[str, None]:
|
150
150
|
"""
|
151
151
|
Get the value for `key`.
|
152
152
|
"""
|
@@ -154,7 +154,7 @@ class ValkeyConnector(InstanceConnector):
|
|
154
154
|
if val is None:
|
155
155
|
return None
|
156
156
|
|
157
|
-
return val.decode('utf-8')
|
157
|
+
return val.decode('utf-8') if decode else val
|
158
158
|
|
159
159
|
def test_connection(self) -> bool:
|
160
160
|
"""
|
@@ -888,7 +888,9 @@ def fetch_pipes_keys(
|
|
888
888
|
tags: Optional[List[str]] = None,
|
889
889
|
params: Optional[Dict[str, Any]] = None,
|
890
890
|
debug: bool = False
|
891
|
-
) ->
|
891
|
+
) -> List[
|
892
|
+
Tuple[str, str, Union[str, None], Dict[str, Any]]
|
893
|
+
]:
|
892
894
|
"""
|
893
895
|
Return the keys for the registered pipes.
|
894
896
|
"""
|
@@ -919,6 +921,7 @@ def fetch_pipes_keys(
|
|
919
921
|
doc['connector_keys'],
|
920
922
|
doc['metric_key'],
|
921
923
|
doc['location_key'],
|
924
|
+
doc.get('parameters', {})
|
922
925
|
)
|
923
926
|
for doc in df.to_dict(orient='records')
|
924
927
|
]
|
@@ -929,9 +932,8 @@ def fetch_pipes_keys(
|
|
929
932
|
in_ex_tag_groups = [separate_negation_values(tag_group) for tag_group in tag_groups]
|
930
933
|
|
931
934
|
filtered_keys = []
|
932
|
-
for ck, mk, lk in keys:
|
933
|
-
|
934
|
-
pipe_tags = set(pipe.tags)
|
935
|
+
for ck, mk, lk, parameters in keys:
|
936
|
+
pipe_tags = set(parameters.get('tags', []))
|
935
937
|
|
936
938
|
include_pipe = True
|
937
939
|
for in_tags, ex_tags in in_ex_tag_groups:
|
@@ -943,6 +945,6 @@ def fetch_pipes_keys(
|
|
943
945
|
continue
|
944
946
|
|
945
947
|
if include_pipe:
|
946
|
-
filtered_keys.append((ck, mk, lk))
|
948
|
+
filtered_keys.append((ck, mk, lk, parameters))
|
947
949
|
|
948
950
|
return filtered_keys
|