singlestoredb 1.16.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.
- singlestoredb/__init__.py +75 -0
- singlestoredb/ai/__init__.py +2 -0
- singlestoredb/ai/chat.py +139 -0
- singlestoredb/ai/embeddings.py +128 -0
- singlestoredb/alchemy/__init__.py +90 -0
- singlestoredb/apps/__init__.py +3 -0
- singlestoredb/apps/_cloud_functions.py +90 -0
- singlestoredb/apps/_config.py +72 -0
- singlestoredb/apps/_connection_info.py +18 -0
- singlestoredb/apps/_dashboards.py +47 -0
- singlestoredb/apps/_process.py +32 -0
- singlestoredb/apps/_python_udfs.py +100 -0
- singlestoredb/apps/_stdout_supress.py +30 -0
- singlestoredb/apps/_uvicorn_util.py +36 -0
- singlestoredb/auth.py +245 -0
- singlestoredb/config.py +484 -0
- singlestoredb/connection.py +1487 -0
- singlestoredb/converters.py +950 -0
- singlestoredb/docstring/__init__.py +33 -0
- singlestoredb/docstring/attrdoc.py +126 -0
- singlestoredb/docstring/common.py +230 -0
- singlestoredb/docstring/epydoc.py +267 -0
- singlestoredb/docstring/google.py +412 -0
- singlestoredb/docstring/numpydoc.py +562 -0
- singlestoredb/docstring/parser.py +100 -0
- singlestoredb/docstring/py.typed +1 -0
- singlestoredb/docstring/rest.py +256 -0
- singlestoredb/docstring/tests/__init__.py +1 -0
- singlestoredb/docstring/tests/_pydoctor.py +21 -0
- singlestoredb/docstring/tests/test_epydoc.py +729 -0
- singlestoredb/docstring/tests/test_google.py +1007 -0
- singlestoredb/docstring/tests/test_numpydoc.py +1100 -0
- singlestoredb/docstring/tests/test_parse_from_object.py +109 -0
- singlestoredb/docstring/tests/test_parser.py +248 -0
- singlestoredb/docstring/tests/test_rest.py +547 -0
- singlestoredb/docstring/tests/test_util.py +70 -0
- singlestoredb/docstring/util.py +141 -0
- singlestoredb/exceptions.py +120 -0
- singlestoredb/functions/__init__.py +16 -0
- singlestoredb/functions/decorator.py +201 -0
- singlestoredb/functions/dtypes.py +1793 -0
- singlestoredb/functions/ext/__init__.py +1 -0
- singlestoredb/functions/ext/arrow.py +375 -0
- singlestoredb/functions/ext/asgi.py +2133 -0
- singlestoredb/functions/ext/json.py +420 -0
- singlestoredb/functions/ext/mmap.py +413 -0
- singlestoredb/functions/ext/rowdat_1.py +724 -0
- singlestoredb/functions/ext/timer.py +89 -0
- singlestoredb/functions/ext/utils.py +218 -0
- singlestoredb/functions/signature.py +1578 -0
- singlestoredb/functions/typing/__init__.py +41 -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/functions/utils.py +421 -0
- singlestoredb/fusion/__init__.py +11 -0
- singlestoredb/fusion/graphql.py +213 -0
- singlestoredb/fusion/handler.py +916 -0
- singlestoredb/fusion/handlers/__init__.py +0 -0
- singlestoredb/fusion/handlers/export.py +525 -0
- singlestoredb/fusion/handlers/files.py +690 -0
- singlestoredb/fusion/handlers/job.py +660 -0
- singlestoredb/fusion/handlers/models.py +250 -0
- singlestoredb/fusion/handlers/stage.py +502 -0
- singlestoredb/fusion/handlers/utils.py +324 -0
- singlestoredb/fusion/handlers/workspace.py +956 -0
- singlestoredb/fusion/registry.py +249 -0
- singlestoredb/fusion/result.py +399 -0
- singlestoredb/http/__init__.py +27 -0
- singlestoredb/http/connection.py +1267 -0
- singlestoredb/magics/__init__.py +34 -0
- singlestoredb/magics/run_personal.py +137 -0
- singlestoredb/magics/run_shared.py +134 -0
- singlestoredb/management/__init__.py +9 -0
- singlestoredb/management/billing_usage.py +148 -0
- singlestoredb/management/cluster.py +462 -0
- singlestoredb/management/export.py +295 -0
- singlestoredb/management/files.py +1102 -0
- singlestoredb/management/inference_api.py +105 -0
- singlestoredb/management/job.py +887 -0
- singlestoredb/management/manager.py +373 -0
- singlestoredb/management/organization.py +226 -0
- singlestoredb/management/region.py +169 -0
- singlestoredb/management/utils.py +423 -0
- singlestoredb/management/workspace.py +1927 -0
- singlestoredb/mysql/__init__.py +177 -0
- singlestoredb/mysql/_auth.py +298 -0
- singlestoredb/mysql/charset.py +214 -0
- singlestoredb/mysql/connection.py +2032 -0
- singlestoredb/mysql/constants/CLIENT.py +38 -0
- singlestoredb/mysql/constants/COMMAND.py +32 -0
- singlestoredb/mysql/constants/CR.py +78 -0
- singlestoredb/mysql/constants/ER.py +474 -0
- singlestoredb/mysql/constants/EXTENDED_TYPE.py +3 -0
- singlestoredb/mysql/constants/FIELD_TYPE.py +48 -0
- singlestoredb/mysql/constants/FLAG.py +15 -0
- singlestoredb/mysql/constants/SERVER_STATUS.py +10 -0
- singlestoredb/mysql/constants/VECTOR_TYPE.py +6 -0
- singlestoredb/mysql/constants/__init__.py +0 -0
- singlestoredb/mysql/converters.py +271 -0
- singlestoredb/mysql/cursors.py +896 -0
- singlestoredb/mysql/err.py +92 -0
- singlestoredb/mysql/optionfile.py +20 -0
- singlestoredb/mysql/protocol.py +450 -0
- singlestoredb/mysql/tests/__init__.py +19 -0
- singlestoredb/mysql/tests/base.py +126 -0
- singlestoredb/mysql/tests/conftest.py +37 -0
- singlestoredb/mysql/tests/test_DictCursor.py +132 -0
- singlestoredb/mysql/tests/test_SSCursor.py +141 -0
- singlestoredb/mysql/tests/test_basic.py +452 -0
- singlestoredb/mysql/tests/test_connection.py +851 -0
- singlestoredb/mysql/tests/test_converters.py +58 -0
- singlestoredb/mysql/tests/test_cursor.py +141 -0
- singlestoredb/mysql/tests/test_err.py +16 -0
- singlestoredb/mysql/tests/test_issues.py +514 -0
- singlestoredb/mysql/tests/test_load_local.py +75 -0
- singlestoredb/mysql/tests/test_nextset.py +88 -0
- singlestoredb/mysql/tests/test_optionfile.py +27 -0
- singlestoredb/mysql/tests/thirdparty/__init__.py +6 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/__init__.py +9 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/capabilities.py +323 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/dbapi20.py +865 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py +110 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py +224 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py +101 -0
- singlestoredb/mysql/times.py +23 -0
- singlestoredb/notebook/__init__.py +16 -0
- singlestoredb/notebook/_objects.py +213 -0
- singlestoredb/notebook/_portal.py +352 -0
- singlestoredb/py.typed +0 -0
- singlestoredb/pytest.py +352 -0
- singlestoredb/server/__init__.py +0 -0
- singlestoredb/server/docker.py +452 -0
- singlestoredb/server/free_tier.py +267 -0
- singlestoredb/tests/__init__.py +0 -0
- singlestoredb/tests/alltypes.sql +307 -0
- singlestoredb/tests/alltypes_no_nulls.sql +208 -0
- singlestoredb/tests/empty.sql +0 -0
- singlestoredb/tests/ext_funcs/__init__.py +702 -0
- singlestoredb/tests/local_infile.csv +3 -0
- singlestoredb/tests/test.ipynb +18 -0
- singlestoredb/tests/test.sql +680 -0
- singlestoredb/tests/test2.ipynb +18 -0
- singlestoredb/tests/test2.sql +1 -0
- singlestoredb/tests/test_basics.py +1332 -0
- singlestoredb/tests/test_config.py +318 -0
- singlestoredb/tests/test_connection.py +3103 -0
- singlestoredb/tests/test_dbapi.py +27 -0
- singlestoredb/tests/test_exceptions.py +45 -0
- singlestoredb/tests/test_ext_func.py +1472 -0
- singlestoredb/tests/test_ext_func_data.py +1101 -0
- singlestoredb/tests/test_fusion.py +1527 -0
- singlestoredb/tests/test_http.py +288 -0
- singlestoredb/tests/test_management.py +1599 -0
- singlestoredb/tests/test_plugin.py +33 -0
- singlestoredb/tests/test_results.py +171 -0
- singlestoredb/tests/test_types.py +132 -0
- singlestoredb/tests/test_udf.py +737 -0
- singlestoredb/tests/test_udf_returns.py +459 -0
- singlestoredb/tests/test_vectorstore.py +51 -0
- singlestoredb/tests/test_xdict.py +333 -0
- singlestoredb/tests/utils.py +141 -0
- singlestoredb/types.py +373 -0
- singlestoredb/utils/__init__.py +0 -0
- singlestoredb/utils/config.py +950 -0
- singlestoredb/utils/convert_rows.py +69 -0
- singlestoredb/utils/debug.py +13 -0
- singlestoredb/utils/dtypes.py +205 -0
- singlestoredb/utils/events.py +65 -0
- singlestoredb/utils/mogrify.py +151 -0
- singlestoredb/utils/results.py +585 -0
- singlestoredb/utils/xdict.py +425 -0
- singlestoredb/vectorstore.py +192 -0
- singlestoredb/warnings.py +5 -0
- singlestoredb-1.16.1.dist-info/METADATA +165 -0
- singlestoredb-1.16.1.dist-info/RECORD +183 -0
- singlestoredb-1.16.1.dist-info/WHEEL +5 -0
- singlestoredb-1.16.1.dist-info/entry_points.txt +2 -0
- singlestoredb-1.16.1.dist-info/licenses/LICENSE +201 -0
- singlestoredb-1.16.1.dist-info/top_level.txt +3 -0
- sqlx/__init__.py +4 -0
- sqlx/magic.py +113 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
# mypy: disable-error-code="type-arg"
|
|
2
|
+
# from __future__ import annotations
|
|
3
|
+
import unittest
|
|
4
|
+
from typing import Any
|
|
5
|
+
from typing import Callable
|
|
6
|
+
from typing import List
|
|
7
|
+
from typing import NamedTuple
|
|
8
|
+
from typing import Optional
|
|
9
|
+
from typing import TypedDict
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
import numpy.typing as npt
|
|
13
|
+
import pandas as pd
|
|
14
|
+
import polars as pl
|
|
15
|
+
import pyarrow as pa
|
|
16
|
+
from pydantic import BaseModel
|
|
17
|
+
|
|
18
|
+
from singlestoredb.functions import Table
|
|
19
|
+
from singlestoredb.functions import udf
|
|
20
|
+
from singlestoredb.functions.signature import get_signature
|
|
21
|
+
from singlestoredb.functions.signature import signature_to_sql
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def to_sql(func: Callable[..., Any]) -> str:
|
|
25
|
+
"""Convert a function signature to SQL."""
|
|
26
|
+
out = signature_to_sql(get_signature(func))
|
|
27
|
+
return out.split('EXTERNAL FUNCTION ')[1].split('AS REMOTE')[0].strip()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Parameters(NamedTuple):
|
|
31
|
+
x: Optional[str] = ''
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class UDFTuple(NamedTuple):
|
|
35
|
+
value: str
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class TVFTuple(NamedTuple):
|
|
39
|
+
idx: int
|
|
40
|
+
value: Optional[str]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class TVFDict(TypedDict):
|
|
44
|
+
idx: int
|
|
45
|
+
value: Optional[str]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class TVFBaseModel(BaseModel):
|
|
49
|
+
idx: int
|
|
50
|
+
value: Optional[str]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class UDFResultsTest(unittest.TestCase):
|
|
54
|
+
|
|
55
|
+
def test_udf_returns(self) -> None:
|
|
56
|
+
# Plain UDF
|
|
57
|
+
@udf
|
|
58
|
+
def foo_a(x: str) -> str:
|
|
59
|
+
return f'0: {x}'
|
|
60
|
+
|
|
61
|
+
foo_a_out = foo_a('cat')
|
|
62
|
+
|
|
63
|
+
assert type(foo_a_out) is str
|
|
64
|
+
assert foo_a_out == '0: cat'
|
|
65
|
+
assert to_sql(foo_a) == '`foo_a`(`x` TEXT NOT NULL) RETURNS TEXT NOT NULL'
|
|
66
|
+
|
|
67
|
+
# Vectorized UDF using lists
|
|
68
|
+
@udf
|
|
69
|
+
def foo_b(x: List[str]) -> List[str]:
|
|
70
|
+
return [f'{i}: {y}' for i, y in enumerate(x)]
|
|
71
|
+
|
|
72
|
+
foo_b_out = foo_b(['cat', 'dog', 'monkey'])
|
|
73
|
+
|
|
74
|
+
assert type(foo_b_out) is list
|
|
75
|
+
assert foo_b_out == ['0: cat', '1: dog', '2: monkey']
|
|
76
|
+
assert to_sql(foo_b) == '`foo_b`(`x` TEXT NOT NULL) RETURNS TEXT NOT NULL'
|
|
77
|
+
|
|
78
|
+
# Illegal return type for UDF
|
|
79
|
+
@udf
|
|
80
|
+
def foo_c(x: List[str]) -> List[UDFTuple]:
|
|
81
|
+
return [UDFTuple(value='invalid')]
|
|
82
|
+
|
|
83
|
+
# Vectorized UDF using pandas Series
|
|
84
|
+
@udf(args=Parameters, returns=UDFTuple)
|
|
85
|
+
def foo_d(x: pd.Series) -> pd.Series:
|
|
86
|
+
return pd.Series([f'{i}: {y}' for i, y in enumerate(x)])
|
|
87
|
+
|
|
88
|
+
foo_d_out = foo_d(pd.Series(['cat', 'dog', 'monkey']))
|
|
89
|
+
|
|
90
|
+
assert type(foo_d_out) is pd.Series
|
|
91
|
+
assert list(foo_d_out) == ['0: cat', '1: dog', '2: monkey']
|
|
92
|
+
assert to_sql(foo_d) == "`foo_d`(`x` TEXT NULL DEFAULT '') RETURNS TEXT NOT NULL"
|
|
93
|
+
|
|
94
|
+
# Vectorized UDF using polars Series
|
|
95
|
+
@udf(args=Parameters, returns=UDFTuple)
|
|
96
|
+
def foo_e(x: pl.Series) -> pl.Series:
|
|
97
|
+
return pl.Series([f'{i}: {y}' for i, y in enumerate(x)])
|
|
98
|
+
|
|
99
|
+
foo_e_out = foo_e(pl.Series(['cat', 'dog', 'monkey']))
|
|
100
|
+
|
|
101
|
+
assert type(foo_e_out) is pl.Series
|
|
102
|
+
assert list(foo_e_out) == ['0: cat', '1: dog', '2: monkey']
|
|
103
|
+
assert to_sql(foo_e) == "`foo_e`(`x` TEXT NULL DEFAULT '') RETURNS TEXT NOT NULL"
|
|
104
|
+
|
|
105
|
+
# Vectorized UDF using numpy arrays
|
|
106
|
+
@udf(args=Parameters, returns=UDFTuple)
|
|
107
|
+
def foo_f(x: np.ndarray) -> np.ndarray:
|
|
108
|
+
return np.array([f'{i}: {y}' for i, y in enumerate(x)])
|
|
109
|
+
|
|
110
|
+
foo_f_out = foo_f(np.array(['cat', 'dog', 'monkey']))
|
|
111
|
+
|
|
112
|
+
assert type(foo_f_out) is np.ndarray
|
|
113
|
+
assert list(foo_f_out) == ['0: cat', '1: dog', '2: monkey']
|
|
114
|
+
assert to_sql(foo_f) == "`foo_f`(`x` TEXT NULL DEFAULT '') RETURNS TEXT NOT NULL"
|
|
115
|
+
|
|
116
|
+
# Vectorized UDF using typed numpy arrays
|
|
117
|
+
@udf
|
|
118
|
+
def foo_g(x: npt.NDArray[np.str_]) -> npt.NDArray[np.str_]:
|
|
119
|
+
return np.array([f'{i}: {y}' for i, y in enumerate(x)])
|
|
120
|
+
|
|
121
|
+
foo_g_out = foo_g(np.array(['cat', 'dog', 'monkey']))
|
|
122
|
+
|
|
123
|
+
assert type(foo_g_out) is np.ndarray
|
|
124
|
+
assert list(foo_g_out) == ['0: cat', '1: dog', '2: monkey']
|
|
125
|
+
assert to_sql(foo_g) == '`foo_g`(`x` TEXT NOT NULL) RETURNS TEXT NOT NULL'
|
|
126
|
+
|
|
127
|
+
# Plain TVF using one list
|
|
128
|
+
@udf
|
|
129
|
+
def foo_h_(x: str) -> Table[List[str]]:
|
|
130
|
+
return Table([x] * 3)
|
|
131
|
+
|
|
132
|
+
foo_h__out = foo_h_('cat')
|
|
133
|
+
|
|
134
|
+
assert type(foo_h__out) is Table
|
|
135
|
+
assert foo_h__out == Table(['cat', 'cat', 'cat'])
|
|
136
|
+
|
|
137
|
+
assert to_sql(foo_h_) == \
|
|
138
|
+
'`foo_h_`(`x` TEXT NOT NULL) RETURNS TABLE(`a` TEXT NOT NULL)'
|
|
139
|
+
|
|
140
|
+
# Plain TVF using multiple lists -- Illegal!
|
|
141
|
+
@udf
|
|
142
|
+
def foo_h(x: str) -> Table[List[int], List[str]]:
|
|
143
|
+
return Table(list(range(3)), [x] * 3)
|
|
144
|
+
|
|
145
|
+
foo_h_out = foo_h('cat')
|
|
146
|
+
|
|
147
|
+
assert type(foo_h_out) is Table
|
|
148
|
+
assert foo_h_out == Table([0, 1, 2], ['cat', 'cat', 'cat'])
|
|
149
|
+
|
|
150
|
+
with self.assertRaises(TypeError):
|
|
151
|
+
to_sql(foo_h)
|
|
152
|
+
|
|
153
|
+
# Plain TVF using lists of NamedTuples
|
|
154
|
+
@udf
|
|
155
|
+
def foo_i(x: str) -> Table[List[TVFTuple]]:
|
|
156
|
+
return Table([
|
|
157
|
+
TVFTuple(idx=0, value=x),
|
|
158
|
+
TVFTuple(idx=1, value=x),
|
|
159
|
+
TVFTuple(idx=2, value=x),
|
|
160
|
+
])
|
|
161
|
+
|
|
162
|
+
foo_i_out = foo_i('cat')
|
|
163
|
+
|
|
164
|
+
assert type(foo_i_out) is Table
|
|
165
|
+
assert foo_i_out == Table([
|
|
166
|
+
TVFTuple(idx=0, value='cat'),
|
|
167
|
+
TVFTuple(idx=1, value='cat'),
|
|
168
|
+
TVFTuple(idx=2, value='cat'),
|
|
169
|
+
])
|
|
170
|
+
assert to_sql(foo_i) == (
|
|
171
|
+
'`foo_i`(`x` TEXT NOT NULL) '
|
|
172
|
+
'RETURNS TABLE(`idx` BIGINT NOT NULL, `value` TEXT NULL)'
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# Plain TVF using lists of TypedDicts
|
|
176
|
+
@udf
|
|
177
|
+
def foo_j(x: str) -> Table[List[TVFDict]]:
|
|
178
|
+
return Table([
|
|
179
|
+
dict(idx=0, value=x),
|
|
180
|
+
dict(idx=1, value=x),
|
|
181
|
+
dict(idx=2, value=x),
|
|
182
|
+
])
|
|
183
|
+
|
|
184
|
+
foo_j_out = foo_j('cat')
|
|
185
|
+
|
|
186
|
+
assert type(foo_j_out) is Table
|
|
187
|
+
assert foo_j_out == Table([
|
|
188
|
+
dict(idx=0, value='cat'),
|
|
189
|
+
dict(idx=1, value='cat'),
|
|
190
|
+
dict(idx=2, value='cat'),
|
|
191
|
+
])
|
|
192
|
+
assert to_sql(foo_j) == (
|
|
193
|
+
'`foo_j`(`x` TEXT NOT NULL) '
|
|
194
|
+
'RETURNS TABLE(`idx` BIGINT NOT NULL, `value` TEXT NULL)'
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
# Plain TVF using lists of pydantic BaseModels
|
|
198
|
+
@udf
|
|
199
|
+
def foo_k(x: str) -> Table[List[TVFBaseModel]]:
|
|
200
|
+
return Table([
|
|
201
|
+
TVFBaseModel(idx=0, value=x),
|
|
202
|
+
TVFBaseModel(idx=1, value=x),
|
|
203
|
+
TVFBaseModel(idx=2, value=x),
|
|
204
|
+
])
|
|
205
|
+
|
|
206
|
+
foo_k_out = foo_k('cat')
|
|
207
|
+
|
|
208
|
+
assert type(foo_k_out) is Table
|
|
209
|
+
assert foo_k_out == Table([
|
|
210
|
+
TVFBaseModel(idx=0, value='cat'),
|
|
211
|
+
TVFBaseModel(idx=1, value='cat'),
|
|
212
|
+
TVFBaseModel(idx=2, value='cat'),
|
|
213
|
+
])
|
|
214
|
+
assert to_sql(foo_k) == (
|
|
215
|
+
'`foo_k`(`x` TEXT NOT NULL) '
|
|
216
|
+
'RETURNS TABLE(`idx` BIGINT NOT NULL, `value` TEXT NULL)'
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
# Plain TVF using pandas Series
|
|
220
|
+
@udf(returns=TVFTuple)
|
|
221
|
+
def foo_l(x: str) -> Table[pd.Series, pd.Series]:
|
|
222
|
+
return Table(pd.Series(range(3)), pd.Series([x] * 3))
|
|
223
|
+
|
|
224
|
+
foo_l_out = foo_l('cat')
|
|
225
|
+
|
|
226
|
+
assert type(foo_l_out) is Table
|
|
227
|
+
assert len(foo_l_out) == 2
|
|
228
|
+
assert type(foo_l_out[0]) is pd.Series
|
|
229
|
+
assert list(foo_l_out[0]) == [0, 1, 2]
|
|
230
|
+
assert type(foo_l_out[1]) is pd.Series
|
|
231
|
+
assert list(foo_l_out[1]) == ['cat', 'cat', 'cat']
|
|
232
|
+
assert to_sql(foo_l) == (
|
|
233
|
+
'`foo_l`(`x` TEXT NOT NULL) '
|
|
234
|
+
'RETURNS TABLE(`idx` BIGINT NOT NULL, `value` TEXT NULL)'
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
# Plain TVF using polars Series
|
|
238
|
+
@udf(returns=TVFTuple)
|
|
239
|
+
def foo_m(x: str) -> Table[pl.Series, pl.Series]:
|
|
240
|
+
return Table(pl.Series(range(3)), pl.Series([x] * 3))
|
|
241
|
+
|
|
242
|
+
foo_m_out = foo_m('cat')
|
|
243
|
+
|
|
244
|
+
assert type(foo_m_out) is Table
|
|
245
|
+
assert len(foo_m_out) == 2
|
|
246
|
+
assert type(foo_m_out[0]) is pl.Series
|
|
247
|
+
assert list(foo_m_out[0]) == [0, 1, 2]
|
|
248
|
+
assert type(foo_m_out[1]) is pl.Series
|
|
249
|
+
assert list(foo_m_out[1]) == ['cat', 'cat', 'cat']
|
|
250
|
+
assert to_sql(foo_m) == (
|
|
251
|
+
'`foo_m`(`x` TEXT NOT NULL) '
|
|
252
|
+
'RETURNS TABLE(`idx` BIGINT NOT NULL, `value` TEXT NULL)'
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# Plain TVF using pyarrow Array
|
|
256
|
+
@udf(returns=TVFTuple)
|
|
257
|
+
def foo_n(x: str) -> Table[pa.Array, pa.Array]:
|
|
258
|
+
return Table(pa.array(range(3)), pa.array([x] * 3))
|
|
259
|
+
|
|
260
|
+
foo_n_out = foo_n('cat')
|
|
261
|
+
|
|
262
|
+
assert type(foo_n_out) is Table
|
|
263
|
+
assert foo_n_out == Table(pa.array([0, 1, 2]), pa.array(['cat', 'cat', 'cat']))
|
|
264
|
+
assert to_sql(foo_n) == (
|
|
265
|
+
'`foo_n`(`x` TEXT NOT NULL) '
|
|
266
|
+
'RETURNS TABLE(`idx` BIGINT NOT NULL, `value` TEXT NULL)'
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
# Plain TVF using numpy arrays
|
|
270
|
+
@udf(returns=TVFTuple)
|
|
271
|
+
def foo_o(x: str) -> Table[np.ndarray, np.ndarray]:
|
|
272
|
+
return Table(np.array(range(3)), np.array([x] * 3))
|
|
273
|
+
|
|
274
|
+
foo_o_out = foo_o('cat')
|
|
275
|
+
|
|
276
|
+
assert type(foo_o_out) is Table
|
|
277
|
+
assert len(foo_o_out) == 2
|
|
278
|
+
assert type(foo_o_out[0]) is np.ndarray
|
|
279
|
+
assert list(foo_o_out[0]) == [0, 1, 2]
|
|
280
|
+
assert type(foo_o_out[1]) is np.ndarray
|
|
281
|
+
assert list(foo_o_out[1]) == ['cat', 'cat', 'cat']
|
|
282
|
+
assert to_sql(foo_o) == (
|
|
283
|
+
'`foo_o`(`x` TEXT NOT NULL) '
|
|
284
|
+
'RETURNS TABLE(`idx` BIGINT NOT NULL, `value` TEXT NULL)'
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
# Plain TVF using typed numpy arrays
|
|
288
|
+
@udf
|
|
289
|
+
def foo_p(x: str) -> Table[npt.NDArray[np.int_], npt.NDArray[np.str_]]:
|
|
290
|
+
return Table(np.array(range(3)), np.array([x] * 3))
|
|
291
|
+
|
|
292
|
+
foo_p_out = foo_p('cat')
|
|
293
|
+
|
|
294
|
+
assert type(foo_p_out) is Table
|
|
295
|
+
assert len(foo_p_out) == 2
|
|
296
|
+
assert type(foo_p_out[0]) is np.ndarray
|
|
297
|
+
assert list(foo_p_out[0]) == [0, 1, 2]
|
|
298
|
+
assert type(foo_p_out[1]) is np.ndarray
|
|
299
|
+
assert list(foo_p_out[1]) == ['cat', 'cat', 'cat']
|
|
300
|
+
assert to_sql(foo_p) == (
|
|
301
|
+
'`foo_p`(`x` TEXT NOT NULL) '
|
|
302
|
+
'RETURNS TABLE(`a` BIGINT NOT NULL, `b` TEXT NOT NULL)'
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
# Plain TVF using pandas DataFrame
|
|
306
|
+
@udf(returns=TVFTuple)
|
|
307
|
+
def foo_q(x: str) -> Table[pd.DataFrame]:
|
|
308
|
+
return Table(pd.DataFrame([[0, x], [1, x], [2, x]])) # columns???
|
|
309
|
+
|
|
310
|
+
foo_q_out = foo_q('cat')
|
|
311
|
+
|
|
312
|
+
assert type(foo_q_out) is Table
|
|
313
|
+
assert len(foo_q_out) == 1
|
|
314
|
+
assert list(foo_q_out[0].iloc[:, 0]) == [0, 1, 2]
|
|
315
|
+
assert list(foo_q_out[0].iloc[:, 1]) == ['cat', 'cat', 'cat']
|
|
316
|
+
assert to_sql(foo_q) == (
|
|
317
|
+
'`foo_q`(`x` TEXT NOT NULL) '
|
|
318
|
+
'RETURNS TABLE(`idx` BIGINT NOT NULL, `value` TEXT NULL)'
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
# Plain TVF using polars DataFrame
|
|
322
|
+
@udf(returns=TVFTuple)
|
|
323
|
+
def foo_r(x: str) -> Table[pl.DataFrame]:
|
|
324
|
+
return Table(pl.DataFrame([[0, 1, 2], [x] * 3])) # columns???
|
|
325
|
+
|
|
326
|
+
foo_r_out = foo_r('cat')
|
|
327
|
+
|
|
328
|
+
assert type(foo_r_out) is Table
|
|
329
|
+
assert len(foo_r_out) == 1
|
|
330
|
+
assert list(foo_r_out[0][:, 0]) == [0, 1, 2]
|
|
331
|
+
assert list(foo_r_out[0][:, 1]) == ['cat', 'cat', 'cat']
|
|
332
|
+
assert to_sql(foo_r) == (
|
|
333
|
+
'`foo_r`(`x` TEXT NOT NULL) '
|
|
334
|
+
'RETURNS TABLE(`idx` BIGINT NOT NULL, `value` TEXT NULL)'
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
# Plain TVF using pyarrow Table
|
|
338
|
+
@udf(returns=TVFTuple)
|
|
339
|
+
def foo_s(x: str) -> Table[pa.Table]:
|
|
340
|
+
return Table(
|
|
341
|
+
pa.Table.from_pylist([
|
|
342
|
+
dict(idx=0, value='cat'),
|
|
343
|
+
dict(idx=1, value='cat'),
|
|
344
|
+
dict(idx=2, value='cat'),
|
|
345
|
+
]),
|
|
346
|
+
) # columns???
|
|
347
|
+
|
|
348
|
+
foo_s_out = foo_s('cat')
|
|
349
|
+
|
|
350
|
+
assert type(foo_s_out) is Table
|
|
351
|
+
assert foo_s_out == Table(
|
|
352
|
+
pa.Table.from_pylist([
|
|
353
|
+
dict(idx=0, value='cat'),
|
|
354
|
+
dict(idx=1, value='cat'),
|
|
355
|
+
dict(idx=2, value='cat'),
|
|
356
|
+
]),
|
|
357
|
+
)
|
|
358
|
+
assert to_sql(foo_s) == (
|
|
359
|
+
'`foo_s`(`x` TEXT NOT NULL) '
|
|
360
|
+
'RETURNS TABLE(`idx` BIGINT NOT NULL, `value` TEXT NULL)'
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
# Vectorized TVF using lists -- Illegal!
|
|
364
|
+
@udf
|
|
365
|
+
def foo_t(x: List[str]) -> Table[List[int], List[str]]:
|
|
366
|
+
return Table(list(range(len(x))), x)
|
|
367
|
+
|
|
368
|
+
foo_t_out = foo_t(['cat', 'dog', 'monkey'])
|
|
369
|
+
|
|
370
|
+
assert type(foo_t_out) is Table
|
|
371
|
+
assert foo_t_out == Table([0, 1, 2], ['cat', 'dog', 'monkey'])
|
|
372
|
+
with self.assertRaises(TypeError):
|
|
373
|
+
to_sql(foo_t)
|
|
374
|
+
|
|
375
|
+
# Vectorized TVF using pandas Series
|
|
376
|
+
@udf(args=Parameters, returns=TVFTuple)
|
|
377
|
+
def foo_u(x: pd.Series) -> Table[pd.Series, pd.Series]:
|
|
378
|
+
return Table(pd.Series(range(len(x))), pd.Series(x))
|
|
379
|
+
|
|
380
|
+
foo_u_out = foo_u(pd.Series(['cat', 'dog', 'monkey']))
|
|
381
|
+
|
|
382
|
+
assert type(foo_u_out) is Table
|
|
383
|
+
assert len(foo_u_out) == 2
|
|
384
|
+
assert list(foo_u_out[0]) == [0, 1, 2]
|
|
385
|
+
assert list(foo_u_out[1]) == ['cat', 'dog', 'monkey']
|
|
386
|
+
assert to_sql(foo_u) == (
|
|
387
|
+
"`foo_u`(`x` TEXT NULL DEFAULT '') "
|
|
388
|
+
'RETURNS TABLE(`idx` BIGINT NOT NULL, `value` TEXT NULL)'
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
# Vectorized TVF using polars Series
|
|
392
|
+
@udf(args=Parameters, returns=TVFTuple)
|
|
393
|
+
def foo_v(x: pl.Series) -> Table[pl.Series, pl.Series]:
|
|
394
|
+
return Table(pl.Series(range(len(x))), pl.Series(x))
|
|
395
|
+
|
|
396
|
+
foo_v_out = foo_v(pl.Series(['cat', 'dog', 'monkey']))
|
|
397
|
+
|
|
398
|
+
assert type(foo_v_out) is Table
|
|
399
|
+
assert len(foo_v_out) == 2
|
|
400
|
+
assert list(foo_v_out[0]) == [0, 1, 2]
|
|
401
|
+
assert list(foo_v_out[1]) == ['cat', 'dog', 'monkey']
|
|
402
|
+
assert to_sql(foo_v) == (
|
|
403
|
+
"`foo_v`(`x` TEXT NULL DEFAULT '') "
|
|
404
|
+
'RETURNS TABLE(`idx` BIGINT NOT NULL, `value` TEXT NULL)'
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
# Vectorized TVF using pyarrow Array
|
|
408
|
+
@udf(args=Parameters, returns=TVFTuple)
|
|
409
|
+
def foo_w(x: pa.Array) -> Table[pa.Array, pa.Array]:
|
|
410
|
+
return Table(pa.array(range(len(x))), pa.array(x))
|
|
411
|
+
|
|
412
|
+
foo_w_out = foo_w(pa.array(['cat', 'dog', 'monkey']))
|
|
413
|
+
|
|
414
|
+
assert type(foo_w_out) is Table
|
|
415
|
+
assert foo_w_out == Table(
|
|
416
|
+
pa.array([0, 1, 2]), pa.array(['cat', 'dog', 'monkey']),
|
|
417
|
+
)
|
|
418
|
+
assert to_sql(foo_w) == (
|
|
419
|
+
"`foo_w`(`x` TEXT NULL DEFAULT '') "
|
|
420
|
+
'RETURNS TABLE(`idx` BIGINT NOT NULL, `value` TEXT NULL)'
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
# Vectorized TVF using numpy arrays
|
|
424
|
+
@udf(args=Parameters, returns=TVFTuple)
|
|
425
|
+
def foo_x(x: np.ndarray) -> Table[np.ndarray, np.ndarray]:
|
|
426
|
+
return Table(np.array(range(len(x))), np.array(x))
|
|
427
|
+
|
|
428
|
+
foo_x_out = foo_x(np.array(['cat', 'dog', 'monkey']))
|
|
429
|
+
|
|
430
|
+
assert type(foo_x_out) is Table
|
|
431
|
+
assert len(foo_x_out) == 2
|
|
432
|
+
assert list(foo_x_out[0]) == [0, 1, 2]
|
|
433
|
+
assert list(foo_x_out[1]) == ['cat', 'dog', 'monkey']
|
|
434
|
+
assert to_sql(foo_x) == (
|
|
435
|
+
"`foo_x`(`x` TEXT NULL DEFAULT '') "
|
|
436
|
+
'RETURNS TABLE(`idx` BIGINT NOT NULL, `value` TEXT NULL)'
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
# Vectorized TVF using typed numpy arrays
|
|
440
|
+
@udf
|
|
441
|
+
def foo_y(
|
|
442
|
+
x: npt.NDArray[np.str_],
|
|
443
|
+
) -> Table[npt.NDArray[np.int_], npt.NDArray[np.str_]]:
|
|
444
|
+
return Table(np.array(range(len(x))), np.array(x))
|
|
445
|
+
|
|
446
|
+
foo_y_out = foo_y(np.array(['cat', 'dog', 'monkey']))
|
|
447
|
+
|
|
448
|
+
assert type(foo_y_out) is Table
|
|
449
|
+
assert len(foo_y_out) == 2
|
|
450
|
+
assert list(foo_y_out[0]) == [0, 1, 2]
|
|
451
|
+
assert list(foo_y_out[1]) == ['cat', 'dog', 'monkey']
|
|
452
|
+
assert to_sql(foo_y) == (
|
|
453
|
+
'`foo_y`(`x` TEXT NOT NULL) '
|
|
454
|
+
'RETURNS TABLE(`a` BIGINT NOT NULL, `b` TEXT NOT NULL)'
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
if __name__ == '__main__':
|
|
459
|
+
unittest.main()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import unittest
|
|
3
|
+
|
|
4
|
+
from vectorstore import VectorDB
|
|
5
|
+
|
|
6
|
+
import singlestoredb as s2
|
|
7
|
+
from . import utils
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestVectorDB(unittest.TestCase):
|
|
11
|
+
|
|
12
|
+
driver = s2
|
|
13
|
+
|
|
14
|
+
dbname: str = ''
|
|
15
|
+
dbexisted: bool = False
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def setUpClass(cls) -> None:
|
|
19
|
+
sql_file = os.path.join(os.path.dirname(__file__), 'empty.sql')
|
|
20
|
+
cls.dbname, cls.dbexisted = utils.load_sql(sql_file) # type: ignore
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
def tearDownClass(cls) -> None:
|
|
24
|
+
if not cls.dbexisted:
|
|
25
|
+
utils.drop_database(cls.dbname) # type: ignore
|
|
26
|
+
|
|
27
|
+
def test_vectordb_from_params(self) -> None:
|
|
28
|
+
db: VectorDB = s2.vector_db(database=type(self).dbname)
|
|
29
|
+
index = db.create_index(
|
|
30
|
+
name='test_index', dimension=3,
|
|
31
|
+
tags={'name': 'test_tag'},
|
|
32
|
+
)
|
|
33
|
+
assert index.name == 'test_index'
|
|
34
|
+
assert index.dimension == 3
|
|
35
|
+
assert index.tags == {'name': 'test_tag'}
|
|
36
|
+
assert db.has_index('test_index')
|
|
37
|
+
|
|
38
|
+
def test_vectordb_from_connection(self) -> None:
|
|
39
|
+
with s2.connect(database=type(self).dbname) as conn:
|
|
40
|
+
db: VectorDB = conn.vector_db
|
|
41
|
+
index = db.create_index(
|
|
42
|
+
name='test_index_1',
|
|
43
|
+
dimension=4, tags={'name': 'test_tag'},
|
|
44
|
+
)
|
|
45
|
+
assert index.name == 'test_index_1'
|
|
46
|
+
assert index.dimension == 4
|
|
47
|
+
assert index.tags == {'name': 'test_tag'}
|
|
48
|
+
assert db.has_index('test_index_1')
|
|
49
|
+
|
|
50
|
+
db2: VectorDB = conn.vector_db
|
|
51
|
+
assert db2.has_index('test_index_1')
|