singlestoredb 0.4.0__py3-none-any.whl → 1.0.4__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.

Potentially problematic release.


This version of singlestoredb might be problematic. Click here for more details.

Files changed (120) hide show
  1. singlestoredb/__init__.py +33 -1
  2. singlestoredb/alchemy/__init__.py +90 -0
  3. singlestoredb/auth.py +5 -1
  4. singlestoredb/config.py +116 -14
  5. singlestoredb/connection.py +483 -516
  6. singlestoredb/converters.py +238 -135
  7. singlestoredb/exceptions.py +30 -2
  8. singlestoredb/functions/__init__.py +1 -0
  9. singlestoredb/functions/decorator.py +142 -0
  10. singlestoredb/functions/dtypes.py +1639 -0
  11. singlestoredb/functions/ext/__init__.py +2 -0
  12. singlestoredb/functions/ext/arrow.py +375 -0
  13. singlestoredb/functions/ext/asgi.py +661 -0
  14. singlestoredb/functions/ext/json.py +427 -0
  15. singlestoredb/functions/ext/mmap.py +306 -0
  16. singlestoredb/functions/ext/rowdat_1.py +744 -0
  17. singlestoredb/functions/signature.py +673 -0
  18. singlestoredb/fusion/__init__.py +11 -0
  19. singlestoredb/fusion/graphql.py +213 -0
  20. singlestoredb/fusion/handler.py +621 -0
  21. singlestoredb/fusion/handlers/stage.py +257 -0
  22. singlestoredb/fusion/handlers/utils.py +162 -0
  23. singlestoredb/fusion/handlers/workspace.py +412 -0
  24. singlestoredb/fusion/registry.py +164 -0
  25. singlestoredb/fusion/result.py +399 -0
  26. singlestoredb/http/__init__.py +27 -0
  27. singlestoredb/{http.py → http/connection.py} +555 -154
  28. singlestoredb/management/__init__.py +3 -0
  29. singlestoredb/management/billing_usage.py +148 -0
  30. singlestoredb/management/cluster.py +14 -6
  31. singlestoredb/management/manager.py +100 -38
  32. singlestoredb/management/organization.py +188 -0
  33. singlestoredb/management/region.py +5 -5
  34. singlestoredb/management/utils.py +281 -2
  35. singlestoredb/management/workspace.py +1344 -49
  36. singlestoredb/{clients/pymysqlsv → mysql}/__init__.py +16 -21
  37. singlestoredb/{clients/pymysqlsv → mysql}/_auth.py +39 -8
  38. singlestoredb/{clients/pymysqlsv → mysql}/charset.py +26 -23
  39. singlestoredb/{clients/pymysqlsv/connections.py → mysql/connection.py} +532 -165
  40. singlestoredb/{clients/pymysqlsv → mysql}/constants/CLIENT.py +0 -1
  41. singlestoredb/{clients/pymysqlsv → mysql}/constants/COMMAND.py +0 -1
  42. singlestoredb/{clients/pymysqlsv → mysql}/constants/CR.py +0 -2
  43. singlestoredb/{clients/pymysqlsv → mysql}/constants/ER.py +0 -1
  44. singlestoredb/{clients/pymysqlsv → mysql}/constants/FIELD_TYPE.py +1 -1
  45. singlestoredb/{clients/pymysqlsv → mysql}/constants/FLAG.py +0 -1
  46. singlestoredb/{clients/pymysqlsv → mysql}/constants/SERVER_STATUS.py +0 -1
  47. singlestoredb/mysql/converters.py +271 -0
  48. singlestoredb/{clients/pymysqlsv → mysql}/cursors.py +228 -112
  49. singlestoredb/mysql/err.py +92 -0
  50. singlestoredb/{clients/pymysqlsv → mysql}/optionfile.py +5 -4
  51. singlestoredb/{clients/pymysqlsv → mysql}/protocol.py +49 -20
  52. singlestoredb/mysql/tests/__init__.py +19 -0
  53. singlestoredb/{clients/pymysqlsv → mysql}/tests/base.py +32 -12
  54. singlestoredb/mysql/tests/conftest.py +37 -0
  55. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_DictCursor.py +11 -7
  56. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_SSCursor.py +17 -12
  57. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_basic.py +32 -24
  58. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_connection.py +130 -119
  59. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_converters.py +9 -7
  60. singlestoredb/mysql/tests/test_cursor.py +141 -0
  61. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_err.py +3 -2
  62. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_issues.py +35 -27
  63. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_load_local.py +13 -11
  64. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_nextset.py +7 -3
  65. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_optionfile.py +2 -1
  66. singlestoredb/{clients/pymysqlsv → mysql}/tests/thirdparty/__init__.py +1 -1
  67. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/__init__.py +9 -0
  68. singlestoredb/{clients/pymysqlsv → mysql}/tests/thirdparty/test_MySQLdb/capabilities.py +19 -17
  69. singlestoredb/{clients/pymysqlsv → mysql}/tests/thirdparty/test_MySQLdb/dbapi20.py +31 -22
  70. singlestoredb/{clients/pymysqlsv → mysql}/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py +3 -4
  71. singlestoredb/{clients/pymysqlsv → mysql}/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py +24 -20
  72. singlestoredb/{clients/pymysqlsv → mysql}/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py +4 -4
  73. singlestoredb/{clients/pymysqlsv → mysql}/times.py +3 -4
  74. singlestoredb/pytest.py +283 -0
  75. singlestoredb/tests/empty.sql +0 -0
  76. singlestoredb/tests/ext_funcs/__init__.py +385 -0
  77. singlestoredb/tests/test.sql +210 -0
  78. singlestoredb/tests/test2.sql +1 -0
  79. singlestoredb/tests/test_basics.py +482 -115
  80. singlestoredb/tests/test_config.py +13 -13
  81. singlestoredb/tests/test_connection.py +241 -305
  82. singlestoredb/tests/test_dbapi.py +27 -0
  83. singlestoredb/tests/test_ext_func.py +1193 -0
  84. singlestoredb/tests/test_ext_func_data.py +1101 -0
  85. singlestoredb/tests/test_fusion.py +465 -0
  86. singlestoredb/tests/test_http.py +32 -26
  87. singlestoredb/tests/test_management.py +588 -8
  88. singlestoredb/tests/test_plugin.py +33 -0
  89. singlestoredb/tests/test_results.py +11 -12
  90. singlestoredb/tests/test_udf.py +687 -0
  91. singlestoredb/tests/utils.py +3 -2
  92. singlestoredb/utils/config.py +58 -0
  93. singlestoredb/utils/debug.py +13 -0
  94. singlestoredb/utils/mogrify.py +151 -0
  95. singlestoredb/utils/results.py +4 -1
  96. singlestoredb-1.0.4.dist-info/METADATA +139 -0
  97. singlestoredb-1.0.4.dist-info/RECORD +112 -0
  98. {singlestoredb-0.4.0.dist-info → singlestoredb-1.0.4.dist-info}/WHEEL +1 -1
  99. singlestoredb-1.0.4.dist-info/entry_points.txt +2 -0
  100. singlestoredb/clients/pymysqlsv/converters.py +0 -365
  101. singlestoredb/clients/pymysqlsv/err.py +0 -144
  102. singlestoredb/clients/pymysqlsv/tests/__init__.py +0 -19
  103. singlestoredb/clients/pymysqlsv/tests/test_cursor.py +0 -133
  104. singlestoredb/clients/pymysqlsv/tests/thirdparty/test_MySQLdb/__init__.py +0 -9
  105. singlestoredb/drivers/__init__.py +0 -45
  106. singlestoredb/drivers/base.py +0 -198
  107. singlestoredb/drivers/cymysql.py +0 -38
  108. singlestoredb/drivers/http.py +0 -47
  109. singlestoredb/drivers/mariadb.py +0 -40
  110. singlestoredb/drivers/mysqlconnector.py +0 -49
  111. singlestoredb/drivers/mysqldb.py +0 -60
  112. singlestoredb/drivers/pymysql.py +0 -37
  113. singlestoredb/drivers/pymysqlsv.py +0 -35
  114. singlestoredb/drivers/pyodbc.py +0 -65
  115. singlestoredb-0.4.0.dist-info/METADATA +0 -111
  116. singlestoredb-0.4.0.dist-info/RECORD +0 -86
  117. /singlestoredb/{clients → fusion/handlers}/__init__.py +0 -0
  118. /singlestoredb/{clients/pymysqlsv → mysql}/constants/__init__.py +0 -0
  119. {singlestoredb-0.4.0.dist-info → singlestoredb-1.0.4.dist-info}/LICENSE +0 -0
  120. {singlestoredb-0.4.0.dist-info → singlestoredb-1.0.4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,687 @@
1
+ #!/usr/bin/env python
2
+ # type: ignore
3
+ """SingleStoreDB UDF testing."""
4
+ import datetime
5
+ import re
6
+ import unittest
7
+ from typing import List
8
+ from typing import Optional
9
+ from typing import Tuple
10
+ from typing import TypeVar
11
+ from typing import Union
12
+
13
+ import numpy as np
14
+
15
+ from ..functions import dtypes as dt
16
+ from ..functions import signature as sig
17
+ from ..functions import udf
18
+
19
+
20
+ A = TypeVar('A', bytearray, bytes, None)
21
+ B = TypeVar('B', int, float, np.int64, np.int32, np.uint16)
22
+ C = TypeVar('C', B, np.int8)
23
+ D = TypeVar('D', bound=str)
24
+ E = Optional[List[Optional[Union[float, int]]]]
25
+
26
+
27
+ def to_sql(x):
28
+ out = sig.signature_to_sql(sig.get_signature(x))
29
+ out = re.sub(r'^CREATE EXTERNAL FUNCTION ', r'', out)
30
+ out = re.sub(r' AS REMOTE SERVICE.+$', r'', out)
31
+ return out
32
+
33
+
34
+ class TestUDF(unittest.TestCase):
35
+
36
+ def test_return_annotations(self):
37
+
38
+ # No annotations
39
+ def foo(): ...
40
+ with self.assertRaises(TypeError):
41
+ to_sql(foo)
42
+
43
+ # NULL return value
44
+ def foo() -> None: ...
45
+ assert to_sql(foo) == '`foo`() RETURNS NULL'
46
+
47
+ # Simple return value
48
+ def foo() -> int: ...
49
+ assert to_sql(foo) == '`foo`() RETURNS BIGINT NOT NULL'
50
+
51
+ # Simple return value
52
+ def foo() -> np.int8: ...
53
+ assert to_sql(foo) == '`foo`() RETURNS TINYINT NOT NULL'
54
+
55
+ # Optional return value
56
+ def foo() -> Optional[int]: ...
57
+ assert to_sql(foo) == '`foo`() RETURNS BIGINT NULL'
58
+
59
+ # Optional return value
60
+ def foo() -> Union[int, None]: ...
61
+ assert to_sql(foo) == '`foo`() RETURNS BIGINT NULL'
62
+
63
+ # Optional return value with multiple types
64
+ def foo() -> Union[int, float, None]: ...
65
+ assert to_sql(foo) == '`foo`() RETURNS DOUBLE NULL'
66
+
67
+ # Optional return value with custom type
68
+ def foo() -> Optional[B]: ...
69
+ assert to_sql(foo) == '`foo`() RETURNS DOUBLE NULL'
70
+
71
+ # Optional return value with nested custom type
72
+ def foo() -> Optional[C]: ...
73
+ assert to_sql(foo) == '`foo`() RETURNS DOUBLE NULL'
74
+
75
+ # Optional return value with collection type
76
+ def foo() -> Optional[List[str]]: ...
77
+ assert to_sql(foo) == '`foo`() RETURNS ARRAY(TEXT NOT NULL) NULL'
78
+
79
+ # Optional return value with nested collection type
80
+ def foo() -> Optional[List[List[str]]]: ...
81
+ assert to_sql(foo) == '`foo`() RETURNS ARRAY(ARRAY(TEXT NOT NULL) NOT NULL) NULL'
82
+
83
+ # Optional return value with collection type with nulls
84
+ def foo() -> Optional[List[Optional[str]]]: ...
85
+ assert to_sql(foo) == '`foo`() RETURNS ARRAY(TEXT NULL) NULL'
86
+
87
+ # Custom type with bound
88
+ def foo() -> D: ...
89
+ assert to_sql(foo) == '`foo`() RETURNS TEXT NOT NULL'
90
+
91
+ # Return value with custom collection type with nulls
92
+ def foo() -> E: ...
93
+ assert to_sql(foo) == '`foo`() RETURNS ARRAY(DOUBLE NULL) NULL'
94
+
95
+ # Incompatible types
96
+ def foo() -> Union[int, str]: ...
97
+ with self.assertRaises(TypeError):
98
+ to_sql(foo)
99
+
100
+ # Tuple
101
+ def foo() -> Tuple[int, float, str]: ...
102
+ assert to_sql(foo) == '`foo`() RETURNS RECORD(a BIGINT NOT NULL, ' \
103
+ 'b DOUBLE NOT NULL, ' \
104
+ 'c TEXT NOT NULL) NOT NULL'
105
+
106
+ # Optional tuple
107
+ def foo() -> Optional[Tuple[int, float, str]]: ...
108
+ assert to_sql(foo) == '`foo`() RETURNS RECORD(a BIGINT NOT NULL, ' \
109
+ 'b DOUBLE NOT NULL, ' \
110
+ 'c TEXT NOT NULL) NULL'
111
+
112
+ # Optional tuple with optional element
113
+ def foo() -> Optional[Tuple[int, float, Optional[str]]]: ...
114
+ assert to_sql(foo) == '`foo`() RETURNS RECORD(a BIGINT NOT NULL, ' \
115
+ 'b DOUBLE NOT NULL, ' \
116
+ 'c TEXT NULL) NULL'
117
+
118
+ # Optional tuple with optional union element
119
+ def foo() -> Optional[Tuple[int, Optional[Union[float, int]], str]]: ...
120
+ assert to_sql(foo) == '`foo`() RETURNS RECORD(a BIGINT NOT NULL, ' \
121
+ 'b DOUBLE NULL, ' \
122
+ 'c TEXT NOT NULL) NULL'
123
+
124
+ # Unknown type
125
+ def foo() -> set: ...
126
+ with self.assertRaises(TypeError) as exc:
127
+ to_sql(foo)
128
+ assert 'unsupported type annotation' in str(exc.exception)
129
+
130
+ def test_parameter_annotations(self):
131
+
132
+ # No annotations
133
+ def foo(x) -> None: ...
134
+ with self.assertRaises(TypeError):
135
+ to_sql(foo)
136
+
137
+ # Simple parameter
138
+ def foo(x: int) -> None: ...
139
+ assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) RETURNS NULL'
140
+
141
+ # Optional parameter
142
+ def foo(x: Optional[int]) -> None: ...
143
+ assert to_sql(foo) == '`foo`(`x` BIGINT NULL) RETURNS NULL'
144
+
145
+ # Optional parameter
146
+ def foo(x: Union[int, None]) -> None: ...
147
+ assert to_sql(foo) == '`foo`(`x` BIGINT NULL) RETURNS NULL'
148
+
149
+ # Optional multiple parameter types
150
+ def foo(x: Union[int, float, None]) -> None: ...
151
+ assert to_sql(foo) == '`foo`(`x` DOUBLE NULL) RETURNS NULL'
152
+
153
+ # Optional parameter with custom type
154
+ def foo(x: Optional[B]) -> None: ...
155
+ assert to_sql(foo) == '`foo`(`x` DOUBLE NULL) RETURNS NULL'
156
+
157
+ # Optional parameter with nested custom type
158
+ def foo(x: Optional[C]) -> None: ...
159
+ assert to_sql(foo) == '`foo`(`x` DOUBLE NULL) RETURNS NULL'
160
+
161
+ # Optional parameter with collection type
162
+ def foo(x: Optional[List[str]]) -> None: ...
163
+ assert to_sql(foo) == '`foo`(`x` ARRAY(TEXT NOT NULL) NULL) RETURNS NULL'
164
+
165
+ # Optional parameter with nested collection type
166
+ def foo(x: Optional[List[List[str]]]) -> None: ...
167
+ assert to_sql(foo) == '`foo`(`x` ARRAY(ARRAY(TEXT NOT NULL) NOT NULL) NULL) ' \
168
+ 'RETURNS NULL'
169
+
170
+ # Optional parameter with collection type with nulls
171
+ def foo(x: Optional[List[Optional[str]]]) -> None: ...
172
+ assert to_sql(foo) == '`foo`(`x` ARRAY(TEXT NULL) NULL) RETURNS NULL'
173
+
174
+ # Custom type with bound
175
+ def foo(x: D) -> None: ...
176
+ assert to_sql(foo) == '`foo`(`x` TEXT NOT NULL) RETURNS NULL'
177
+
178
+ # Incompatible types
179
+ def foo(x: Union[int, str]) -> None: ...
180
+ with self.assertRaises(TypeError):
181
+ to_sql(foo)
182
+
183
+ # Tuple
184
+ def foo(x: Tuple[int, float, str]) -> None: ...
185
+ assert to_sql(foo) == '`foo`(`x` RECORD(a BIGINT NOT NULL, ' \
186
+ 'b DOUBLE NOT NULL, ' \
187
+ 'c TEXT NOT NULL) NOT NULL) RETURNS NULL'
188
+
189
+ # Optional tuple with optional element
190
+ def foo(x: Optional[Tuple[int, float, Optional[str]]]) -> None: ...
191
+ assert to_sql(foo) == '`foo`(`x` RECORD(a BIGINT NOT NULL, ' \
192
+ 'b DOUBLE NOT NULL, ' \
193
+ 'c TEXT NULL) NULL) RETURNS NULL'
194
+
195
+ # Optional tuple with optional union element
196
+ def foo(x: Optional[Tuple[int, Optional[Union[float, int]], str]]) -> None: ...
197
+ assert to_sql(foo) == '`foo`(`x` RECORD(a BIGINT NOT NULL, ' \
198
+ 'b DOUBLE NULL, ' \
199
+ 'c TEXT NOT NULL) NULL) RETURNS NULL'
200
+
201
+ # Unknown type
202
+ def foo(x: set) -> None: ...
203
+ with self.assertRaises(TypeError) as exc:
204
+ to_sql(foo)
205
+ assert 'unsupported type annotation' in str(exc.exception)
206
+
207
+ def test_datetimes(self):
208
+
209
+ # Datetime
210
+ def foo(x: datetime.datetime) -> None: ...
211
+ assert to_sql(foo) == '`foo`(`x` DATETIME NOT NULL) RETURNS NULL'
212
+
213
+ # Date
214
+ def foo(x: datetime.date) -> None: ...
215
+ assert to_sql(foo) == '`foo`(`x` DATE NOT NULL) RETURNS NULL'
216
+
217
+ # Time
218
+ def foo(x: datetime.timedelta) -> None: ...
219
+ assert to_sql(foo) == '`foo`(`x` TIME NOT NULL) RETURNS NULL'
220
+
221
+ # Datetime + Date
222
+ def foo(x: Union[datetime.datetime, datetime.date]) -> None: ...
223
+ with self.assertRaises(TypeError):
224
+ to_sql(foo)
225
+
226
+ def test_numerics(self):
227
+ #
228
+ # Ints
229
+ #
230
+ def foo(x: int) -> None: ...
231
+ assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) RETURNS NULL'
232
+
233
+ def foo(x: np.int8) -> None: ...
234
+ assert to_sql(foo) == '`foo`(`x` TINYINT NOT NULL) RETURNS NULL'
235
+
236
+ def foo(x: np.int16) -> None: ...
237
+ assert to_sql(foo) == '`foo`(`x` SMALLINT NOT NULL) RETURNS NULL'
238
+
239
+ def foo(x: np.int32) -> None: ...
240
+ assert to_sql(foo) == '`foo`(`x` INT NOT NULL) RETURNS NULL'
241
+
242
+ def foo(x: np.int64) -> None: ...
243
+ assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) RETURNS NULL'
244
+
245
+ #
246
+ # Unsigned ints
247
+ #
248
+ def foo(x: np.uint8) -> None: ...
249
+ assert to_sql(foo) == '`foo`(`x` TINYINT UNSIGNED NOT NULL) RETURNS NULL'
250
+
251
+ def foo(x: np.uint16) -> None: ...
252
+ assert to_sql(foo) == '`foo`(`x` SMALLINT UNSIGNED NOT NULL) RETURNS NULL'
253
+
254
+ def foo(x: np.uint32) -> None: ...
255
+ assert to_sql(foo) == '`foo`(`x` INT UNSIGNED NOT NULL) RETURNS NULL'
256
+
257
+ def foo(x: np.uint64) -> None: ...
258
+ assert to_sql(foo) == '`foo`(`x` BIGINT UNSIGNED NOT NULL) RETURNS NULL'
259
+
260
+ #
261
+ # Floats
262
+ #
263
+ def foo(x: float) -> None: ...
264
+ assert to_sql(foo) == '`foo`(`x` DOUBLE NOT NULL) RETURNS NULL'
265
+
266
+ def foo(x: np.float32) -> None: ...
267
+ assert to_sql(foo) == '`foo`(`x` FLOAT NOT NULL) RETURNS NULL'
268
+
269
+ def foo(x: np.float64) -> None: ...
270
+ assert to_sql(foo) == '`foo`(`x` DOUBLE NOT NULL) RETURNS NULL'
271
+
272
+ #
273
+ # Type collapsing
274
+ #
275
+ def foo(x: Union[np.int8, np.int16]) -> None: ...
276
+ assert to_sql(foo) == '`foo`(`x` SMALLINT NOT NULL) RETURNS NULL'
277
+
278
+ def foo(x: Union[np.int64, np.double]) -> None: ...
279
+ assert to_sql(foo) == '`foo`(`x` DOUBLE NOT NULL) RETURNS NULL'
280
+
281
+ def foo(x: Union[int, float]) -> None: ...
282
+ assert to_sql(foo) == '`foo`(`x` DOUBLE NOT NULL) RETURNS NULL'
283
+
284
+ def test_positional_and_keyword_parameters(self):
285
+ # Keyword only
286
+ def foo(x: int = 100) -> None: ...
287
+ assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL DEFAULT 100) RETURNS NULL'
288
+
289
+ # Multiple keywords
290
+ def foo(x: int = 100, y: float = 3.14) -> None: ...
291
+ assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL DEFAULT 100, ' \
292
+ '`y` DOUBLE NOT NULL DEFAULT 3.14e0) RETURNS NULL'
293
+
294
+ # Keywords and positional
295
+ def foo(a: str, b: str, x: int = 100, y: float = 3.14) -> None: ...
296
+ assert to_sql(foo) == '`foo`(`a` TEXT NOT NULL, ' \
297
+ '`b` TEXT NOT NULL, ' \
298
+ '`x` BIGINT NOT NULL DEFAULT 100, ' \
299
+ '`y` DOUBLE NOT NULL DEFAULT 3.14e0) RETURNS NULL'
300
+
301
+ # Variable positional
302
+ def foo(*args: int) -> None: ...
303
+ with self.assertRaises(TypeError):
304
+ to_sql(foo)
305
+
306
+ # Variable keywords
307
+ def foo(x: int = 100, **kwargs: float) -> None: ...
308
+ with self.assertRaises(TypeError):
309
+ to_sql(foo)
310
+
311
+ def test_udf(self):
312
+
313
+ # No parameters
314
+ @udf
315
+ def foo(x: int) -> int: ...
316
+ assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) RETURNS BIGINT NOT NULL'
317
+
318
+ # No parameters
319
+ @udf()
320
+ def foo(x: int) -> int: ...
321
+ assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) RETURNS BIGINT NOT NULL'
322
+
323
+ # Override return value with callable
324
+ @udf(returns=dt.SMALLINT)
325
+ def foo(x: int) -> int: ...
326
+ assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) RETURNS SMALLINT NULL'
327
+
328
+ # Override return value with string
329
+ @udf(returns=dt.SMALLINT(nullable=False))
330
+ def foo(x: int) -> int: ...
331
+ assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) RETURNS SMALLINT NOT NULL'
332
+
333
+ # Override multiple params with one type
334
+ @udf(args=dt.SMALLINT(nullable=False))
335
+ def foo(x: int, y: float, z: np.int8) -> int: ...
336
+ assert to_sql(foo) == '`foo`(`x` SMALLINT NOT NULL, ' \
337
+ '`y` SMALLINT NOT NULL, ' \
338
+ '`z` SMALLINT NOT NULL) RETURNS BIGINT NOT NULL'
339
+
340
+ # Override with list
341
+ @udf(args=[dt.SMALLINT, dt.FLOAT, dt.CHAR(30)])
342
+ def foo(x: int, y: float, z: str) -> int: ...
343
+ assert to_sql(foo) == '`foo`(`x` SMALLINT NULL, ' \
344
+ '`y` FLOAT NULL, ' \
345
+ '`z` CHAR(30) NULL) RETURNS BIGINT NOT NULL'
346
+
347
+ # Override with too short of a list
348
+ @udf(args=[dt.SMALLINT, dt.FLOAT])
349
+ def foo(x: int, y: float, z: str) -> int: ...
350
+ with self.assertRaises(TypeError):
351
+ to_sql(foo)
352
+
353
+ # Override with too long of a list
354
+ @udf(args=[dt.SMALLINT, dt.FLOAT, dt.CHAR(30), dt.TEXT])
355
+ def foo(x: int, y: float, z: str) -> int: ...
356
+ with self.assertRaises(TypeError):
357
+ to_sql(foo)
358
+
359
+ # Override with list
360
+ @udf(args=[dt.SMALLINT, dt.FLOAT, dt.CHAR(30)])
361
+ def foo(x: int, y: float, z: str) -> int: ...
362
+ assert to_sql(foo) == '`foo`(`x` SMALLINT NULL, ' \
363
+ '`y` FLOAT NULL, ' \
364
+ '`z` CHAR(30) NULL) RETURNS BIGINT NOT NULL'
365
+
366
+ # Override with dict
367
+ @udf(args=dict(x=dt.SMALLINT, z=dt.CHAR(30)))
368
+ def foo(x: int, y: float, z: str) -> int: ...
369
+ assert to_sql(foo) == '`foo`(`x` SMALLINT NULL, ' \
370
+ '`y` DOUBLE NOT NULL, ' \
371
+ '`z` CHAR(30) NULL) RETURNS BIGINT NOT NULL'
372
+
373
+ # Override with empty dict
374
+ @udf(args=dict())
375
+ def foo(x: int, y: float, z: str) -> int: ...
376
+ assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL, ' \
377
+ '`y` DOUBLE NOT NULL, ' \
378
+ '`z` TEXT NOT NULL) RETURNS BIGINT NOT NULL'
379
+
380
+ # Override with dict with extra keys
381
+ @udf(args=dict(bar=dt.INT))
382
+ def foo(x: int, y: float, z: str) -> int: ...
383
+ assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL, ' \
384
+ '`y` DOUBLE NOT NULL, ' \
385
+ '`z` TEXT NOT NULL) RETURNS BIGINT NOT NULL'
386
+
387
+ # Override parameters and return value
388
+ @udf(args=dict(x=dt.SMALLINT, z=dt.CHAR(30)), returns=dt.SMALLINT(nullable=False))
389
+ def foo(x: int, y: float, z: str) -> int: ...
390
+ assert to_sql(foo) == '`foo`(`x` SMALLINT NULL, ' \
391
+ '`y` DOUBLE NOT NULL, ' \
392
+ '`z` CHAR(30) NULL) RETURNS SMALLINT NOT NULL'
393
+
394
+ # Override parameter with incorrect type
395
+ with self.assertRaises(TypeError):
396
+ @udf(args=dict(x=int))
397
+ def foo(x: int, y: float, z: str) -> int: ...
398
+
399
+ # Override return value with incorrect type
400
+ with self.assertRaises(TypeError):
401
+ @udf(returns=int)
402
+ def foo(x: int, y: float, z: str) -> int: ...
403
+
404
+ # Change function name
405
+ @udf(name='hello_world')
406
+ def foo(x: int) -> int: ...
407
+ assert to_sql(foo) == '`hello_world`(`x` BIGINT NOT NULL) ' \
408
+ 'RETURNS BIGINT NOT NULL'
409
+
410
+ @udf(name='hello`_`world')
411
+ def foo(x: int) -> int: ...
412
+ assert to_sql(foo) == '`hello``_``world`(`x` BIGINT NOT NULL) ' \
413
+ 'RETURNS BIGINT NOT NULL'
414
+
415
+ def test_dtypes(self):
416
+ assert dt.BOOL() == 'BOOL NULL'
417
+ assert dt.BOOL(nullable=False) == 'BOOL NOT NULL'
418
+ assert dt.BOOL(default=False) == 'BOOL NULL DEFAULT 0'
419
+ assert dt.BOOL(default=True) == 'BOOL NULL DEFAULT 1'
420
+ assert dt.BOOL(default='a') == 'BOOL NULL DEFAULT 1'
421
+
422
+ assert dt.BOOLEAN() == 'BOOLEAN NULL'
423
+ assert dt.BOOLEAN(nullable=False) == 'BOOLEAN NOT NULL'
424
+ assert dt.BOOLEAN(default=False) == 'BOOLEAN NULL DEFAULT 0'
425
+ assert dt.BOOLEAN(default=True) == 'BOOLEAN NULL DEFAULT 1'
426
+ assert dt.BOOLEAN(default='a') == 'BOOLEAN NULL DEFAULT 1'
427
+
428
+ assert dt.BIT() == 'BIT NULL'
429
+ assert dt.BIT(nullable=False) == 'BIT NOT NULL'
430
+ assert dt.BIT(default=100) == 'BIT NULL DEFAULT 100'
431
+
432
+ assert dt.TINYINT() == 'TINYINT NULL'
433
+ assert dt.TINYINT(5) == 'TINYINT(5) NULL'
434
+ assert dt.TINYINT(nullable=False) == 'TINYINT NOT NULL'
435
+ assert dt.TINYINT(default=100) == 'TINYINT NULL DEFAULT 100'
436
+ assert dt.TINYINT(unsigned=True, default=100) == \
437
+ 'TINYINT UNSIGNED NULL DEFAULT 100'
438
+
439
+ assert dt.TINYINT_UNSIGNED() == 'TINYINT UNSIGNED NULL'
440
+ assert dt.TINYINT_UNSIGNED(5) == 'TINYINT(5) UNSIGNED NULL'
441
+ assert dt.TINYINT_UNSIGNED(nullable=False) == 'TINYINT UNSIGNED NOT NULL'
442
+ assert dt.TINYINT_UNSIGNED(default=100) == 'TINYINT UNSIGNED NULL DEFAULT 100'
443
+
444
+ assert dt.SMALLINT() == 'SMALLINT NULL'
445
+ assert dt.SMALLINT(5) == 'SMALLINT(5) NULL'
446
+ assert dt.SMALLINT(nullable=False) == 'SMALLINT NOT NULL'
447
+ assert dt.SMALLINT(default=100) == 'SMALLINT NULL DEFAULT 100'
448
+ assert dt.SMALLINT(unsigned=True, default=100) == \
449
+ 'SMALLINT UNSIGNED NULL DEFAULT 100'
450
+
451
+ assert dt.SMALLINT_UNSIGNED() == 'SMALLINT UNSIGNED NULL'
452
+ assert dt.SMALLINT_UNSIGNED(5) == 'SMALLINT(5) UNSIGNED NULL'
453
+ assert dt.SMALLINT_UNSIGNED(nullable=False) == 'SMALLINT UNSIGNED NOT NULL'
454
+ assert dt.SMALLINT_UNSIGNED(default=100) == \
455
+ 'SMALLINT UNSIGNED NULL DEFAULT 100'
456
+
457
+ assert dt.MEDIUMINT() == 'MEDIUMINT NULL'
458
+ assert dt.MEDIUMINT(5) == 'MEDIUMINT(5) NULL'
459
+ assert dt.MEDIUMINT(nullable=False) == 'MEDIUMINT NOT NULL'
460
+ assert dt.MEDIUMINT(default=100) == 'MEDIUMINT NULL DEFAULT 100'
461
+ assert dt.MEDIUMINT(unsigned=True, default=100) == \
462
+ 'MEDIUMINT UNSIGNED NULL DEFAULT 100'
463
+
464
+ assert dt.MEDIUMINT_UNSIGNED() == 'MEDIUMINT UNSIGNED NULL'
465
+ assert dt.MEDIUMINT_UNSIGNED(5) == 'MEDIUMINT(5) UNSIGNED NULL'
466
+ assert dt.MEDIUMINT_UNSIGNED(nullable=False) == 'MEDIUMINT UNSIGNED NOT NULL'
467
+ assert dt.MEDIUMINT_UNSIGNED(default=100) == \
468
+ 'MEDIUMINT UNSIGNED NULL DEFAULT 100'
469
+
470
+ assert dt.INT() == 'INT NULL'
471
+ assert dt.INT(5) == 'INT(5) NULL'
472
+ assert dt.INT(nullable=False) == 'INT NOT NULL'
473
+ assert dt.INT(default=100) == 'INT NULL DEFAULT 100'
474
+ assert dt.INT(unsigned=True, default=100) == \
475
+ 'INT UNSIGNED NULL DEFAULT 100'
476
+
477
+ assert dt.INT_UNSIGNED() == 'INT UNSIGNED NULL'
478
+ assert dt.INT_UNSIGNED(5) == 'INT(5) UNSIGNED NULL'
479
+ assert dt.INT_UNSIGNED(nullable=False) == 'INT UNSIGNED NOT NULL'
480
+ assert dt.INT_UNSIGNED(default=100) == \
481
+ 'INT UNSIGNED NULL DEFAULT 100'
482
+
483
+ assert dt.INTEGER() == 'INTEGER NULL'
484
+ assert dt.INTEGER(5) == 'INTEGER(5) NULL'
485
+ assert dt.INTEGER(nullable=False) == 'INTEGER NOT NULL'
486
+ assert dt.INTEGER(default=100) == 'INTEGER NULL DEFAULT 100'
487
+ assert dt.INTEGER(unsigned=True, default=100) == \
488
+ 'INTEGER UNSIGNED NULL DEFAULT 100'
489
+
490
+ assert dt.INTEGER_UNSIGNED() == 'INTEGER UNSIGNED NULL'
491
+ assert dt.INTEGER_UNSIGNED(5) == 'INTEGER(5) UNSIGNED NULL'
492
+ assert dt.INTEGER_UNSIGNED(nullable=False) == 'INTEGER UNSIGNED NOT NULL'
493
+ assert dt.INTEGER_UNSIGNED(default=100) == \
494
+ 'INTEGER UNSIGNED NULL DEFAULT 100'
495
+
496
+ assert dt.BIGINT() == 'BIGINT NULL'
497
+ assert dt.BIGINT(5) == 'BIGINT(5) NULL'
498
+ assert dt.BIGINT(nullable=False) == 'BIGINT NOT NULL'
499
+ assert dt.BIGINT(default=100) == 'BIGINT NULL DEFAULT 100'
500
+ assert dt.BIGINT(unsigned=True, default=100) == \
501
+ 'BIGINT UNSIGNED NULL DEFAULT 100'
502
+
503
+ assert dt.BIGINT_UNSIGNED() == 'BIGINT UNSIGNED NULL'
504
+ assert dt.BIGINT_UNSIGNED(5) == 'BIGINT(5) UNSIGNED NULL'
505
+ assert dt.BIGINT_UNSIGNED(nullable=False) == 'BIGINT UNSIGNED NOT NULL'
506
+ assert dt.BIGINT_UNSIGNED(default=100) == \
507
+ 'BIGINT UNSIGNED NULL DEFAULT 100'
508
+
509
+ assert dt.BIGINT() == 'BIGINT NULL'
510
+ assert dt.BIGINT(5) == 'BIGINT(5) NULL'
511
+ assert dt.BIGINT(nullable=False) == 'BIGINT NOT NULL'
512
+ assert dt.BIGINT(default=100) == 'BIGINT NULL DEFAULT 100'
513
+ assert dt.BIGINT(unsigned=True, default=100) == \
514
+ 'BIGINT UNSIGNED NULL DEFAULT 100'
515
+
516
+ assert dt.FLOAT() == 'FLOAT NULL'
517
+ assert dt.FLOAT(5) == 'FLOAT(5) NULL'
518
+ assert dt.FLOAT(nullable=False) == 'FLOAT NOT NULL'
519
+ assert dt.FLOAT(default=1.234) == 'FLOAT NULL DEFAULT 1.234e0'
520
+
521
+ assert dt.DOUBLE() == 'DOUBLE NULL'
522
+ assert dt.DOUBLE(5) == 'DOUBLE(5) NULL'
523
+ assert dt.DOUBLE(nullable=False) == 'DOUBLE NOT NULL'
524
+ assert dt.DOUBLE(default=1.234) == 'DOUBLE NULL DEFAULT 1.234e0'
525
+
526
+ assert dt.REAL() == 'REAL NULL'
527
+ assert dt.REAL(5) == 'REAL(5) NULL'
528
+ assert dt.REAL(nullable=False) == 'REAL NOT NULL'
529
+ assert dt.REAL(default=1.234) == 'REAL NULL DEFAULT 1.234e0'
530
+
531
+ with self.assertRaises(TypeError):
532
+ dt.DECIMAL()
533
+ with self.assertRaises(TypeError):
534
+ dt.DECIMAL(5)
535
+ assert dt.DECIMAL(10, 5) == 'DECIMAL(10, 5) NULL'
536
+ assert dt.DECIMAL(10, 5, nullable=False) == 'DECIMAL(10, 5) NOT NULL'
537
+ assert dt.DECIMAL(10, 5, default=1.234) == \
538
+ 'DECIMAL(10, 5) NULL DEFAULT 1.234e0'
539
+
540
+ with self.assertRaises(TypeError):
541
+ dt.DEC()
542
+ with self.assertRaises(TypeError):
543
+ dt.DEC(5)
544
+ assert dt.DEC(10, 5) == 'DEC(10, 5) NULL'
545
+ assert dt.DEC(10, 5, nullable=False) == 'DEC(10, 5) NOT NULL'
546
+ assert dt.DEC(10, 5, default=1.234) == \
547
+ 'DEC(10, 5) NULL DEFAULT 1.234e0'
548
+
549
+ with self.assertRaises(TypeError):
550
+ dt.FIXED()
551
+ with self.assertRaises(TypeError):
552
+ dt.FIXED(5)
553
+ assert dt.FIXED(10, 5) == 'FIXED(10, 5) NULL'
554
+ assert dt.FIXED(10, 5, nullable=False) == 'FIXED(10, 5) NOT NULL'
555
+ assert dt.FIXED(10, 5, default=1.234) == \
556
+ 'FIXED(10, 5) NULL DEFAULT 1.234e0'
557
+
558
+ with self.assertRaises(TypeError):
559
+ dt.NUMERIC()
560
+ with self.assertRaises(TypeError):
561
+ dt.NUMERIC(5)
562
+ assert dt.NUMERIC(10, 5) == 'NUMERIC(10, 5) NULL'
563
+ assert dt.NUMERIC(10, 5, nullable=False) == 'NUMERIC(10, 5) NOT NULL'
564
+ assert dt.NUMERIC(10, 5, default=1.234) == \
565
+ 'NUMERIC(10, 5) NULL DEFAULT 1.234e0'
566
+
567
+ assert dt.DATE() == 'DATE NULL'
568
+ assert dt.DATE(nullable=False) == 'DATE NOT NULL'
569
+ assert dt.DATE(default=datetime.date(2020, 1, 2)) == \
570
+ "DATE NULL DEFAULT '2020-01-02'"
571
+
572
+ assert dt.TIME() == 'TIME NULL'
573
+ assert dt.TIME(6) == 'TIME(6) NULL'
574
+ assert dt.TIME(nullable=False) == 'TIME NOT NULL'
575
+ assert dt.TIME(default=datetime.timedelta(seconds=1000)) == \
576
+ "TIME NULL DEFAULT '00:16:40'"
577
+
578
+ assert dt.DATETIME() == 'DATETIME NULL'
579
+ assert dt.DATETIME(6) == 'DATETIME(6) NULL'
580
+ assert dt.DATETIME(nullable=False) == 'DATETIME NOT NULL'
581
+ assert dt.DATETIME(default=datetime.datetime(2020, 1, 2, 3, 4, 5)) == \
582
+ "DATETIME NULL DEFAULT '2020-01-02 03:04:05'"
583
+
584
+ assert dt.TIMESTAMP() == 'TIMESTAMP NULL'
585
+ assert dt.TIMESTAMP(6) == 'TIMESTAMP(6) NULL'
586
+ assert dt.TIMESTAMP(nullable=False) == 'TIMESTAMP NOT NULL'
587
+ assert dt.TIMESTAMP(default=datetime.datetime(2020, 1, 2, 3, 4, 5)) == \
588
+ "TIMESTAMP NULL DEFAULT '2020-01-02 03:04:05'"
589
+
590
+ assert dt.YEAR() == 'YEAR NULL'
591
+ assert dt.YEAR(nullable=False) == 'YEAR NOT NULL'
592
+ assert dt.YEAR(default=1961) == 'YEAR NULL DEFAULT 1961'
593
+
594
+ assert dt.CHAR() == 'CHAR NULL'
595
+ assert dt.CHAR(10) == 'CHAR(10) NULL'
596
+ assert dt.CHAR(charset=dt.utf8, collate=dt.utf8_bin) == \
597
+ 'CHAR CHARACTER SET utf8 COLLATE utf8_bin NULL'
598
+ assert dt.CHAR(nullable=False) == 'CHAR NOT NULL'
599
+ assert dt.CHAR(default='hi') == "CHAR NULL DEFAULT 'hi'"
600
+
601
+ assert dt.VARCHAR() == 'VARCHAR NULL'
602
+ assert dt.VARCHAR(10) == 'VARCHAR(10) NULL'
603
+ assert dt.VARCHAR(charset=dt.utf8, collate=dt.utf8_bin) == \
604
+ 'VARCHAR CHARACTER SET utf8 COLLATE utf8_bin NULL'
605
+ assert dt.VARCHAR(nullable=False) == 'VARCHAR NOT NULL'
606
+ assert dt.VARCHAR(default='hi') == "VARCHAR NULL DEFAULT 'hi'"
607
+
608
+ assert dt.LONGTEXT() == 'LONGTEXT NULL'
609
+ assert dt.LONGTEXT(10) == 'LONGTEXT(10) NULL'
610
+ assert dt.LONGTEXT(charset=dt.utf8, collate=dt.utf8_bin) == \
611
+ 'LONGTEXT CHARACTER SET utf8 COLLATE utf8_bin NULL'
612
+ assert dt.LONGTEXT(nullable=False) == 'LONGTEXT NOT NULL'
613
+ assert dt.LONGTEXT(default='hi') == "LONGTEXT NULL DEFAULT 'hi'"
614
+
615
+ assert dt.MEDIUMTEXT() == 'MEDIUMTEXT NULL'
616
+ assert dt.MEDIUMTEXT(10) == 'MEDIUMTEXT(10) NULL'
617
+ assert dt.MEDIUMTEXT(charset=dt.utf8, collate=dt.utf8_bin) == \
618
+ 'MEDIUMTEXT CHARACTER SET utf8 COLLATE utf8_bin NULL'
619
+ assert dt.MEDIUMTEXT(nullable=False) == 'MEDIUMTEXT NOT NULL'
620
+ assert dt.MEDIUMTEXT(default='hi') == "MEDIUMTEXT NULL DEFAULT 'hi'"
621
+
622
+ assert dt.TEXT() == 'TEXT NULL'
623
+ assert dt.TEXT(10) == 'TEXT(10) NULL'
624
+ assert dt.TEXT(charset=dt.utf8, collate=dt.utf8_bin) == \
625
+ 'TEXT CHARACTER SET utf8 COLLATE utf8_bin NULL'
626
+ assert dt.TEXT(nullable=False) == 'TEXT NOT NULL'
627
+ assert dt.TEXT(default='hi') == "TEXT NULL DEFAULT 'hi'"
628
+
629
+ assert dt.TINYTEXT() == 'TINYTEXT NULL'
630
+ assert dt.TINYTEXT(10) == 'TINYTEXT(10) NULL'
631
+ assert dt.TINYTEXT(charset=dt.utf8, collate=dt.utf8_bin) == \
632
+ 'TINYTEXT CHARACTER SET utf8 COLLATE utf8_bin NULL'
633
+ assert dt.TINYTEXT(nullable=False) == 'TINYTEXT NOT NULL'
634
+ assert dt.TINYTEXT(default='hi') == "TINYTEXT NULL DEFAULT 'hi'"
635
+
636
+ assert dt.BINARY() == 'BINARY NULL'
637
+ assert dt.BINARY(10) == 'BINARY(10) NULL'
638
+ assert dt.BINARY(collate=dt.utf8_bin) == \
639
+ 'BINARY COLLATE utf8_bin NULL'
640
+ assert dt.BINARY(nullable=False) == 'BINARY NOT NULL'
641
+ assert dt.BINARY(default='hi') == "BINARY NULL DEFAULT 'hi'"
642
+
643
+ assert dt.VARBINARY() == 'VARBINARY NULL'
644
+ assert dt.VARBINARY(10) == 'VARBINARY(10) NULL'
645
+ assert dt.VARBINARY(collate=dt.utf8_bin) == \
646
+ 'VARBINARY COLLATE utf8_bin NULL'
647
+ assert dt.VARBINARY(nullable=False) == 'VARBINARY NOT NULL'
648
+ assert dt.VARBINARY(default='hi') == "VARBINARY NULL DEFAULT 'hi'"
649
+
650
+ assert dt.BLOB() == 'BLOB NULL'
651
+ assert dt.BLOB(10) == 'BLOB(10) NULL'
652
+ assert dt.BLOB(collate=dt.utf8_bin) == \
653
+ 'BLOB COLLATE utf8_bin NULL'
654
+ assert dt.BLOB(nullable=False) == 'BLOB NOT NULL'
655
+ assert dt.BLOB(default='hi') == "BLOB NULL DEFAULT 'hi'"
656
+
657
+ assert dt.TINYBLOB() == 'TINYBLOB NULL'
658
+ assert dt.TINYBLOB(10) == 'TINYBLOB(10) NULL'
659
+ assert dt.TINYBLOB(collate=dt.utf8_bin) == \
660
+ 'TINYBLOB COLLATE utf8_bin NULL'
661
+ assert dt.TINYBLOB(nullable=False) == 'TINYBLOB NOT NULL'
662
+ assert dt.TINYBLOB(default='hi') == "TINYBLOB NULL DEFAULT 'hi'"
663
+
664
+ assert dt.JSON() == 'JSON NULL'
665
+ assert dt.JSON(10) == 'JSON(10) NULL'
666
+ assert dt.JSON(charset=dt.utf8, collate=dt.utf8_bin) == \
667
+ 'JSON CHARACTER SET utf8 COLLATE utf8_bin NULL'
668
+ assert dt.JSON(nullable=False) == 'JSON NOT NULL'
669
+ assert dt.JSON(default='hi') == "JSON NULL DEFAULT 'hi'"
670
+
671
+ assert dt.GEOGRAPHYPOINT() == 'GEOGRAPHYPOINT NULL'
672
+ assert dt.GEOGRAPHYPOINT(nullable=False) == 'GEOGRAPHYPOINT NOT NULL'
673
+ assert dt.GEOGRAPHYPOINT(default='hi') == "GEOGRAPHYPOINT NULL DEFAULT 'hi'"
674
+
675
+ assert dt.GEOGRAPHY() == 'GEOGRAPHY NULL'
676
+ assert dt.GEOGRAPHY(nullable=False) == 'GEOGRAPHY NOT NULL'
677
+ assert dt.GEOGRAPHY(default='hi') == "GEOGRAPHY NULL DEFAULT 'hi'"
678
+
679
+ with self.assertRaises(AssertionError):
680
+ dt.RECORD()
681
+ assert dt.RECORD(('a', dt.INT), ('b', dt.FLOAT)) == \
682
+ 'RECORD(`a` INT NULL, `b` FLOAT NULL) NULL'
683
+ assert dt.RECORD(('a', dt.INT), ('b', dt.FLOAT), nullable=False) == \
684
+ 'RECORD(`a` INT NULL, `b` FLOAT NULL) NOT NULL'
685
+
686
+ assert dt.ARRAY(dt.INT) == 'ARRAY(INT NULL) NULL'
687
+ assert dt.ARRAY(dt.INT, nullable=False) == 'ARRAY(INT NULL) NOT NULL'