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.
Files changed (183) hide show
  1. singlestoredb/__init__.py +75 -0
  2. singlestoredb/ai/__init__.py +2 -0
  3. singlestoredb/ai/chat.py +139 -0
  4. singlestoredb/ai/embeddings.py +128 -0
  5. singlestoredb/alchemy/__init__.py +90 -0
  6. singlestoredb/apps/__init__.py +3 -0
  7. singlestoredb/apps/_cloud_functions.py +90 -0
  8. singlestoredb/apps/_config.py +72 -0
  9. singlestoredb/apps/_connection_info.py +18 -0
  10. singlestoredb/apps/_dashboards.py +47 -0
  11. singlestoredb/apps/_process.py +32 -0
  12. singlestoredb/apps/_python_udfs.py +100 -0
  13. singlestoredb/apps/_stdout_supress.py +30 -0
  14. singlestoredb/apps/_uvicorn_util.py +36 -0
  15. singlestoredb/auth.py +245 -0
  16. singlestoredb/config.py +484 -0
  17. singlestoredb/connection.py +1487 -0
  18. singlestoredb/converters.py +950 -0
  19. singlestoredb/docstring/__init__.py +33 -0
  20. singlestoredb/docstring/attrdoc.py +126 -0
  21. singlestoredb/docstring/common.py +230 -0
  22. singlestoredb/docstring/epydoc.py +267 -0
  23. singlestoredb/docstring/google.py +412 -0
  24. singlestoredb/docstring/numpydoc.py +562 -0
  25. singlestoredb/docstring/parser.py +100 -0
  26. singlestoredb/docstring/py.typed +1 -0
  27. singlestoredb/docstring/rest.py +256 -0
  28. singlestoredb/docstring/tests/__init__.py +1 -0
  29. singlestoredb/docstring/tests/_pydoctor.py +21 -0
  30. singlestoredb/docstring/tests/test_epydoc.py +729 -0
  31. singlestoredb/docstring/tests/test_google.py +1007 -0
  32. singlestoredb/docstring/tests/test_numpydoc.py +1100 -0
  33. singlestoredb/docstring/tests/test_parse_from_object.py +109 -0
  34. singlestoredb/docstring/tests/test_parser.py +248 -0
  35. singlestoredb/docstring/tests/test_rest.py +547 -0
  36. singlestoredb/docstring/tests/test_util.py +70 -0
  37. singlestoredb/docstring/util.py +141 -0
  38. singlestoredb/exceptions.py +120 -0
  39. singlestoredb/functions/__init__.py +16 -0
  40. singlestoredb/functions/decorator.py +201 -0
  41. singlestoredb/functions/dtypes.py +1793 -0
  42. singlestoredb/functions/ext/__init__.py +1 -0
  43. singlestoredb/functions/ext/arrow.py +375 -0
  44. singlestoredb/functions/ext/asgi.py +2133 -0
  45. singlestoredb/functions/ext/json.py +420 -0
  46. singlestoredb/functions/ext/mmap.py +413 -0
  47. singlestoredb/functions/ext/rowdat_1.py +724 -0
  48. singlestoredb/functions/ext/timer.py +89 -0
  49. singlestoredb/functions/ext/utils.py +218 -0
  50. singlestoredb/functions/signature.py +1578 -0
  51. singlestoredb/functions/typing/__init__.py +41 -0
  52. singlestoredb/functions/typing/numpy.py +20 -0
  53. singlestoredb/functions/typing/pandas.py +2 -0
  54. singlestoredb/functions/typing/polars.py +2 -0
  55. singlestoredb/functions/typing/pyarrow.py +2 -0
  56. singlestoredb/functions/utils.py +421 -0
  57. singlestoredb/fusion/__init__.py +11 -0
  58. singlestoredb/fusion/graphql.py +213 -0
  59. singlestoredb/fusion/handler.py +916 -0
  60. singlestoredb/fusion/handlers/__init__.py +0 -0
  61. singlestoredb/fusion/handlers/export.py +525 -0
  62. singlestoredb/fusion/handlers/files.py +690 -0
  63. singlestoredb/fusion/handlers/job.py +660 -0
  64. singlestoredb/fusion/handlers/models.py +250 -0
  65. singlestoredb/fusion/handlers/stage.py +502 -0
  66. singlestoredb/fusion/handlers/utils.py +324 -0
  67. singlestoredb/fusion/handlers/workspace.py +956 -0
  68. singlestoredb/fusion/registry.py +249 -0
  69. singlestoredb/fusion/result.py +399 -0
  70. singlestoredb/http/__init__.py +27 -0
  71. singlestoredb/http/connection.py +1267 -0
  72. singlestoredb/magics/__init__.py +34 -0
  73. singlestoredb/magics/run_personal.py +137 -0
  74. singlestoredb/magics/run_shared.py +134 -0
  75. singlestoredb/management/__init__.py +9 -0
  76. singlestoredb/management/billing_usage.py +148 -0
  77. singlestoredb/management/cluster.py +462 -0
  78. singlestoredb/management/export.py +295 -0
  79. singlestoredb/management/files.py +1102 -0
  80. singlestoredb/management/inference_api.py +105 -0
  81. singlestoredb/management/job.py +887 -0
  82. singlestoredb/management/manager.py +373 -0
  83. singlestoredb/management/organization.py +226 -0
  84. singlestoredb/management/region.py +169 -0
  85. singlestoredb/management/utils.py +423 -0
  86. singlestoredb/management/workspace.py +1927 -0
  87. singlestoredb/mysql/__init__.py +177 -0
  88. singlestoredb/mysql/_auth.py +298 -0
  89. singlestoredb/mysql/charset.py +214 -0
  90. singlestoredb/mysql/connection.py +2032 -0
  91. singlestoredb/mysql/constants/CLIENT.py +38 -0
  92. singlestoredb/mysql/constants/COMMAND.py +32 -0
  93. singlestoredb/mysql/constants/CR.py +78 -0
  94. singlestoredb/mysql/constants/ER.py +474 -0
  95. singlestoredb/mysql/constants/EXTENDED_TYPE.py +3 -0
  96. singlestoredb/mysql/constants/FIELD_TYPE.py +48 -0
  97. singlestoredb/mysql/constants/FLAG.py +15 -0
  98. singlestoredb/mysql/constants/SERVER_STATUS.py +10 -0
  99. singlestoredb/mysql/constants/VECTOR_TYPE.py +6 -0
  100. singlestoredb/mysql/constants/__init__.py +0 -0
  101. singlestoredb/mysql/converters.py +271 -0
  102. singlestoredb/mysql/cursors.py +896 -0
  103. singlestoredb/mysql/err.py +92 -0
  104. singlestoredb/mysql/optionfile.py +20 -0
  105. singlestoredb/mysql/protocol.py +450 -0
  106. singlestoredb/mysql/tests/__init__.py +19 -0
  107. singlestoredb/mysql/tests/base.py +126 -0
  108. singlestoredb/mysql/tests/conftest.py +37 -0
  109. singlestoredb/mysql/tests/test_DictCursor.py +132 -0
  110. singlestoredb/mysql/tests/test_SSCursor.py +141 -0
  111. singlestoredb/mysql/tests/test_basic.py +452 -0
  112. singlestoredb/mysql/tests/test_connection.py +851 -0
  113. singlestoredb/mysql/tests/test_converters.py +58 -0
  114. singlestoredb/mysql/tests/test_cursor.py +141 -0
  115. singlestoredb/mysql/tests/test_err.py +16 -0
  116. singlestoredb/mysql/tests/test_issues.py +514 -0
  117. singlestoredb/mysql/tests/test_load_local.py +75 -0
  118. singlestoredb/mysql/tests/test_nextset.py +88 -0
  119. singlestoredb/mysql/tests/test_optionfile.py +27 -0
  120. singlestoredb/mysql/tests/thirdparty/__init__.py +6 -0
  121. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/__init__.py +9 -0
  122. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/capabilities.py +323 -0
  123. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/dbapi20.py +865 -0
  124. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py +110 -0
  125. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py +224 -0
  126. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py +101 -0
  127. singlestoredb/mysql/times.py +23 -0
  128. singlestoredb/notebook/__init__.py +16 -0
  129. singlestoredb/notebook/_objects.py +213 -0
  130. singlestoredb/notebook/_portal.py +352 -0
  131. singlestoredb/py.typed +0 -0
  132. singlestoredb/pytest.py +352 -0
  133. singlestoredb/server/__init__.py +0 -0
  134. singlestoredb/server/docker.py +452 -0
  135. singlestoredb/server/free_tier.py +267 -0
  136. singlestoredb/tests/__init__.py +0 -0
  137. singlestoredb/tests/alltypes.sql +307 -0
  138. singlestoredb/tests/alltypes_no_nulls.sql +208 -0
  139. singlestoredb/tests/empty.sql +0 -0
  140. singlestoredb/tests/ext_funcs/__init__.py +702 -0
  141. singlestoredb/tests/local_infile.csv +3 -0
  142. singlestoredb/tests/test.ipynb +18 -0
  143. singlestoredb/tests/test.sql +680 -0
  144. singlestoredb/tests/test2.ipynb +18 -0
  145. singlestoredb/tests/test2.sql +1 -0
  146. singlestoredb/tests/test_basics.py +1332 -0
  147. singlestoredb/tests/test_config.py +318 -0
  148. singlestoredb/tests/test_connection.py +3103 -0
  149. singlestoredb/tests/test_dbapi.py +27 -0
  150. singlestoredb/tests/test_exceptions.py +45 -0
  151. singlestoredb/tests/test_ext_func.py +1472 -0
  152. singlestoredb/tests/test_ext_func_data.py +1101 -0
  153. singlestoredb/tests/test_fusion.py +1527 -0
  154. singlestoredb/tests/test_http.py +288 -0
  155. singlestoredb/tests/test_management.py +1599 -0
  156. singlestoredb/tests/test_plugin.py +33 -0
  157. singlestoredb/tests/test_results.py +171 -0
  158. singlestoredb/tests/test_types.py +132 -0
  159. singlestoredb/tests/test_udf.py +737 -0
  160. singlestoredb/tests/test_udf_returns.py +459 -0
  161. singlestoredb/tests/test_vectorstore.py +51 -0
  162. singlestoredb/tests/test_xdict.py +333 -0
  163. singlestoredb/tests/utils.py +141 -0
  164. singlestoredb/types.py +373 -0
  165. singlestoredb/utils/__init__.py +0 -0
  166. singlestoredb/utils/config.py +950 -0
  167. singlestoredb/utils/convert_rows.py +69 -0
  168. singlestoredb/utils/debug.py +13 -0
  169. singlestoredb/utils/dtypes.py +205 -0
  170. singlestoredb/utils/events.py +65 -0
  171. singlestoredb/utils/mogrify.py +151 -0
  172. singlestoredb/utils/results.py +585 -0
  173. singlestoredb/utils/xdict.py +425 -0
  174. singlestoredb/vectorstore.py +192 -0
  175. singlestoredb/warnings.py +5 -0
  176. singlestoredb-1.16.1.dist-info/METADATA +165 -0
  177. singlestoredb-1.16.1.dist-info/RECORD +183 -0
  178. singlestoredb-1.16.1.dist-info/WHEEL +5 -0
  179. singlestoredb-1.16.1.dist-info/entry_points.txt +2 -0
  180. singlestoredb-1.16.1.dist-info/licenses/LICENSE +201 -0
  181. singlestoredb-1.16.1.dist-info/top_level.txt +3 -0
  182. sqlx/__init__.py +4 -0
  183. sqlx/magic.py +113 -0
@@ -0,0 +1,956 @@
1
+ #!/usr/bin/env python3
2
+ import json
3
+ from typing import Any
4
+ from typing import Dict
5
+ from typing import Optional
6
+
7
+ from .. import result
8
+ from ..handler import SQLHandler
9
+ from ..result import FusionSQLResult
10
+ from .utils import dt_isoformat
11
+ from .utils import get_workspace
12
+ from .utils import get_workspace_group
13
+ from .utils import get_workspace_manager
14
+
15
+
16
+ class UseWorkspaceHandler(SQLHandler):
17
+ """
18
+ USE WORKSPACE workspace [ in_group ] [ with_database ];
19
+
20
+ # Workspace
21
+ workspace = { workspace_id | workspace_name | current_workspace }
22
+
23
+ # ID of workspace
24
+ workspace_id = ID '<workspace-id>'
25
+
26
+ # Name of workspace
27
+ workspace_name = '<workspace-name>'
28
+
29
+ # Current workspace
30
+ current_workspace = @@CURRENT
31
+
32
+ # Workspace group specification
33
+ in_group = IN GROUP { group_id | group_name }
34
+
35
+ # ID of workspace group
36
+ group_id = ID '<group-id>'
37
+
38
+ # Name of workspace group
39
+ group_name = '<group-name>'
40
+
41
+ # Name of database
42
+ with_database = WITH DATABASE 'database-name'
43
+
44
+ Description
45
+ -----------
46
+ Change the workspace and database in the notebook.
47
+
48
+ Arguments
49
+ ---------
50
+ * ``<workspace-id>``: The ID of the workspace to use.
51
+ * ``<workspace-name>``: The name of the workspace to use.
52
+ * ``<group-id>``: The ID of the workspace group to search in.
53
+ * ``<group-name>``: The name of the workspace group to search in.
54
+
55
+ Remarks
56
+ -------
57
+ * If you want to specify a database in the current workspace,
58
+ the workspace name can be specified as ``@@CURRENT``.
59
+ * Use the ``IN GROUP`` clause to specify the ID or name of the workspace
60
+ group where the workspace should be found. If not specified, the current
61
+ workspace group will be used.
62
+ * Specify the ``WITH DATABASE`` clause to select a default
63
+ database for the session.
64
+ * This command only works in a notebook session in the
65
+ Managed Service.
66
+
67
+ Example
68
+ -------
69
+ The following command sets the workspace to ``examplews`` and
70
+ select 'dbname' as the default database::
71
+
72
+ USE WORKSPACE 'examplews' WITH DATABASE 'dbname';
73
+
74
+ The following command sets the workspace to ``examplews`` from a specific
75
+ workspace group::
76
+
77
+ USE WORKSPACE 'examplews' IN GROUP 'my-workspace-group';
78
+
79
+ """
80
+ def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]:
81
+ from singlestoredb.notebook import portal
82
+
83
+ # Handle current workspace case
84
+ if params['workspace'].get('current_workspace'):
85
+ if params.get('with_database'):
86
+ portal.default_database = params['with_database']
87
+ return None
88
+
89
+ # Get workspace name or ID
90
+ workspace_name = params['workspace'].get('workspace_name')
91
+ workspace_id = params['workspace'].get('workspace_id')
92
+
93
+ # If IN GROUP is specified, look up workspace in that group
94
+ if params.get('in_group'):
95
+ workspace_group = get_workspace_group(params)
96
+
97
+ if workspace_name:
98
+ workspace = workspace_group.workspaces[workspace_name]
99
+ elif workspace_id:
100
+ # Find workspace by ID in the specified group
101
+ workspace = next(
102
+ (w for w in workspace_group.workspaces if w.id == workspace_id),
103
+ None,
104
+ )
105
+ if workspace is None:
106
+ raise KeyError(f'no workspace found with ID: {workspace_id}')
107
+
108
+ workspace_id = workspace.id
109
+
110
+ try:
111
+ # Set workspace and database
112
+ if params.get('with_database'):
113
+ if params.get('in_group'):
114
+ # Use 3-element tuple: (workspace_group_id, workspace_name_or_id,
115
+ # database)
116
+ portal.connection = ( # type: ignore[assignment]
117
+ workspace_group.id,
118
+ workspace_name or workspace_id,
119
+ params['with_database'],
120
+ )
121
+ else:
122
+ # Use 2-element tuple: (workspace_name_or_id, database)
123
+ portal.connection = (
124
+ workspace_name or workspace_id,
125
+ params['with_database'],
126
+ )
127
+ else:
128
+ if params.get('in_group'):
129
+ # Use 2-element tuple: (workspace_group_id, workspace_name_or_id)
130
+ portal.workspace = ( # type: ignore[assignment]
131
+ workspace_group.id,
132
+ workspace_name or workspace_id,
133
+ )
134
+ else:
135
+ # Use string: workspace_name_or_id
136
+ portal.workspace = workspace_name or workspace_id
137
+
138
+ except RuntimeError as exc:
139
+ if 'timeout' not in str(exc):
140
+ raise
141
+
142
+ return None
143
+
144
+
145
+ UseWorkspaceHandler.register(overwrite=True)
146
+
147
+
148
+ class ShowRegionsHandler(SQLHandler):
149
+ """
150
+ SHOW REGIONS [ <like> ]
151
+ [ <order-by> ]
152
+ [ <limit> ];
153
+
154
+ Description
155
+ -----------
156
+ Returns a list of all the valid regions for the user.
157
+
158
+ Arguments
159
+ ---------
160
+ * ``<pattern>``: A pattern similar to SQL LIKE clause.
161
+ Uses ``%`` as the wildcard character.
162
+
163
+ Remarks
164
+ -------
165
+ * Use the ``LIKE`` clause to specify a pattern and return only the
166
+ regions that match the specified pattern.
167
+ * The ``LIMIT`` clause limits the number of results to the
168
+ specified number.
169
+ * Use the ``ORDER BY`` clause to sort the results by the specified
170
+ key. By default, the results are sorted in the ascending order.
171
+
172
+ Example
173
+ -------
174
+ The following command returns a list of all the regions in the US
175
+ and sorts the results in ascending order by their ``Name``::
176
+
177
+ SHOW REGIONS LIKE 'US%' ORDER BY Name;
178
+
179
+ """
180
+
181
+ def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]:
182
+ manager = get_workspace_manager()
183
+
184
+ res = FusionSQLResult()
185
+ res.add_field('Name', result.STRING)
186
+ res.add_field('ID', result.STRING)
187
+ res.add_field('Provider', result.STRING)
188
+
189
+ res.set_rows([(x.name, x.id, x.provider) for x in manager.regions])
190
+
191
+ if params['like']:
192
+ res = res.like(Name=params['like'])
193
+
194
+ return res.order_by(**params['order_by']).limit(params['limit'])
195
+
196
+
197
+ ShowRegionsHandler.register(overwrite=True)
198
+
199
+
200
+ class ShowWorkspaceGroupsHandler(SQLHandler):
201
+ """
202
+ SHOW WORKSPACE GROUPS [ <like> ]
203
+ [ <extended> ] [ <order-by> ]
204
+ [ <limit> ];
205
+
206
+ Description
207
+ -----------
208
+ Displays information on workspace groups.
209
+
210
+ Arguments
211
+ ---------
212
+ * ``<pattern>``: A pattern similar to SQL LIKE clause.
213
+ Uses ``%`` as the wildcard character.
214
+
215
+ Remarks
216
+ -------
217
+ * Use the ``LIKE`` clause to specify a pattern and return only the
218
+ workspace groups that match the specified pattern.
219
+ * The ``LIMIT`` clause limits the number of results to the
220
+ specified number.
221
+ * Use the ``ORDER BY`` clause to sort the results by the specified
222
+ key. By default, the results are sorted in the ascending order.
223
+ * To return more information about the workspace groups, use the
224
+ ``EXTENDED`` clause.
225
+
226
+ Example
227
+ -------
228
+ The following command displays a list of workspace groups with names
229
+ that match the specified pattern::
230
+
231
+ SHOW WORKSPACE GROUPS LIKE 'Marketing%' EXTENDED ORDER BY Name;
232
+
233
+ See Also
234
+ --------
235
+ * ``SHOW WORKSPACES``
236
+
237
+ """
238
+
239
+ def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]:
240
+ manager = get_workspace_manager()
241
+
242
+ res = FusionSQLResult()
243
+ res.add_field('Name', result.STRING)
244
+ res.add_field('ID', result.STRING)
245
+ res.add_field('Region', result.STRING)
246
+ res.add_field('FirewallRanges', result.JSON)
247
+
248
+ if params['extended']:
249
+ res.add_field('CreatedAt', result.DATETIME)
250
+ res.add_field('TerminatedAt', result.DATETIME)
251
+
252
+ def fields(x: Any) -> Any:
253
+ return (
254
+ x.name, x.id, x.region.name,
255
+ json.dumps(x.firewall_ranges),
256
+ dt_isoformat(x.created_at),
257
+ dt_isoformat(x.terminated_at),
258
+ )
259
+ else:
260
+ def fields(x: Any) -> Any:
261
+ return (x.name, x.id, x.region.name, json.dumps(x.firewall_ranges))
262
+
263
+ res.set_rows([fields(x) for x in manager.workspace_groups])
264
+
265
+ if params['like']:
266
+ res = res.like(Name=params['like'])
267
+
268
+ return res.order_by(**params['order_by']).limit(params['limit'])
269
+
270
+
271
+ ShowWorkspaceGroupsHandler.register(overwrite=True)
272
+
273
+
274
+ class ShowWorkspacesHandler(SQLHandler):
275
+ """
276
+ SHOW WORKSPACES [ in_group ]
277
+ [ <like> ] [ <extended> ]
278
+ [ <order-by> ] [ <limit> ];
279
+
280
+ # Workspace group
281
+ in_group = IN GROUP { group_id | group_name }
282
+
283
+ # ID of group
284
+ group_id = ID '<group-id>'
285
+
286
+ # Name of group
287
+ group_name = '<group-name>'
288
+
289
+ Description
290
+ -----------
291
+ Displays information on workspaces in a workspace group.
292
+
293
+ Arguments
294
+ ---------
295
+ * ``<group_id>``: The ID of the workspace group that contains
296
+ the workspace.
297
+ * ``<group_name>``: The name of the workspace group that
298
+ contains the workspace.
299
+ * ``<pattern>``: A pattern similar to SQL LIKE clause.
300
+ Uses ``%`` as the wildcard character.
301
+
302
+ Remarks
303
+ -------
304
+ * The ``IN GROUP`` clause specifies the ID or the name of the
305
+ workspace group that contains the workspace.
306
+ * Use the ``LIKE`` clause to specify a pattern and return only
307
+ the workspaces that match the specified pattern.
308
+ * The ``LIMIT`` clause limits the number of results to the
309
+ specified number.
310
+ * Use the ``ORDER BY`` clause to sort the results by the
311
+ specified key. By default, the results are sorted in the
312
+ ascending order.
313
+ * To return more information about the workspaces, use the
314
+ ``EXTENDED`` clause.
315
+
316
+ Example
317
+ -------
318
+ The following command displays information on all the workspaces
319
+ in a workspace group named **wsg1** and sorts the results by
320
+ workspace name in the ascending order::
321
+
322
+ SHOW WORKSPACES IN GROUP 'wsg1' EXTENDED ORDER BY Name;
323
+
324
+ See Also
325
+ --------
326
+ * ``SHOW WORKSPACE GROUPS``
327
+
328
+ """
329
+
330
+ def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]:
331
+ res = FusionSQLResult()
332
+ res.add_field('Name', result.STRING)
333
+ res.add_field('ID', result.STRING)
334
+ res.add_field('Size', result.STRING)
335
+ res.add_field('State', result.STRING)
336
+
337
+ workspace_group = get_workspace_group(params)
338
+
339
+ if params['extended']:
340
+ res.add_field('Endpoint', result.STRING)
341
+ res.add_field('CreatedAt', result.DATETIME)
342
+ res.add_field('TerminatedAt', result.DATETIME)
343
+
344
+ def fields(x: Any) -> Any:
345
+ return (
346
+ x.name, x.id, x.size, x.state,
347
+ x.endpoint, dt_isoformat(x.created_at),
348
+ dt_isoformat(x.terminated_at),
349
+ )
350
+ else:
351
+ def fields(x: Any) -> Any:
352
+ return (x.name, x.id, x.size, x.state)
353
+
354
+ res.set_rows([fields(x) for x in workspace_group.workspaces])
355
+
356
+ if params['like']:
357
+ res = res.like(Name=params['like'])
358
+
359
+ return res.order_by(**params['order_by']).limit(params['limit'])
360
+
361
+
362
+ ShowWorkspacesHandler.register(overwrite=True)
363
+
364
+
365
+ class CreateWorkspaceGroupHandler(SQLHandler):
366
+ """
367
+ CREATE WORKSPACE GROUP [ if_not_exists ] group_name
368
+ IN REGION { region_id | region_name }
369
+ [ with_password ]
370
+ [ expires_at ]
371
+ [ with_firewall_ranges ]
372
+ [ with_backup_bucket_kms_key_id ]
373
+ [ with_data_bucket_kms_key_id ]
374
+ [ with_smart_dr ]
375
+ [ allow_all_traffic ]
376
+ [ with_update_window ]
377
+ ;
378
+
379
+ # Only create workspace group if it doesn't exist already
380
+ if_not_exists = IF NOT EXISTS
381
+
382
+ # Name of the workspace group
383
+ group_name = '<group-name>'
384
+
385
+ # ID of region to create workspace group in
386
+ region_id = ID '<region-id>'
387
+
388
+ # Name of region to create workspace group in
389
+ region_name = '<region-name>'
390
+
391
+ # Admin password
392
+ with_password = WITH PASSWORD '<password>'
393
+
394
+ # Datetime or interval for expiration date/time of workspace group
395
+ expires_at = EXPIRES AT '<iso-datetime-or-interval>'
396
+
397
+ # Incoming IP ranges
398
+ with_firewall_ranges = WITH FIREWALL RANGES '<ip-range>',...
399
+
400
+ # Backup bucket key
401
+ with_backup_bucket_kms_key_id = WITH BACKUP BUCKET KMS KEY ID '<key-id>'
402
+
403
+ # Data bucket key
404
+ with_data_bucket_kms_key_id = WITH DATA BUCKET KMS KEY ID '<key-id>'
405
+
406
+ # Smart DR
407
+ with_smart_dr = WITH SMART DR
408
+
409
+ # Allow all incoming traffic
410
+ allow_all_traffic = ALLOW ALL TRAFFIC
411
+
412
+ # Update window
413
+ with_update_window = WITH UPDATE WINDOW '<day>:<hour>'
414
+
415
+ Description
416
+ -----------
417
+ Creates a workspace group.
418
+
419
+ Arguments
420
+ ---------
421
+ * ``<group-name>``: The name of the workspace group.
422
+ * ``<region_id>`` or ``<region_name>``: The ID or the name of the region
423
+ in which the new workspace group is created.
424
+ * ``<password>``: The admin password of the workspace group.
425
+ The password must contain:
426
+ - At least 8 characters
427
+ - At least one uppercase character
428
+ - At least one lowercase character
429
+ - At least one number or special character
430
+ * ``<expiry_time>``: The timestamp of when the workspace group terminates.
431
+ Expiration time can be specified as a timestamp or duration.
432
+ * ``<ip_range>``: A list of allowed IP addresses or CIDR ranges.
433
+ * ``<backup_key_id>``: The KMS key ID associated with the backup bucket.
434
+ * ``<data_key_id>``: The KMS key ID associated with the data bucket.
435
+ * ``<day>:<hour>``: The day of the week (0-6) and the hour of the day
436
+ (0-23) when the engine updates are applied to the workspace group.
437
+
438
+ Remarks
439
+ -------
440
+ * Specify the ``IF NOT EXISTS`` clause to create a new workspace group only
441
+ if a workspace group with the specified name does not exist.
442
+ * If the ``WITH BACKUP BUCKET KMS KEY ID '<backup_key_id>'`` clause is
443
+ specified, Customer-Managed Encryption Keys (CMEK) encryption is enabled
444
+ for the data bucket of the workspace group.
445
+ * If the ``WITH DATA BUCKET KMS KEY ID '<data_key_id>'`` clause is specified,
446
+ CMEK encryption for the data bucket and Amazon Elastic Block Store (EBS)
447
+ volumes of the workspace group is enabled.
448
+ * To enable Smart Disaster Recovery (SmartDR) for the workspace group, specify
449
+ the WITH SMART DR clause. Refer to Smart Disaster Recovery (DR):
450
+ SmartDR for more information.
451
+ * To allow incoming traffic from any IP address, use the ``ALLOW ALL TRAFFIC``
452
+ clause.
453
+
454
+ Examples
455
+ --------
456
+ The following command creates a workspace group named wsg1 in the
457
+ US East 2 (Ohio) region::
458
+
459
+ CREATE WORKSPACE GROUP 'wsg1' IN REGION 'US East 2 (Ohio)';
460
+
461
+ The following command specifies additional workspace group configuration
462
+ options::
463
+
464
+ CREATE WORKSPACE GROUP 'wsg1'
465
+ IN REGION ID '93b61160-0000-1000-9000-977b8e2e3ee5'
466
+ WITH FIREWALL RANGES '0.0.0.0/0';
467
+
468
+ See Also
469
+ --------
470
+ * ``SHOW WORKSPACE GROUPS``
471
+
472
+ """
473
+
474
+ def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]:
475
+ manager = get_workspace_manager()
476
+
477
+ # Only create if one doesn't exist
478
+ if params['if_not_exists']:
479
+ try:
480
+ get_workspace_group(params)
481
+ return None
482
+ except (ValueError, KeyError):
483
+ pass
484
+
485
+ # Get region ID
486
+ if params['region_name']:
487
+ regs = [x for x in manager.regions if x.name == params['region_name']]
488
+ if not regs:
489
+ raise KeyError(f'no region found with name "{params["region_name"]}"')
490
+ if len(regs) > 1:
491
+ raise ValueError(
492
+ f'multiple regions found with the name "{params["region_name"]}"',
493
+ )
494
+ region_id = regs[0].id
495
+ else:
496
+ region_id = params['region_id']
497
+
498
+ with_update_window = None
499
+ if params['with_update_window']:
500
+ day, hour = params['with_update_window'].split(':', 1)
501
+ with_update_window = dict(day=int(day), hour=int(hour))
502
+
503
+ manager.create_workspace_group(
504
+ params['group_name'],
505
+ region=region_id,
506
+ admin_password=params['with_password'],
507
+ expires_at=params['expires_at'],
508
+ firewall_ranges=params['with_firewall_ranges'],
509
+ backup_bucket_kms_key_id=params['with_backup_bucket_kms_key_id'],
510
+ data_bucket_kms_key_id=params['with_data_bucket_kms_key_id'],
511
+ smart_dr=params['with_smart_dr'],
512
+ allow_all_traffic=params['allow_all_traffic'],
513
+ update_window=with_update_window,
514
+ )
515
+
516
+ return None
517
+
518
+
519
+ CreateWorkspaceGroupHandler.register(overwrite=True)
520
+
521
+
522
+ class CreateWorkspaceHandler(SQLHandler):
523
+ """
524
+ CREATE WORKSPACE [ if_not_exists ] workspace_name
525
+ [ in_group ]
526
+ WITH SIZE size
527
+ [ auto_suspend ]
528
+ [ enable_kai ]
529
+ [ with_cache_config ]
530
+ [ wait_on_active ];
531
+
532
+ # Create workspace in workspace group
533
+ in_group = IN GROUP { group_id | group_name }
534
+
535
+ # Only run command if workspace doesn't already exist
536
+ if_not_exists = IF NOT EXISTS
537
+
538
+ # Name of the workspace
539
+ workspace_name = '<workspace-name>'
540
+
541
+ # ID of the group to create workspace in
542
+ group_id = ID '<group-id>'
543
+
544
+ # Name of the group to create workspace in
545
+ group_name = '<group-name>'
546
+
547
+ # Runtime size
548
+ size = '<size>'
549
+
550
+ # Auto-suspend
551
+ auto_suspend = AUTO SUSPEND AFTER suspend_after_value suspend_after_units suspend_type
552
+ suspend_after_value = <integer>
553
+ suspend_after_units = { SECONDS | MINUTES | HOURS | DAYS }
554
+ suspend_type = WITH TYPE { IDLE | SCHEDULED | DISABLED }
555
+
556
+ # Enable Kai
557
+ enable_kai = ENABLE KAI
558
+
559
+ # Cache config
560
+ with_cache_config = WITH CACHE CONFIG <integer>
561
+
562
+ # Wait for workspace to be active before continuing
563
+ wait_on_active = WAIT ON ACTIVE
564
+
565
+ Description
566
+ -----------
567
+ Creates a new workspace. Refer to
568
+ `Creating and Using Workspaces <https://docs.singlestore.com/cloud/getting-started-with-singlestore-helios/about-workspaces/creating-and-using-workspaces/>`_
569
+ for more information.
570
+
571
+ Arguments
572
+ ---------
573
+ * ``<workspace_name>``: The name of the workspace.
574
+ * ``<group_id>`` or ``<group_name>``: The ID or name of the workspace group
575
+ in which the workspace is created.
576
+ * ``<workspace_size>``: The size of the workspace in workspace size notation,
577
+ for example "S-1".
578
+ * ``<suspend_time>``: The time (in given units) after which the workspace is
579
+ suspended, according to the specified auto-suspend type.
580
+ * ``<multiplier>``: The multiplier for the persistent cache associated with
581
+ the workspace.
582
+
583
+ Remarks
584
+ -------
585
+ * Use the ``IF NOT EXISTS`` clause to create a new workspace only if a workspace
586
+ with the specified name does not exist.
587
+ * If the ``WITH CACHE CONFIG <multiplier>`` clause is specified, the cache
588
+ configuration multiplier is enabled for the workspace. It can have the
589
+ following values: 1, 2, or 4.
590
+ * The ``WAIT ON ACTIVE`` clause indicates that the execution is paused until this
591
+ workspace is in ACTIVE state.
592
+ * Specify the ``ENABLE KAI`` clause to enable SingleStore Kai and the MongoDB®
593
+ API for the workspace.
594
+
595
+ Example
596
+ -------
597
+ The following command creates a workspace named **examplews** in a workspace
598
+ group named **wsg1**::
599
+
600
+ CREATE WORKSPACE 'examplews' IN GROUP 'wsgroup1'
601
+ WITH SIZE 'S-00' WAIT ON ACTIVE;
602
+
603
+ See Also
604
+ --------
605
+ * ``CREATE WORKSPACE GROUP``
606
+
607
+ """ # noqa: E501
608
+
609
+ def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]:
610
+ workspace_group = get_workspace_group(params)
611
+
612
+ # Only create if one doesn't exist
613
+ if params['if_not_exists']:
614
+ try:
615
+ workspace_group.workspaces[params['workspace_name']]
616
+ return None
617
+ except KeyError:
618
+ pass
619
+
620
+ auto_suspend = None
621
+ if params['auto_suspend']:
622
+ mult = dict(
623
+ SECONDS=1,
624
+ MINUTES=60,
625
+ HOURS=60*60,
626
+ DAYS=60*60*24,
627
+ )
628
+ val = params['auto_suspend'][0]['suspend_after_value']
629
+ val = val * mult[params['auto_suspend'][1]['suspend_after_units'].upper()]
630
+ auto_suspend = dict(
631
+ suspend_after_seconds=val,
632
+ suspend_type=params['auto_suspend'][2]['suspend_type'].upper(),
633
+ )
634
+
635
+ workspace_group.create_workspace(
636
+ params['workspace_name'],
637
+ size=params['size'],
638
+ auto_suspend=auto_suspend,
639
+ enable_kai=params['enable_kai'],
640
+ cache_config=params['with_cache_config'],
641
+ wait_on_active=params['wait_on_active'],
642
+ )
643
+
644
+ return None
645
+
646
+
647
+ CreateWorkspaceHandler.register(overwrite=True)
648
+
649
+
650
+ class SuspendWorkspaceHandler(SQLHandler):
651
+ """
652
+ SUSPEND WORKSPACE workspace
653
+ [ in_group ]
654
+ [ wait_on_suspended ];
655
+
656
+ # Workspace
657
+ workspace = { workspace_id | workspace_name }
658
+
659
+ # ID of workspace
660
+ workspace_id = ID '<workspace-id>'
661
+
662
+ # Name of workspace
663
+ workspace_name = '<workspace-name>'
664
+
665
+ # Workspace group
666
+ in_group = IN GROUP { group_id | group_name }
667
+
668
+ # ID of workspace group
669
+ group_id = ID '<group-id>'
670
+
671
+ # Name of workspace group
672
+ group_name = '<group-name>'
673
+
674
+ # Wait for workspace to be suspended before continuing
675
+ wait_on_suspended = WAIT ON SUSPENDED
676
+
677
+ Description
678
+ -----------
679
+ Suspends a workspace.
680
+
681
+ Refer to `Manage Workspaces <https://docs.singlestore.com/cloud/user-and-workspace-administration/manage-organizations/manage-workspaces/>`_
682
+ for more information.
683
+
684
+ Arguments
685
+ ---------
686
+ * ``<workspace-id>``: The ID of the workspace to suspend.
687
+ * ``<workspace-name>``: The name of the workspace to suspend.
688
+ * ``<group-id>``: The ID of the workspace group that contains
689
+ the workspace.
690
+ * ``<group-name>``: The name of the workspace group that
691
+ contains the workspace.
692
+
693
+ Remarks
694
+ -------
695
+ * Use the ``WAIT ON SUSPENDED`` clause to pause query execution
696
+ until the workspace is in the ``SUSPENDED`` state.
697
+
698
+ Example
699
+ -------
700
+ The following example suspends a workspace named examplews in
701
+ a workspace group named **wsg1**::
702
+
703
+ SUSPEND WORKSPACE 'examplews' IN GROUP 'wsg1';
704
+
705
+ See Also
706
+ --------
707
+ * ``RESUME WORKSPACE``
708
+
709
+ """ # noqa: E501
710
+
711
+ def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]:
712
+ ws = get_workspace(params)
713
+ ws.suspend(wait_on_suspended=params['wait_on_suspended'])
714
+ return None
715
+
716
+
717
+ SuspendWorkspaceHandler.register(overwrite=True)
718
+
719
+
720
+ class ResumeWorkspaceHandler(SQLHandler):
721
+ """
722
+ RESUME WORKSPACE workspace
723
+ [ in_group ]
724
+ [ disable_auto_suspend ]
725
+ [ wait_on_resumed ];
726
+
727
+ # Workspace
728
+ workspace = { workspace_id | workspace_name }
729
+
730
+ # ID of workspace
731
+ workspace_id = ID '<workspace-id>'
732
+
733
+ # Name of workspace
734
+ workspace_name = '<workspace-name>'
735
+
736
+ # Workspace group
737
+ in_group = IN GROUP { group_id | group_name }
738
+
739
+ # ID of workspace group
740
+ group_id = ID '<group-id>'
741
+
742
+ # Name of workspace group
743
+ group_name = '<group-name>'
744
+
745
+ # Disable auto-suspend
746
+ disable_auto_suspend = DISABLE AUTO SUSPEND
747
+
748
+ # Wait for workspace to be resumed before continuing
749
+ wait_on_resumed = WAIT ON RESUMED
750
+
751
+ Description
752
+ -----------
753
+ Resumes a workspace.
754
+
755
+ Refer to `Manage Workspaces <https://docs.singlestore.com/cloud/user-and-workspace-administration/manage-organizations/manage-workspaces/>`_
756
+ for more information.
757
+
758
+ Arguments
759
+ ---------
760
+ * ``<workspace-id>``: The ID of the workspace to resume.
761
+ * ``<workspace-name>``: The name of the workspace to resume.
762
+ * ``<group_id>``: The ID of the workspace group that contains
763
+ the workspace.
764
+ * ``<group_name>``: The name of the workspace group that
765
+ contains the workspace.
766
+
767
+ Remarks
768
+ -------
769
+ * Use the ``IN GROUP`` clause to specify the ID or name of the
770
+ workspace group that contains the workspace to resume.
771
+ * Use the ``WAIT ON RESUMED`` clause to pause query execution
772
+ until the workspace is in the ``RESUMED`` state.
773
+ * Specify the ``DISABLE AUTO SUSPEND`` clause to disable
774
+ auto-suspend for the resumed workspace.
775
+
776
+ Example
777
+ -------
778
+ The following example resumes a workspace with the specified ID
779
+ in a workspace group named **wsg1**::
780
+
781
+ RESUME WORKSPACE ID '93b61160-0000-1000-9000-977b8e2e3ee5'
782
+ IN GROUP 'wsg1';
783
+
784
+ """ # noqa: E501
785
+
786
+ def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]:
787
+ ws = get_workspace(params)
788
+ ws.resume(
789
+ wait_on_resumed=params['wait_on_resumed'],
790
+ disable_auto_suspend=params['disable_auto_suspend'],
791
+ )
792
+ return None
793
+
794
+
795
+ ResumeWorkspaceHandler.register(overwrite=True)
796
+
797
+
798
+ class DropWorkspaceGroupHandler(SQLHandler):
799
+ """
800
+ DROP WORKSPACE GROUP [ if_exists ]
801
+ group
802
+ [ wait_on_terminated ]
803
+ [ force ];
804
+
805
+ # Only run command if the workspace group exists
806
+ if_exists = IF EXISTS
807
+
808
+ # Workspace group
809
+ group = { group_id | group_name }
810
+
811
+ # ID of the workspace group to delete
812
+ group_id = ID '<group-id>'
813
+
814
+ # Name of the workspace group to delete
815
+ group_name = '<group-name>'
816
+
817
+ # Wait for termination to complete before continuing
818
+ wait_on_terminated = WAIT ON TERMINATED
819
+
820
+ # Should the workspace group be terminated even if it has workspaces?
821
+ force = FORCE
822
+
823
+ Description
824
+ -----------
825
+ Deletes the specified workspace group.
826
+
827
+ Arguments
828
+ ---------
829
+ * ``<group_id>``: The ID of the workspace group to delete.
830
+ * ``<group_name>``: The name of the workspace group to delete.
831
+
832
+ Remarks
833
+ -------
834
+ * Specify the ``IF EXISTS`` clause to attempt the delete operation
835
+ only if a workspace group with the specified ID or name exists.
836
+ * Use the ``WAIT ON TERMINATED`` clause to pause query execution until
837
+ the workspace group is in the ``TERMINATED`` state.
838
+ * If the ``FORCE`` clause is specified, the workspace group is
839
+ terminated even if it contains workspaces.
840
+
841
+ Example
842
+ -------
843
+ The following command deletes a workspace group named **wsg1** even
844
+ if it contains workspaces::
845
+
846
+ DROP WORKSPACE GROUP 'wsg1' FORCE;
847
+
848
+ See Also
849
+ --------
850
+ * ``DROP WORKSPACE``
851
+
852
+ """
853
+
854
+ def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]:
855
+ try:
856
+ workspace_group = get_workspace_group(params)
857
+ if workspace_group.terminated_at is not None:
858
+ raise KeyError('workspace group is alread terminated')
859
+ workspace_group.terminate(
860
+ wait_on_terminated=params['wait_on_terminated'],
861
+ force=params['force'],
862
+ )
863
+
864
+ except KeyError:
865
+ if not params['if_exists']:
866
+ raise
867
+
868
+ return None
869
+
870
+
871
+ DropWorkspaceGroupHandler.register(overwrite=True)
872
+
873
+
874
+ class DropWorkspaceHandler(SQLHandler):
875
+ """
876
+ DROP WORKSPACE [ if_exists ]
877
+ workspace
878
+ [ in_group ]
879
+ [ wait_on_terminated ];
880
+
881
+ # Only drop workspace if it exists
882
+ if_exists = IF EXISTS
883
+
884
+ # Workspace
885
+ workspace = { workspace_id | workspace_name }
886
+
887
+ # ID of workspace
888
+ workspace_id = ID '<workspace-id>'
889
+
890
+ # Name of workspace
891
+ workspace_name = '<workspace-name>'
892
+
893
+ # Workspace group
894
+ in_group = IN GROUP { group_id | group_name }
895
+
896
+ # ID of workspace group
897
+ group_id = ID '<group-id>'
898
+
899
+ # Name of workspace group
900
+ group_name = '<group-name>'
901
+
902
+ # Wait for workspace to be terminated before continuing
903
+ wait_on_terminated = WAIT ON TERMINATED
904
+
905
+ Description
906
+ -----------
907
+ Deletes a workspace.
908
+
909
+ Arguments
910
+ ---------
911
+ * ``<workspace-id>``: The ID of the workspace to delete.
912
+ * ``<workspace-name>``: The name of the workspace to delete.
913
+ * ``<group_id>``: The ID of the workspace group that contains
914
+ the workspace.
915
+ * ``<group_name>``: The name of the workspace group that
916
+ contains the workspace.
917
+
918
+ Remarks
919
+ -------
920
+ * Specify the ``IF EXISTS`` clause to attempt the delete operation
921
+ only if a workspace with the specified ID or name exists.
922
+ * Use the ``IN GROUP`` clause to specify the ID or name of the workspace
923
+ group that contains the workspace to delete.
924
+ * Use the ``WAIT ON TERMINATED`` clause to pause query execution until
925
+ the workspace is in the ``TERMINATED`` state.
926
+ * All databases attached to the workspace are detached when the
927
+ workspace is deleted (terminated).
928
+
929
+ Example
930
+ -------
931
+ The following example deletes a workspace named **examplews** in
932
+ a workspace group **wsg1**::
933
+
934
+ DROP WORKSPACE IF EXISTS 'examplews' IN GROUP 'wsg1';
935
+
936
+ See Also
937
+ --------
938
+ * ``DROP WORKSPACE GROUP``
939
+
940
+ """
941
+
942
+ def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]:
943
+ try:
944
+ ws = get_workspace(params)
945
+ if ws.terminated_at is not None:
946
+ raise KeyError('workspace is already terminated')
947
+ ws.terminate(wait_on_terminated=params['wait_on_terminated'])
948
+
949
+ except KeyError:
950
+ if not params['if_exists']:
951
+ raise
952
+
953
+ return None
954
+
955
+
956
+ DropWorkspaceHandler.register(overwrite=True)