singlestoredb 1.14.1__cp38-abi3-win32.whl → 1.15.0__cp38-abi3-win32.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.
Potentially problematic release.
This version of singlestoredb might be problematic. Click here for more details.
- _singlestoredb_accel.pyd +0 -0
- singlestoredb/__init__.py +14 -10
- singlestoredb/apps/_python_udfs.py +3 -3
- singlestoredb/config.py +5 -0
- singlestoredb/functions/decorator.py +32 -13
- singlestoredb/functions/ext/asgi.py +287 -27
- singlestoredb/functions/ext/timer.py +98 -0
- singlestoredb/functions/typing/numpy.py +20 -0
- singlestoredb/functions/typing/pandas.py +2 -0
- singlestoredb/functions/typing/polars.py +2 -0
- singlestoredb/functions/typing/pyarrow.py +2 -0
- singlestoredb/fusion/handler.py +17 -4
- singlestoredb/magics/run_personal.py +82 -1
- singlestoredb/magics/run_shared.py +82 -1
- singlestoredb/management/__init__.py +1 -0
- singlestoredb/management/export.py +1 -1
- singlestoredb/management/region.py +92 -0
- singlestoredb/management/workspace.py +180 -1
- singlestoredb/tests/ext_funcs/__init__.py +94 -55
- singlestoredb/tests/test.sql +22 -0
- singlestoredb/tests/test_ext_func.py +90 -0
- singlestoredb/tests/test_fusion.py +4 -1
- singlestoredb/tests/test_management.py +253 -20
- {singlestoredb-1.14.1.dist-info → singlestoredb-1.15.0.dist-info}/METADATA +3 -2
- {singlestoredb-1.14.1.dist-info → singlestoredb-1.15.0.dist-info}/RECORD +30 -25
- /singlestoredb/functions/{typing.py → typing/__init__.py} +0 -0
- {singlestoredb-1.14.1.dist-info → singlestoredb-1.15.0.dist-info}/LICENSE +0 -0
- {singlestoredb-1.14.1.dist-info → singlestoredb-1.15.0.dist-info}/WHEEL +0 -0
- {singlestoredb-1.14.1.dist-info → singlestoredb-1.15.0.dist-info}/entry_points.txt +0 -0
- {singlestoredb-1.14.1.dist-info → singlestoredb-1.15.0.dist-info}/top_level.txt +0 -0
|
@@ -1301,17 +1301,24 @@ class StarterWorkspace(object):
|
|
|
1301
1301
|
See Also
|
|
1302
1302
|
--------
|
|
1303
1303
|
:meth:`WorkspaceManager.get_starter_workspace`
|
|
1304
|
+
:meth:`WorkspaceManager.create_starter_workspace`
|
|
1305
|
+
:meth:`WorkspaceManager.terminate_starter_workspace`
|
|
1306
|
+
:meth:`WorkspaceManager.create_starter_workspace_user`
|
|
1304
1307
|
:attr:`WorkspaceManager.starter_workspaces`
|
|
1305
1308
|
|
|
1306
1309
|
"""
|
|
1307
1310
|
|
|
1308
1311
|
name: str
|
|
1309
1312
|
id: str
|
|
1313
|
+
database_name: str
|
|
1314
|
+
endpoint: Optional[str]
|
|
1310
1315
|
|
|
1311
1316
|
def __init__(
|
|
1312
1317
|
self,
|
|
1313
1318
|
name: str,
|
|
1314
1319
|
id: str,
|
|
1320
|
+
database_name: str,
|
|
1321
|
+
endpoint: Optional[str] = None,
|
|
1315
1322
|
):
|
|
1316
1323
|
#: Name of the starter workspace
|
|
1317
1324
|
self.name = name
|
|
@@ -1319,6 +1326,13 @@ class StarterWorkspace(object):
|
|
|
1319
1326
|
#: Unique ID of the starter workspace
|
|
1320
1327
|
self.id = id
|
|
1321
1328
|
|
|
1329
|
+
#: Name of the database associated with the starter workspace
|
|
1330
|
+
self.database_name = database_name
|
|
1331
|
+
|
|
1332
|
+
#: Endpoint to connect to the starter workspace. The endpoint is in the form
|
|
1333
|
+
#: of ``hostname:port``
|
|
1334
|
+
self.endpoint = endpoint
|
|
1335
|
+
|
|
1322
1336
|
self._manager: Optional[WorkspaceManager] = None
|
|
1323
1337
|
|
|
1324
1338
|
def __str__(self) -> str:
|
|
@@ -1351,10 +1365,63 @@ class StarterWorkspace(object):
|
|
|
1351
1365
|
out = cls(
|
|
1352
1366
|
name=obj['name'],
|
|
1353
1367
|
id=obj['virtualWorkspaceID'],
|
|
1368
|
+
database_name=obj['databaseName'],
|
|
1369
|
+
endpoint=obj.get('endpoint'),
|
|
1354
1370
|
)
|
|
1355
1371
|
out._manager = manager
|
|
1356
1372
|
return out
|
|
1357
1373
|
|
|
1374
|
+
def connect(self, **kwargs: Any) -> connection.Connection:
|
|
1375
|
+
"""
|
|
1376
|
+
Create a connection to the database server for this starter workspace.
|
|
1377
|
+
|
|
1378
|
+
Parameters
|
|
1379
|
+
----------
|
|
1380
|
+
**kwargs : keyword-arguments, optional
|
|
1381
|
+
Parameters to the SingleStoreDB `connect` function except host
|
|
1382
|
+
and port which are supplied by the starter workspace object
|
|
1383
|
+
|
|
1384
|
+
Returns
|
|
1385
|
+
-------
|
|
1386
|
+
:class:`Connection`
|
|
1387
|
+
|
|
1388
|
+
"""
|
|
1389
|
+
if not self.endpoint:
|
|
1390
|
+
raise ManagementError(
|
|
1391
|
+
msg='An endpoint has not been set in this '
|
|
1392
|
+
'starter workspace configuration',
|
|
1393
|
+
)
|
|
1394
|
+
# Parse endpoint as host:port
|
|
1395
|
+
if ':' in self.endpoint:
|
|
1396
|
+
host, port = self.endpoint.split(':', 1)
|
|
1397
|
+
kwargs['host'] = host
|
|
1398
|
+
kwargs['port'] = int(port)
|
|
1399
|
+
else:
|
|
1400
|
+
kwargs['host'] = self.endpoint
|
|
1401
|
+
return connection.connect(**kwargs)
|
|
1402
|
+
|
|
1403
|
+
def terminate(self) -> None:
|
|
1404
|
+
"""Terminate the starter workspace."""
|
|
1405
|
+
if self._manager is None:
|
|
1406
|
+
raise ManagementError(
|
|
1407
|
+
msg='No workspace manager is associated with this object.',
|
|
1408
|
+
)
|
|
1409
|
+
self._manager._delete(f'sharedtier/virtualWorkspaces/{self.id}')
|
|
1410
|
+
|
|
1411
|
+
def refresh(self) -> StarterWorkspace:
|
|
1412
|
+
"""Update the object to the current state."""
|
|
1413
|
+
if self._manager is None:
|
|
1414
|
+
raise ManagementError(
|
|
1415
|
+
msg='No workspace manager is associated with this object.',
|
|
1416
|
+
)
|
|
1417
|
+
new_obj = self._manager.get_starter_workspace(self.id)
|
|
1418
|
+
for name, value in vars(new_obj).items():
|
|
1419
|
+
if isinstance(value, Mapping):
|
|
1420
|
+
setattr(self, name, snake_to_camel_dict(value))
|
|
1421
|
+
else:
|
|
1422
|
+
setattr(self, name, value)
|
|
1423
|
+
return self
|
|
1424
|
+
|
|
1358
1425
|
@property
|
|
1359
1426
|
def organization(self) -> Organization:
|
|
1360
1427
|
if self._manager is None:
|
|
@@ -1375,7 +1442,7 @@ class StarterWorkspace(object):
|
|
|
1375
1442
|
stages = stage
|
|
1376
1443
|
|
|
1377
1444
|
@property
|
|
1378
|
-
def starter_workspaces(self) -> NamedList[StarterWorkspace]:
|
|
1445
|
+
def starter_workspaces(self) -> NamedList['StarterWorkspace']:
|
|
1379
1446
|
"""Return a list of available starter workspaces."""
|
|
1380
1447
|
if self._manager is None:
|
|
1381
1448
|
raise ManagementError(
|
|
@@ -1386,6 +1453,64 @@ class StarterWorkspace(object):
|
|
|
1386
1453
|
[StarterWorkspace.from_dict(item, self._manager) for item in res.json()],
|
|
1387
1454
|
)
|
|
1388
1455
|
|
|
1456
|
+
def create_user(
|
|
1457
|
+
self,
|
|
1458
|
+
user_name: str,
|
|
1459
|
+
password: Optional[str] = None,
|
|
1460
|
+
) -> Dict[str, str]:
|
|
1461
|
+
"""
|
|
1462
|
+
Create a new user for this starter workspace.
|
|
1463
|
+
|
|
1464
|
+
Parameters
|
|
1465
|
+
----------
|
|
1466
|
+
user_name : str
|
|
1467
|
+
The starter workspace user name to connect the new user to the database
|
|
1468
|
+
password : str, optional
|
|
1469
|
+
Password for the new user. If not provided, a password will be
|
|
1470
|
+
auto-generated by the system.
|
|
1471
|
+
|
|
1472
|
+
Returns
|
|
1473
|
+
-------
|
|
1474
|
+
Dict[str, str]
|
|
1475
|
+
Dictionary containing 'userID' and 'password' of the created user
|
|
1476
|
+
|
|
1477
|
+
Raises
|
|
1478
|
+
------
|
|
1479
|
+
ManagementError
|
|
1480
|
+
If no workspace manager is associated with this object.
|
|
1481
|
+
"""
|
|
1482
|
+
if self._manager is None:
|
|
1483
|
+
raise ManagementError(
|
|
1484
|
+
msg='No workspace manager is associated with this object.',
|
|
1485
|
+
)
|
|
1486
|
+
|
|
1487
|
+
payload = {
|
|
1488
|
+
'userName': user_name,
|
|
1489
|
+
}
|
|
1490
|
+
if password is not None:
|
|
1491
|
+
payload['password'] = password
|
|
1492
|
+
|
|
1493
|
+
res = self._manager._post(
|
|
1494
|
+
f'sharedtier/virtualWorkspaces/{self.id}/users',
|
|
1495
|
+
json=payload,
|
|
1496
|
+
)
|
|
1497
|
+
|
|
1498
|
+
response_data = res.json()
|
|
1499
|
+
user_id = response_data.get('userID')
|
|
1500
|
+
if not user_id:
|
|
1501
|
+
raise ManagementError(msg='No userID returned from API')
|
|
1502
|
+
|
|
1503
|
+
# Return the password provided by user or generated by API
|
|
1504
|
+
returned_password = password if password is not None \
|
|
1505
|
+
else response_data.get('password')
|
|
1506
|
+
if not returned_password:
|
|
1507
|
+
raise ManagementError(msg='No password available from API response')
|
|
1508
|
+
|
|
1509
|
+
return {
|
|
1510
|
+
'user_id': user_id,
|
|
1511
|
+
'password': returned_password,
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1389
1514
|
|
|
1390
1515
|
class Billing(object):
|
|
1391
1516
|
"""Billing information."""
|
|
@@ -1522,6 +1647,14 @@ class WorkspaceManager(Manager):
|
|
|
1522
1647
|
res = self._get('regions')
|
|
1523
1648
|
return NamedList([Region.from_dict(item, self) for item in res.json()])
|
|
1524
1649
|
|
|
1650
|
+
@ttl_property(datetime.timedelta(hours=1))
|
|
1651
|
+
def shared_tier_regions(self) -> NamedList[Region]:
|
|
1652
|
+
"""Return a list of regions that support shared tier workspaces."""
|
|
1653
|
+
res = self._get('regions/sharedtier')
|
|
1654
|
+
return NamedList(
|
|
1655
|
+
[Region.from_dict(item, self) for item in res.json()],
|
|
1656
|
+
)
|
|
1657
|
+
|
|
1525
1658
|
def create_workspace_group(
|
|
1526
1659
|
self,
|
|
1527
1660
|
name: str,
|
|
@@ -1717,6 +1850,52 @@ class WorkspaceManager(Manager):
|
|
|
1717
1850
|
res = self._get(f'sharedtier/virtualWorkspaces/{id}')
|
|
1718
1851
|
return StarterWorkspace.from_dict(res.json(), manager=self)
|
|
1719
1852
|
|
|
1853
|
+
def create_starter_workspace(
|
|
1854
|
+
self,
|
|
1855
|
+
name: str,
|
|
1856
|
+
database_name: str,
|
|
1857
|
+
workspace_group: dict[str, str],
|
|
1858
|
+
) -> 'StarterWorkspace':
|
|
1859
|
+
"""
|
|
1860
|
+
Create a new starter (shared tier) workspace.
|
|
1861
|
+
|
|
1862
|
+
Parameters
|
|
1863
|
+
----------
|
|
1864
|
+
name : str
|
|
1865
|
+
Name of the starter workspace
|
|
1866
|
+
database_name : str
|
|
1867
|
+
Name of the database for the starter workspace
|
|
1868
|
+
workspace_group : dict[str, str]
|
|
1869
|
+
Workspace group input (dict with keys: 'cell_id')
|
|
1870
|
+
|
|
1871
|
+
Returns
|
|
1872
|
+
-------
|
|
1873
|
+
:class:`StarterWorkspace`
|
|
1874
|
+
"""
|
|
1875
|
+
if not workspace_group or not isinstance(workspace_group, dict):
|
|
1876
|
+
raise ValueError(
|
|
1877
|
+
'workspace_group must be a dict with keys: '
|
|
1878
|
+
"'cell_id'",
|
|
1879
|
+
)
|
|
1880
|
+
if set(workspace_group.keys()) != {'cell_id'}:
|
|
1881
|
+
raise ValueError("workspace_group must contain only 'cell_id'")
|
|
1882
|
+
|
|
1883
|
+
payload = {
|
|
1884
|
+
'name': name,
|
|
1885
|
+
'databaseName': database_name,
|
|
1886
|
+
'workspaceGroup': {
|
|
1887
|
+
'cellID': workspace_group['cell_id'],
|
|
1888
|
+
},
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
res = self._post('sharedtier/virtualWorkspaces', json=payload)
|
|
1892
|
+
virtual_workspace_id = res.json().get('virtualWorkspaceID')
|
|
1893
|
+
if not virtual_workspace_id:
|
|
1894
|
+
raise ManagementError(msg='No virtualWorkspaceID returned from API')
|
|
1895
|
+
|
|
1896
|
+
res = self._get(f'sharedtier/virtualWorkspaces/{virtual_workspace_id}')
|
|
1897
|
+
return StarterWorkspace.from_dict(res.json(), self)
|
|
1898
|
+
|
|
1720
1899
|
|
|
1721
1900
|
def manage_workspaces(
|
|
1722
1901
|
access_token: Optional[str] = None,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
# mypy: disable-error-code="type-arg"
|
|
3
|
+
import asyncio
|
|
4
|
+
import time
|
|
3
5
|
import typing
|
|
4
6
|
from typing import List
|
|
5
7
|
from typing import NamedTuple
|
|
@@ -7,10 +9,6 @@ from typing import Optional
|
|
|
7
9
|
from typing import Tuple
|
|
8
10
|
|
|
9
11
|
import numpy as np
|
|
10
|
-
import numpy.typing as npt
|
|
11
|
-
import pandas as pd
|
|
12
|
-
import polars as pl
|
|
13
|
-
import pyarrow as pa
|
|
14
12
|
|
|
15
13
|
import singlestoredb.functions.dtypes as dt
|
|
16
14
|
from singlestoredb.functions import Masked
|
|
@@ -24,6 +22,10 @@ from singlestoredb.functions.dtypes import MEDIUMINT
|
|
|
24
22
|
from singlestoredb.functions.dtypes import SMALLINT
|
|
25
23
|
from singlestoredb.functions.dtypes import TEXT
|
|
26
24
|
from singlestoredb.functions.dtypes import TINYINT
|
|
25
|
+
from singlestoredb.functions.typing import numpy as npt
|
|
26
|
+
from singlestoredb.functions.typing import pandas as pdt
|
|
27
|
+
from singlestoredb.functions.typing import polars as plt
|
|
28
|
+
from singlestoredb.functions.typing import pyarrow as pat
|
|
27
29
|
|
|
28
30
|
|
|
29
31
|
@udf
|
|
@@ -36,19 +38,44 @@ def double_mult(x: float, y: float) -> float:
|
|
|
36
38
|
return x * y
|
|
37
39
|
|
|
38
40
|
|
|
41
|
+
@udf(timeout=2)
|
|
42
|
+
def timeout_double_mult(x: float, y: float) -> float:
|
|
43
|
+
time.sleep(5)
|
|
44
|
+
return x * y
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@udf
|
|
48
|
+
async def async_double_mult(x: float, y: float) -> float:
|
|
49
|
+
return x * y
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@udf(timeout=2)
|
|
53
|
+
async def async_timeout_double_mult(x: float, y: float) -> float:
|
|
54
|
+
await asyncio.sleep(5)
|
|
55
|
+
return x * y
|
|
56
|
+
|
|
57
|
+
|
|
39
58
|
@udf(
|
|
40
59
|
args=[DOUBLE(nullable=False), DOUBLE(nullable=False)],
|
|
41
60
|
returns=DOUBLE(nullable=False),
|
|
42
61
|
)
|
|
43
|
-
def pandas_double_mult(x:
|
|
62
|
+
def pandas_double_mult(x: pdt.Series, y: pdt.Series) -> pdt.Series:
|
|
44
63
|
return x * y
|
|
45
64
|
|
|
46
65
|
|
|
47
66
|
@udf
|
|
48
67
|
def numpy_double_mult(
|
|
49
|
-
x: npt.
|
|
50
|
-
y: npt.
|
|
51
|
-
) -> npt.
|
|
68
|
+
x: npt.Float64Array,
|
|
69
|
+
y: npt.Float64Array,
|
|
70
|
+
) -> npt.Float64Array:
|
|
71
|
+
return x * y
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@udf
|
|
75
|
+
async def async_numpy_double_mult(
|
|
76
|
+
x: npt.Float64Array,
|
|
77
|
+
y: npt.Float64Array,
|
|
78
|
+
) -> npt.Float64Array:
|
|
52
79
|
return x * y
|
|
53
80
|
|
|
54
81
|
|
|
@@ -56,7 +83,7 @@ def numpy_double_mult(
|
|
|
56
83
|
args=[DOUBLE(nullable=False), DOUBLE(nullable=False)],
|
|
57
84
|
returns=DOUBLE(nullable=False),
|
|
58
85
|
)
|
|
59
|
-
def arrow_double_mult(x:
|
|
86
|
+
def arrow_double_mult(x: pat.Array, y: pat.Array) -> pat.Array:
|
|
60
87
|
import pyarrow.compute as pc
|
|
61
88
|
return pc.multiply(x, y)
|
|
62
89
|
|
|
@@ -65,7 +92,7 @@ def arrow_double_mult(x: pa.Array, y: pa.Array) -> pa.Array:
|
|
|
65
92
|
args=[DOUBLE(nullable=False), DOUBLE(nullable=False)],
|
|
66
93
|
returns=DOUBLE(nullable=False),
|
|
67
94
|
)
|
|
68
|
-
def polars_double_mult(x:
|
|
95
|
+
def polars_double_mult(x: plt.Series, y: plt.Series) -> plt.Series:
|
|
69
96
|
return x * y
|
|
70
97
|
|
|
71
98
|
|
|
@@ -106,12 +133,12 @@ def tinyint_mult(x: Optional[int], y: Optional[int]) -> Optional[int]:
|
|
|
106
133
|
|
|
107
134
|
|
|
108
135
|
@tinyint_udf
|
|
109
|
-
def pandas_tinyint_mult(x:
|
|
136
|
+
def pandas_tinyint_mult(x: pdt.Series, y: pdt.Series) -> pdt.Series:
|
|
110
137
|
return x * y
|
|
111
138
|
|
|
112
139
|
|
|
113
140
|
@tinyint_udf
|
|
114
|
-
def polars_tinyint_mult(x:
|
|
141
|
+
def polars_tinyint_mult(x: plt.Series, y: plt.Series) -> plt.Series:
|
|
115
142
|
return x * y
|
|
116
143
|
|
|
117
144
|
|
|
@@ -121,7 +148,7 @@ def numpy_tinyint_mult(x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
|
|
121
148
|
|
|
122
149
|
|
|
123
150
|
@tinyint_udf
|
|
124
|
-
def arrow_tinyint_mult(x:
|
|
151
|
+
def arrow_tinyint_mult(x: pat.Array, y: pat.Array) -> pat.Array:
|
|
125
152
|
import pyarrow.compute as pc
|
|
126
153
|
return pc.multiply(x, y)
|
|
127
154
|
|
|
@@ -144,12 +171,12 @@ def smallint_mult(x: Optional[int], y: Optional[int]) -> Optional[int]:
|
|
|
144
171
|
|
|
145
172
|
|
|
146
173
|
@smallint_udf
|
|
147
|
-
def pandas_smallint_mult(x:
|
|
174
|
+
def pandas_smallint_mult(x: pdt.Series, y: pdt.Series) -> pdt.Series:
|
|
148
175
|
return x * y
|
|
149
176
|
|
|
150
177
|
|
|
151
178
|
@smallint_udf
|
|
152
|
-
def polars_smallint_mult(x:
|
|
179
|
+
def polars_smallint_mult(x: plt.Series, y: plt.Series) -> plt.Series:
|
|
153
180
|
return x * y
|
|
154
181
|
|
|
155
182
|
|
|
@@ -159,7 +186,7 @@ def numpy_smallint_mult(x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
|
|
159
186
|
|
|
160
187
|
|
|
161
188
|
@smallint_udf
|
|
162
|
-
def arrow_smallint_mult(x:
|
|
189
|
+
def arrow_smallint_mult(x: pat.Array, y: pat.Array) -> pat.Array:
|
|
163
190
|
import pyarrow.compute as pc
|
|
164
191
|
return pc.multiply(x, y)
|
|
165
192
|
|
|
@@ -183,12 +210,12 @@ def mediumint_mult(x: Optional[int], y: Optional[int]) -> Optional[int]:
|
|
|
183
210
|
|
|
184
211
|
|
|
185
212
|
@mediumint_udf
|
|
186
|
-
def pandas_mediumint_mult(x:
|
|
213
|
+
def pandas_mediumint_mult(x: pdt.Series, y: pdt.Series) -> pdt.Series:
|
|
187
214
|
return x * y
|
|
188
215
|
|
|
189
216
|
|
|
190
217
|
@mediumint_udf
|
|
191
|
-
def polars_mediumint_mult(x:
|
|
218
|
+
def polars_mediumint_mult(x: plt.Series, y: plt.Series) -> plt.Series:
|
|
192
219
|
return x * y
|
|
193
220
|
|
|
194
221
|
|
|
@@ -198,7 +225,7 @@ def numpy_mediumint_mult(x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
|
|
198
225
|
|
|
199
226
|
|
|
200
227
|
@mediumint_udf
|
|
201
|
-
def arrow_mediumint_mult(x:
|
|
228
|
+
def arrow_mediumint_mult(x: pat.Array, y: pat.Array) -> pat.Array:
|
|
202
229
|
import pyarrow.compute as pc
|
|
203
230
|
return pc.multiply(x, y)
|
|
204
231
|
|
|
@@ -222,12 +249,12 @@ def bigint_mult(x: Optional[int], y: Optional[int]) -> Optional[int]:
|
|
|
222
249
|
|
|
223
250
|
|
|
224
251
|
@bigint_udf
|
|
225
|
-
def pandas_bigint_mult(x:
|
|
252
|
+
def pandas_bigint_mult(x: pdt.Series, y: pdt.Series) -> pdt.Series:
|
|
226
253
|
return x * y
|
|
227
254
|
|
|
228
255
|
|
|
229
256
|
@bigint_udf
|
|
230
|
-
def polars_bigint_mult(x:
|
|
257
|
+
def polars_bigint_mult(x: plt.Series, y: plt.Series) -> plt.Series:
|
|
231
258
|
return x * y
|
|
232
259
|
|
|
233
260
|
|
|
@@ -237,7 +264,7 @@ def numpy_bigint_mult(x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
|
|
237
264
|
|
|
238
265
|
|
|
239
266
|
@bigint_udf
|
|
240
|
-
def arrow_bigint_mult(x:
|
|
267
|
+
def arrow_bigint_mult(x: pat.Array, y: pat.Array) -> pat.Array:
|
|
241
268
|
import pyarrow.compute as pc
|
|
242
269
|
return pc.multiply(x, y)
|
|
243
270
|
|
|
@@ -261,12 +288,12 @@ def nullable_tinyint_mult(x: Optional[int], y: Optional[int]) -> Optional[int]:
|
|
|
261
288
|
|
|
262
289
|
|
|
263
290
|
@nullable_tinyint_udf
|
|
264
|
-
def pandas_nullable_tinyint_mult(x:
|
|
291
|
+
def pandas_nullable_tinyint_mult(x: pdt.Series, y: pdt.Series) -> pdt.Series:
|
|
265
292
|
return x * y
|
|
266
293
|
|
|
267
294
|
|
|
268
295
|
@nullable_tinyint_udf
|
|
269
|
-
def polars_nullable_tinyint_mult(x:
|
|
296
|
+
def polars_nullable_tinyint_mult(x: plt.Series, y: plt.Series) -> plt.Series:
|
|
270
297
|
return x * y
|
|
271
298
|
|
|
272
299
|
|
|
@@ -276,7 +303,7 @@ def numpy_nullable_tinyint_mult(x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
|
|
276
303
|
|
|
277
304
|
|
|
278
305
|
@nullable_tinyint_udf
|
|
279
|
-
def arrow_nullable_tinyint_mult(x:
|
|
306
|
+
def arrow_nullable_tinyint_mult(x: pat.Array, y: pat.Array) -> pat.Array:
|
|
280
307
|
import pyarrow.compute as pc
|
|
281
308
|
return pc.multiply(x, y)
|
|
282
309
|
|
|
@@ -299,12 +326,12 @@ def nullable_smallint_mult(x: Optional[int], y: Optional[int]) -> Optional[int]:
|
|
|
299
326
|
|
|
300
327
|
|
|
301
328
|
@nullable_smallint_udf
|
|
302
|
-
def pandas_nullable_smallint_mult(x:
|
|
329
|
+
def pandas_nullable_smallint_mult(x: pdt.Series, y: pdt.Series) -> pdt.Series:
|
|
303
330
|
return x * y
|
|
304
331
|
|
|
305
332
|
|
|
306
333
|
@nullable_smallint_udf
|
|
307
|
-
def polars_nullable_smallint_mult(x:
|
|
334
|
+
def polars_nullable_smallint_mult(x: plt.Series, y: plt.Series) -> plt.Series:
|
|
308
335
|
return x * y
|
|
309
336
|
|
|
310
337
|
|
|
@@ -314,7 +341,7 @@ def numpy_nullable_smallint_mult(x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
|
|
314
341
|
|
|
315
342
|
|
|
316
343
|
@nullable_smallint_udf
|
|
317
|
-
def arrow_nullable_smallint_mult(x:
|
|
344
|
+
def arrow_nullable_smallint_mult(x: pat.Array, y: pat.Array) -> pat.Array:
|
|
318
345
|
import pyarrow.compute as pc
|
|
319
346
|
return pc.multiply(x, y)
|
|
320
347
|
|
|
@@ -338,12 +365,12 @@ def nullable_mediumint_mult(x: Optional[int], y: Optional[int]) -> Optional[int]
|
|
|
338
365
|
|
|
339
366
|
|
|
340
367
|
@nullable_mediumint_udf
|
|
341
|
-
def pandas_nullable_mediumint_mult(x:
|
|
368
|
+
def pandas_nullable_mediumint_mult(x: pdt.Series, y: pdt.Series) -> pdt.Series:
|
|
342
369
|
return x * y
|
|
343
370
|
|
|
344
371
|
|
|
345
372
|
@nullable_mediumint_udf
|
|
346
|
-
def polars_nullable_mediumint_mult(x:
|
|
373
|
+
def polars_nullable_mediumint_mult(x: plt.Series, y: plt.Series) -> plt.Series:
|
|
347
374
|
return x * y
|
|
348
375
|
|
|
349
376
|
|
|
@@ -353,7 +380,7 @@ def numpy_nullable_mediumint_mult(x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
|
|
353
380
|
|
|
354
381
|
|
|
355
382
|
@nullable_mediumint_udf
|
|
356
|
-
def arrow_nullable_mediumint_mult(x:
|
|
383
|
+
def arrow_nullable_mediumint_mult(x: pat.Array, y: pat.Array) -> pat.Array:
|
|
357
384
|
import pyarrow.compute as pc
|
|
358
385
|
return pc.multiply(x, y)
|
|
359
386
|
|
|
@@ -377,12 +404,12 @@ def nullable_bigint_mult(x: Optional[int], y: Optional[int]) -> Optional[int]:
|
|
|
377
404
|
|
|
378
405
|
|
|
379
406
|
@nullable_bigint_udf
|
|
380
|
-
def pandas_nullable_bigint_mult(x:
|
|
407
|
+
def pandas_nullable_bigint_mult(x: pdt.Series, y: pdt.Series) -> pdt.Series:
|
|
381
408
|
return x * y
|
|
382
409
|
|
|
383
410
|
|
|
384
411
|
@nullable_bigint_udf
|
|
385
|
-
def polars_nullable_bigint_mult(x:
|
|
412
|
+
def polars_nullable_bigint_mult(x: plt.Series, y: plt.Series) -> plt.Series:
|
|
386
413
|
return x * y
|
|
387
414
|
|
|
388
415
|
|
|
@@ -392,7 +419,7 @@ def numpy_nullable_bigint_mult(x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
|
|
392
419
|
|
|
393
420
|
|
|
394
421
|
@nullable_bigint_udf
|
|
395
|
-
def arrow_nullable_bigint_mult(x:
|
|
422
|
+
def arrow_nullable_bigint_mult(x: pat.Array, y: pat.Array) -> pat.Array:
|
|
396
423
|
import pyarrow.compute as pc
|
|
397
424
|
return pc.multiply(x, y)
|
|
398
425
|
|
|
@@ -410,7 +437,7 @@ def string_mult(x: str, times: int) -> str:
|
|
|
410
437
|
|
|
411
438
|
|
|
412
439
|
@udf(args=[TEXT(nullable=False), BIGINT(nullable=False)], returns=TEXT(nullable=False))
|
|
413
|
-
def pandas_string_mult(x:
|
|
440
|
+
def pandas_string_mult(x: pdt.Series, times: pdt.Series) -> pdt.Series:
|
|
414
441
|
return x * times
|
|
415
442
|
|
|
416
443
|
|
|
@@ -447,8 +474,8 @@ def nullable_string_mult(x: Optional[str], times: Optional[int]) -> Optional[str
|
|
|
447
474
|
returns=TINYINT(nullable=True),
|
|
448
475
|
)
|
|
449
476
|
def pandas_nullable_tinyint_mult_with_masks(
|
|
450
|
-
x: Masked[
|
|
451
|
-
) -> Masked[
|
|
477
|
+
x: Masked[pdt.Series], y: Masked[pdt.Series],
|
|
478
|
+
) -> Masked[pdt.Series]:
|
|
452
479
|
x_data, x_nulls = x
|
|
453
480
|
y_data, y_nulls = y
|
|
454
481
|
return Masked(x_data * y_data, x_nulls | y_nulls)
|
|
@@ -468,8 +495,8 @@ def numpy_nullable_tinyint_mult_with_masks(
|
|
|
468
495
|
returns=TINYINT(nullable=True),
|
|
469
496
|
)
|
|
470
497
|
def polars_nullable_tinyint_mult_with_masks(
|
|
471
|
-
x: Masked[
|
|
472
|
-
) -> Masked[
|
|
498
|
+
x: Masked[plt.Series], y: Masked[plt.Series],
|
|
499
|
+
) -> Masked[plt.Series]:
|
|
473
500
|
x_data, x_nulls = x
|
|
474
501
|
y_data, y_nulls = y
|
|
475
502
|
return Masked(x_data * y_data, x_nulls | y_nulls)
|
|
@@ -480,8 +507,8 @@ def polars_nullable_tinyint_mult_with_masks(
|
|
|
480
507
|
returns=TINYINT(nullable=True),
|
|
481
508
|
)
|
|
482
509
|
def arrow_nullable_tinyint_mult_with_masks(
|
|
483
|
-
x: Masked[
|
|
484
|
-
) -> Masked[
|
|
510
|
+
x: Masked[pat.Array], y: Masked[pat.Array],
|
|
511
|
+
) -> Masked[pat.Array]:
|
|
485
512
|
import pyarrow.compute as pc
|
|
486
513
|
x_data, x_nulls = x
|
|
487
514
|
y_data, y_nulls = y
|
|
@@ -489,7 +516,7 @@ def arrow_nullable_tinyint_mult_with_masks(
|
|
|
489
516
|
|
|
490
517
|
|
|
491
518
|
@udf(returns=[TEXT(nullable=False, name='res')])
|
|
492
|
-
def numpy_fixed_strings() -> Table[npt.
|
|
519
|
+
def numpy_fixed_strings() -> Table[npt.StrArray]:
|
|
493
520
|
out = np.array(
|
|
494
521
|
[
|
|
495
522
|
'hello',
|
|
@@ -502,7 +529,7 @@ def numpy_fixed_strings() -> Table[npt.NDArray[np.str_]]:
|
|
|
502
529
|
|
|
503
530
|
|
|
504
531
|
@udf(returns=[TEXT(nullable=False, name='res'), TINYINT(nullable=False, name='res2')])
|
|
505
|
-
def numpy_fixed_strings_2() -> Table[npt.
|
|
532
|
+
def numpy_fixed_strings_2() -> Table[npt.StrArray, npt.Int8Array]:
|
|
506
533
|
out = np.array(
|
|
507
534
|
[
|
|
508
535
|
'hello',
|
|
@@ -515,7 +542,7 @@ def numpy_fixed_strings_2() -> Table[npt.NDArray[np.str_], npt.NDArray[np.int8]]
|
|
|
515
542
|
|
|
516
543
|
|
|
517
544
|
@udf(returns=[BLOB(nullable=False, name='res')])
|
|
518
|
-
def numpy_fixed_binary() -> Table[npt.
|
|
545
|
+
def numpy_fixed_binary() -> Table[npt.BytesArray]:
|
|
519
546
|
out = np.array(
|
|
520
547
|
[
|
|
521
548
|
'hello'.encode('utf8'),
|
|
@@ -537,6 +564,11 @@ def table_function(n: int) -> Table[List[int]]:
|
|
|
537
564
|
return Table([10] * n)
|
|
538
565
|
|
|
539
566
|
|
|
567
|
+
@udf
|
|
568
|
+
async def async_table_function(n: int) -> Table[List[int]]:
|
|
569
|
+
return Table([10] * n)
|
|
570
|
+
|
|
571
|
+
|
|
540
572
|
@udf(
|
|
541
573
|
returns=[
|
|
542
574
|
dt.INT(name='c_int', nullable=False),
|
|
@@ -561,8 +593,8 @@ def table_function_struct(n: int) -> Table[List[MyTable]]:
|
|
|
561
593
|
|
|
562
594
|
@udf
|
|
563
595
|
def vec_function(
|
|
564
|
-
x: npt.
|
|
565
|
-
) -> npt.
|
|
596
|
+
x: npt.Float64Array, y: npt.Float64Array,
|
|
597
|
+
) -> npt.Float64Array:
|
|
566
598
|
return x * y
|
|
567
599
|
|
|
568
600
|
|
|
@@ -577,8 +609,8 @@ class VecOutputs(typing.NamedTuple):
|
|
|
577
609
|
|
|
578
610
|
@udf(args=VecInputs, returns=VecOutputs)
|
|
579
611
|
def vec_function_ints(
|
|
580
|
-
x: npt.
|
|
581
|
-
) -> npt.
|
|
612
|
+
x: npt.IntArray, y: npt.IntArray,
|
|
613
|
+
) -> npt.IntArray:
|
|
582
614
|
return x * y
|
|
583
615
|
|
|
584
616
|
|
|
@@ -589,9 +621,16 @@ class DFOutputs(typing.NamedTuple):
|
|
|
589
621
|
|
|
590
622
|
@udf(args=VecInputs, returns=DFOutputs)
|
|
591
623
|
def vec_function_df(
|
|
592
|
-
x: npt.
|
|
593
|
-
) -> Table[
|
|
594
|
-
return
|
|
624
|
+
x: npt.IntArray, y: npt.IntArray,
|
|
625
|
+
) -> Table[pdt.DataFrame]:
|
|
626
|
+
return pdt.DataFrame(dict(res=[1, 2, 3], res2=[1.1, 2.2, 3.3]))
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
@udf(args=VecInputs, returns=DFOutputs)
|
|
630
|
+
async def async_vec_function_df(
|
|
631
|
+
x: npt.IntArray, y: npt.IntArray,
|
|
632
|
+
) -> Table[pdt.DataFrame]:
|
|
633
|
+
return pdt.DataFrame(dict(res=[1, 2, 3], res2=[1.1, 2.2, 3.3]))
|
|
595
634
|
|
|
596
635
|
|
|
597
636
|
class MaskOutputs(typing.NamedTuple):
|
|
@@ -600,8 +639,8 @@ class MaskOutputs(typing.NamedTuple):
|
|
|
600
639
|
|
|
601
640
|
@udf(args=VecInputs, returns=MaskOutputs)
|
|
602
641
|
def vec_function_ints_masked(
|
|
603
|
-
x: Masked[npt.
|
|
604
|
-
) -> Table[Masked[npt.
|
|
642
|
+
x: Masked[npt.IntArray], y: Masked[npt.IntArray],
|
|
643
|
+
) -> Table[Masked[npt.IntArray]]:
|
|
605
644
|
x_data, x_nulls = x
|
|
606
645
|
y_data, y_nulls = y
|
|
607
646
|
return Table(Masked(x_data * y_data, x_nulls | y_nulls))
|
|
@@ -614,8 +653,8 @@ class MaskOutputs2(typing.NamedTuple):
|
|
|
614
653
|
|
|
615
654
|
@udf(args=VecInputs, returns=MaskOutputs2)
|
|
616
655
|
def vec_function_ints_masked2(
|
|
617
|
-
x: Masked[npt.
|
|
618
|
-
) -> Table[Masked[npt.
|
|
656
|
+
x: Masked[npt.IntArray], y: Masked[npt.IntArray],
|
|
657
|
+
) -> Table[Masked[npt.IntArray], Masked[npt.IntArray]]:
|
|
619
658
|
x_data, x_nulls = x
|
|
620
659
|
y_data, y_nulls = y
|
|
621
660
|
return Table(
|
singlestoredb/tests/test.sql
CHANGED
|
@@ -14,6 +14,28 @@ INSERT INTO data SET id='e', name='elephants', value=0;
|
|
|
14
14
|
|
|
15
15
|
COMMIT;
|
|
16
16
|
|
|
17
|
+
CREATE ROWSTORE TABLE IF NOT EXISTS longer_data (
|
|
18
|
+
id VARCHAR(255) NOT NULL,
|
|
19
|
+
name VARCHAR(255) NOT NULL,
|
|
20
|
+
value BIGINT NOT NULL,
|
|
21
|
+
PRIMARY KEY (id) USING HASH
|
|
22
|
+
) DEFAULT CHARSET = utf8 COLLATE = utf8_unicode_ci;
|
|
23
|
+
|
|
24
|
+
INSERT INTO longer_data SET id='a', name='antelopes', value=2;
|
|
25
|
+
INSERT INTO longer_data SET id='b', name='bears', value=2;
|
|
26
|
+
INSERT INTO longer_data SET id='c', name='cats', value=5;
|
|
27
|
+
INSERT INTO longer_data SET id='d', name='dogs', value=4;
|
|
28
|
+
INSERT INTO longer_data SET id='e', name='elephants', value=0;
|
|
29
|
+
INSERT INTO longer_data SET id='f', name='ferrets', value=2;
|
|
30
|
+
INSERT INTO longer_data SET id='g', name='gorillas', value=4;
|
|
31
|
+
INSERT INTO longer_data SET id='h', name='horses', value=6;
|
|
32
|
+
INSERT INTO longer_data SET id='i', name='iguanas', value=2;
|
|
33
|
+
INSERT INTO longer_data SET id='j', name='jaguars', value=0;
|
|
34
|
+
INSERT INTO longer_data SET id='k', name='kiwis', value=0;
|
|
35
|
+
INSERT INTO longer_data SET id='l', name='leopards', value=1;
|
|
36
|
+
|
|
37
|
+
COMMIT;
|
|
38
|
+
|
|
17
39
|
CREATE ROWSTORE TABLE IF NOT EXISTS data_with_nulls (
|
|
18
40
|
id VARCHAR(255) NOT NULL,
|
|
19
41
|
name VARCHAR(255),
|