Path: blob/main/singlestoredb/tests/test_udf.py
469 views
#!/usr/bin/env python1# type: ignore2"""SingleStoreDB UDF testing."""3import dataclasses4import datetime5import re6import unittest7from typing import List8from typing import Optional9from typing import Tuple10from typing import TypeVar11from typing import Union1213import numpy as np14import pydantic1516from ..functions import dtypes as dt17from ..functions import signature as sig18from ..functions import Table19from ..functions import udf202122A = TypeVar('A', bytearray, bytes, None)23B = TypeVar('B', int, float, np.int64, np.int32, np.uint16)24C = TypeVar('C', B, np.int8)25D = TypeVar('D', bound=str)26E = Optional[List[Optional[Union[float, int]]]]272829def to_sql(x):30out = sig.signature_to_sql(sig.get_signature(x))31out = re.sub(r'^CREATE EXTERNAL FUNCTION ', r'', out)32out = re.sub(r' AS REMOTE SERVICE.+$', r'', out)33return out.strip()343536class TestUDF(unittest.TestCase):3738def test_invalid_signature(self):3940def foo(x: np.ndarray, y: np.ndarray) -> str: ...41with self.assertRaises(TypeError):42to_sql(foo)4344def foo(x: str, y: str) -> np.ndarray: ...45with self.assertRaises(TypeError):46to_sql(foo)4748def foo(x: str, y: np.ndarray) -> np.ndarray: ...49with self.assertRaises(TypeError):50to_sql(foo)5152def foo(x: np.ndarray, y: str) -> np.ndarray: ...53with self.assertRaises(TypeError):54to_sql(foo)5556def foo(x: str, y: np.ndarray) -> str: ...57with self.assertRaises(TypeError):58to_sql(foo)5960def foo(x: np.ndarray, y: str) -> str: ...61with self.assertRaises(TypeError):62to_sql(foo)6364def test_return_annotations(self):6566# No annotations67def foo(): ...68with self.assertRaises(TypeError):69to_sql(foo)7071# NULL return value72def foo() -> None: ...73assert to_sql(foo) == '`foo`() RETURNS TINYINT NULL'7475# Simple return value76def foo() -> int: ...77assert to_sql(foo) == '`foo`() RETURNS BIGINT NOT NULL'7879# Simple return value80def foo() -> np.int8: ...81assert to_sql(foo) == '`foo`() RETURNS TINYINT NOT NULL'8283# Optional return value84def foo() -> Optional[int]: ...85assert to_sql(foo) == '`foo`() RETURNS BIGINT NULL'8687# Optional return value88def foo() -> Union[int, None]: ...89assert to_sql(foo) == '`foo`() RETURNS BIGINT NULL'9091# Optional return value with multiple types92def foo() -> Union[int, float, None]: ...93assert to_sql(foo) == '`foo`() RETURNS DOUBLE NULL'9495# Optional return value with custom type96def foo() -> Optional[B]: ...97assert to_sql(foo) == '`foo`() RETURNS DOUBLE NULL'9899# Optional return value with nested custom type100def foo() -> Optional[C]: ...101assert to_sql(foo) == '`foo`() RETURNS DOUBLE NULL'102103# Optional return value with collection type104# def foo() -> Optional[List[str]]: ...105# assert to_sql(foo) == '`foo`() RETURNS ARRAY(TEXT NOT NULL) NULL'106107# Optional return value with nested collection type108# def foo() -> Optional[List[List[str]]]: ...109# assert to_sql(foo) == '`foo`()110# RETURNS ARRAY(ARRAY(TEXT NOT NULL) NOT NULL) NULL'111112# Optional return value with collection type with nulls113# def foo() -> Optional[List[Optional[str]]]: ...114# assert to_sql(foo) == '`foo`() RETURNS ARRAY(TEXT NULL) NULL'115116# Custom type with bound117def foo() -> D: ...118assert to_sql(foo) == '`foo`() RETURNS TEXT NOT NULL'119120# Return value with custom collection type with nulls121# def foo() -> E: ...122# assert to_sql(foo) == '`foo`() RETURNS ARRAY(DOUBLE NULL) NULL'123124# Incompatible types125def foo() -> Union[int, str]: ...126with self.assertRaises(TypeError):127to_sql(foo)128129# Tuple130with self.assertRaises(TypeError):131def foo() -> Tuple[int, float, str]: ...132to_sql(foo)133134# Optional tuple135with self.assertRaises(TypeError):136def foo() -> Optional[Tuple[int, float, str]]: ...137to_sql(foo)138139# Optional tuple with optional element140with self.assertRaises(TypeError):141def foo() -> Optional[Tuple[int, float, Optional[str]]]: ...142to_sql(foo)143144# Optional tuple with optional union element145with self.assertRaises(TypeError):146def foo() -> Optional[Tuple[int, Optional[Union[float, int]], str]]: ...147to_sql(foo)148149# Unknown type150def foo() -> set: ...151with self.assertRaises(TypeError) as exc:152to_sql(foo)153assert 'unsupported type annotation' in str(exc.exception)154155def test_parameter_annotations(self):156157# No annotations158def foo(x) -> None: ...159with self.assertRaises(TypeError):160to_sql(foo)161162# Simple parameter163def foo(x: int) -> None: ...164assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) RETURNS TINYINT NULL'165166# Optional parameter167def foo(x: Optional[int]) -> None: ...168assert to_sql(foo) == '`foo`(`x` BIGINT NULL) RETURNS TINYINT NULL'169170# Optional parameter171def foo(x: Union[int, None]) -> None: ...172assert to_sql(foo) == '`foo`(`x` BIGINT NULL) RETURNS TINYINT NULL'173174# Optional multiple parameter types175def foo(x: Union[int, float, None]) -> None: ...176assert to_sql(foo) == '`foo`(`x` DOUBLE NULL) RETURNS TINYINT NULL'177178# Optional parameter with custom type179def foo(x: Optional[B]) -> None: ...180assert to_sql(foo) == '`foo`(`x` DOUBLE NULL) RETURNS TINYINT NULL'181182# Optional parameter with nested custom type183def foo(x: Optional[C]) -> None: ...184assert to_sql(foo) == '`foo`(`x` DOUBLE NULL) RETURNS TINYINT NULL'185186# Optional parameter with collection type187# def foo(x: Optional[List[str]]) -> None: ...188# assert to_sql(foo) == '`foo`(`x`189# ARRAY(TEXT NOT NULL) NULL) RETURNS TINYINT NULL'190191# Optional parameter with nested collection type192# def foo(x: Optional[List[List[str]]]) -> None: ...193# assert to_sql(foo) == '`foo`(`x` ARRAY(ARRAY(TEXT NOT NULL) NOT NULL) NULL) ' \194# 'RETURNS TINYINT NULL'195196# Optional parameter with collection type with nulls197# def foo(x: Optional[List[Optional[str]]]) -> None: ...198# assert to_sql(foo) == '`foo`(`x` ARRAY(TEXT NULL) NULL) RETURNS TINYINT NULL'199200# Custom type with bound201def foo(x: D) -> None: ...202assert to_sql(foo) == '`foo`(`x` TEXT NOT NULL) RETURNS TINYINT NULL'203204# Incompatible types205def foo(x: Union[int, str]) -> None: ...206with self.assertRaises(TypeError):207to_sql(foo)208209# Tuple210with self.assertRaises(TypeError):211def foo(x: Tuple[int, float, str]) -> None: ...212to_sql(foo)213214# Optional tuple with optional element215with self.assertRaises(TypeError):216def foo(x: Optional[Tuple[int, float, Optional[str]]]) -> None: ...217to_sql(foo)218219# Optional tuple with optional union element220with self.assertRaises(TypeError):221def foo(222x: Optional[Tuple[int, Optional[Union[float, int]], str]],223) -> None: ...224to_sql(foo)225226# Unknown type227def foo(x: set) -> None: ...228with self.assertRaises(TypeError) as exc:229to_sql(foo)230assert 'unsupported type annotation' in str(exc.exception)231232def test_datetimes(self):233234# Datetime235def foo(x: datetime.datetime) -> None: ...236assert to_sql(foo) == '`foo`(`x` DATETIME NOT NULL) RETURNS TINYINT NULL'237238# Date239def foo(x: datetime.date) -> None: ...240assert to_sql(foo) == '`foo`(`x` DATE NOT NULL) RETURNS TINYINT NULL'241242# Time243def foo(x: datetime.timedelta) -> None: ...244assert to_sql(foo) == '`foo`(`x` TIME NOT NULL) RETURNS TINYINT NULL'245246# Datetime + Date247def foo(x: Union[datetime.datetime, datetime.date]) -> None: ...248with self.assertRaises(TypeError):249to_sql(foo)250251def test_numerics(self):252#253# Ints254#255def foo(x: int) -> None: ...256assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) RETURNS TINYINT NULL'257258def foo(x: np.int8) -> None: ...259assert to_sql(foo) == '`foo`(`x` TINYINT NOT NULL) RETURNS TINYINT NULL'260261def foo(x: np.int16) -> None: ...262assert to_sql(foo) == '`foo`(`x` SMALLINT NOT NULL) RETURNS TINYINT NULL'263264def foo(x: np.int32) -> None: ...265assert to_sql(foo) == '`foo`(`x` INT NOT NULL) RETURNS TINYINT NULL'266267def foo(x: np.int64) -> None: ...268assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) RETURNS TINYINT NULL'269270#271# Unsigned ints272#273def foo(x: np.uint8) -> None: ...274assert to_sql(foo) == '`foo`(`x` TINYINT UNSIGNED NOT NULL) RETURNS TINYINT NULL'275276def foo(x: np.uint16) -> None: ...277assert to_sql(foo) == '`foo`(`x` SMALLINT UNSIGNED NOT NULL) RETURNS TINYINT NULL'278279def foo(x: np.uint32) -> None: ...280assert to_sql(foo) == '`foo`(`x` INT UNSIGNED NOT NULL) RETURNS TINYINT NULL'281282def foo(x: np.uint64) -> None: ...283assert to_sql(foo) == '`foo`(`x` BIGINT UNSIGNED NOT NULL) RETURNS TINYINT NULL'284285#286# Floats287#288def foo(x: float) -> None: ...289assert to_sql(foo) == '`foo`(`x` DOUBLE NOT NULL) RETURNS TINYINT NULL'290291def foo(x: np.float32) -> None: ...292assert to_sql(foo) == '`foo`(`x` FLOAT NOT NULL) RETURNS TINYINT NULL'293294def foo(x: np.float64) -> None: ...295assert to_sql(foo) == '`foo`(`x` DOUBLE NOT NULL) RETURNS TINYINT NULL'296297#298# Type collapsing299#300def foo(x: Union[np.int8, np.int16]) -> None: ...301assert to_sql(foo) == '`foo`(`x` SMALLINT NOT NULL) RETURNS TINYINT NULL'302303def foo(x: Union[np.int64, np.double]) -> None: ...304assert to_sql(foo) == '`foo`(`x` DOUBLE NOT NULL) RETURNS TINYINT NULL'305306def foo(x: Union[int, float]) -> None: ...307assert to_sql(foo) == '`foo`(`x` DOUBLE NOT NULL) RETURNS TINYINT NULL'308309def test_positional_and_keyword_parameters(self):310# Keyword only311def foo(x: int = 100) -> None: ...312assert to_sql(foo) == \313'`foo`(`x` BIGINT NOT NULL DEFAULT 100) RETURNS TINYINT NULL'314315# Multiple keywords316def foo(x: int = 100, y: float = 3.14) -> None: ...317assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL DEFAULT 100, ' \318'`y` DOUBLE NOT NULL DEFAULT 3.14e0) RETURNS TINYINT NULL'319320# Keywords and positional321def foo(a: str, b: str, x: int = 100, y: float = 3.14) -> None: ...322assert to_sql(foo) == '`foo`(`a` TEXT NOT NULL, ' \323'`b` TEXT NOT NULL, ' \324'`x` BIGINT NOT NULL DEFAULT 100, ' \325'`y` DOUBLE NOT NULL DEFAULT 3.14e0) RETURNS TINYINT NULL'326327# Variable positional328def foo(*args: int) -> None: ...329with self.assertRaises(TypeError):330to_sql(foo)331332# Variable keywords333def foo(x: int = 100, **kwargs: float) -> None: ...334with self.assertRaises(TypeError):335to_sql(foo)336337def test_udf(self):338339# No parameters340@udf341def foo(x: int) -> int: ...342assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) RETURNS BIGINT NOT NULL'343344# No parameters345@udf()346def foo(x: int) -> int: ...347assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) RETURNS BIGINT NOT NULL'348349# Override return value with callable350@udf(returns=dt.SMALLINT)351def foo(x: int) -> int: ...352assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) RETURNS SMALLINT NULL'353354# Override return value with string355@udf(returns=dt.SMALLINT(nullable=False))356def foo(x: int) -> int: ...357assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) RETURNS SMALLINT NOT NULL'358359# Override multiple params with one type360@udf(args=dt.SMALLINT(nullable=False))361def foo(x: int, y: float, z: np.int8) -> int: ...362with self.assertRaises(ValueError):363to_sql(foo)364365# Override with list366@udf(args=[dt.SMALLINT, dt.FLOAT, dt.CHAR(30)])367def foo(x: int, y: float, z: str) -> int: ...368assert to_sql(foo) == '`foo`(`x` SMALLINT NULL, ' \369'`y` FLOAT NULL, ' \370'`z` CHAR(30) NULL) RETURNS BIGINT NOT NULL'371372# Override with too short of a list373@udf(args=[dt.SMALLINT, dt.FLOAT])374def foo(x: int, y: float, z: str) -> int: ...375with self.assertRaises(ValueError):376to_sql(foo)377378# Override with too long of a list379@udf(args=[dt.SMALLINT, dt.FLOAT, dt.CHAR(30), dt.TEXT])380def foo(x: int, y: float, z: str) -> int: ...381with self.assertRaises(ValueError):382to_sql(foo)383384# Override with list385@udf(args=[dt.SMALLINT, dt.FLOAT, dt.CHAR(30)])386def foo(x: int, y: float, z: str) -> int: ...387assert to_sql(foo) == '`foo`(`x` SMALLINT NULL, ' \388'`y` FLOAT NULL, ' \389'`z` CHAR(30) NULL) RETURNS BIGINT NOT NULL'390391# Override with dict392with self.assertRaises(TypeError):393@udf(args=dict(x=dt.SMALLINT, z=dt.CHAR(30)))394def foo(x: int, y: float, z: str) -> int: ...395assert to_sql(foo)396397# Change function name398@udf(name='hello_world')399def foo(x: int) -> int: ...400assert to_sql(foo) == '`hello_world`(`x` BIGINT NOT NULL) ' \401'RETURNS BIGINT NOT NULL'402403@udf(name='hello`_`world')404def foo(x: int) -> int: ...405assert to_sql(foo) == '`hello``_``world`(`x` BIGINT NOT NULL) ' \406'RETURNS BIGINT NOT NULL'407408@dataclasses.dataclass409class MyData:410one: Optional[int]411two: str412three: float413414with self.assertRaises(TypeError):415@udf416def foo(x: int) -> MyData: ...417to_sql(foo)418419@udf420def foo(x: int) -> Table[List[MyData]]: ...421assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) ' \422'RETURNS TABLE(`one` BIGINT NULL, `two` TEXT NOT NULL, ' \423'`three` DOUBLE NOT NULL)'424425@udf(returns=MyData)426def foo(x: int) -> Table[List[Tuple[int, int, int]]]: ...427assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) ' \428'RETURNS TABLE(`one` BIGINT NULL, `two` TEXT NOT NULL, ' \429'`three` DOUBLE NOT NULL)'430431class MyData(pydantic.BaseModel):432one: Optional[int]433two: str434three: float435436@udf437def foo(x: int) -> Table[List[MyData]]: ...438assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) ' \439'RETURNS TABLE(`one` BIGINT NULL, `two` TEXT NOT NULL, ' \440'`three` DOUBLE NOT NULL)'441442@udf(returns=MyData)443def foo(x: int) -> Table[List[Tuple[int, int, int]]]: ...444assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) ' \445'RETURNS TABLE(`one` BIGINT NULL, `two` TEXT NOT NULL, ' \446'`three` DOUBLE NOT NULL)'447448def test_dtypes(self):449assert dt.BOOL() == 'BOOL NULL'450assert dt.BOOL(nullable=False) == 'BOOL NOT NULL'451assert dt.BOOL(default=False) == 'BOOL NULL DEFAULT 0'452assert dt.BOOL(default=True) == 'BOOL NULL DEFAULT 1'453assert dt.BOOL(default='a') == 'BOOL NULL DEFAULT 1'454455assert dt.BOOLEAN() == 'BOOLEAN NULL'456assert dt.BOOLEAN(nullable=False) == 'BOOLEAN NOT NULL'457assert dt.BOOLEAN(default=False) == 'BOOLEAN NULL DEFAULT 0'458assert dt.BOOLEAN(default=True) == 'BOOLEAN NULL DEFAULT 1'459assert dt.BOOLEAN(default='a') == 'BOOLEAN NULL DEFAULT 1'460461assert dt.BIT() == 'BIT NULL'462assert dt.BIT(nullable=False) == 'BIT NOT NULL'463assert dt.BIT(default=100) == 'BIT NULL DEFAULT 100'464465assert dt.TINYINT() == 'TINYINT NULL'466assert dt.TINYINT(5) == 'TINYINT(5) NULL'467assert dt.TINYINT(nullable=False) == 'TINYINT NOT NULL'468assert dt.TINYINT(default=100) == 'TINYINT NULL DEFAULT 100'469assert dt.TINYINT(unsigned=True, default=100) == \470'TINYINT UNSIGNED NULL DEFAULT 100'471472assert dt.TINYINT_UNSIGNED() == 'TINYINT UNSIGNED NULL'473assert dt.TINYINT_UNSIGNED(5) == 'TINYINT(5) UNSIGNED NULL'474assert dt.TINYINT_UNSIGNED(nullable=False) == 'TINYINT UNSIGNED NOT NULL'475assert dt.TINYINT_UNSIGNED(default=100) == 'TINYINT UNSIGNED NULL DEFAULT 100'476477assert dt.SMALLINT() == 'SMALLINT NULL'478assert dt.SMALLINT(5) == 'SMALLINT(5) NULL'479assert dt.SMALLINT(nullable=False) == 'SMALLINT NOT NULL'480assert dt.SMALLINT(default=100) == 'SMALLINT NULL DEFAULT 100'481assert dt.SMALLINT(unsigned=True, default=100) == \482'SMALLINT UNSIGNED NULL DEFAULT 100'483484assert dt.SMALLINT_UNSIGNED() == 'SMALLINT UNSIGNED NULL'485assert dt.SMALLINT_UNSIGNED(5) == 'SMALLINT(5) UNSIGNED NULL'486assert dt.SMALLINT_UNSIGNED(nullable=False) == 'SMALLINT UNSIGNED NOT NULL'487assert dt.SMALLINT_UNSIGNED(default=100) == \488'SMALLINT UNSIGNED NULL DEFAULT 100'489490assert dt.MEDIUMINT() == 'MEDIUMINT NULL'491assert dt.MEDIUMINT(5) == 'MEDIUMINT(5) NULL'492assert dt.MEDIUMINT(nullable=False) == 'MEDIUMINT NOT NULL'493assert dt.MEDIUMINT(default=100) == 'MEDIUMINT NULL DEFAULT 100'494assert dt.MEDIUMINT(unsigned=True, default=100) == \495'MEDIUMINT UNSIGNED NULL DEFAULT 100'496497assert dt.MEDIUMINT_UNSIGNED() == 'MEDIUMINT UNSIGNED NULL'498assert dt.MEDIUMINT_UNSIGNED(5) == 'MEDIUMINT(5) UNSIGNED NULL'499assert dt.MEDIUMINT_UNSIGNED(nullable=False) == 'MEDIUMINT UNSIGNED NOT NULL'500assert dt.MEDIUMINT_UNSIGNED(default=100) == \501'MEDIUMINT UNSIGNED NULL DEFAULT 100'502503assert dt.INT() == 'INT NULL'504assert dt.INT(5) == 'INT(5) NULL'505assert dt.INT(nullable=False) == 'INT NOT NULL'506assert dt.INT(default=100) == 'INT NULL DEFAULT 100'507assert dt.INT(unsigned=True, default=100) == \508'INT UNSIGNED NULL DEFAULT 100'509510assert dt.INT_UNSIGNED() == 'INT UNSIGNED NULL'511assert dt.INT_UNSIGNED(5) == 'INT(5) UNSIGNED NULL'512assert dt.INT_UNSIGNED(nullable=False) == 'INT UNSIGNED NOT NULL'513assert dt.INT_UNSIGNED(default=100) == \514'INT UNSIGNED NULL DEFAULT 100'515516assert dt.INTEGER() == 'INTEGER NULL'517assert dt.INTEGER(5) == 'INTEGER(5) NULL'518assert dt.INTEGER(nullable=False) == 'INTEGER NOT NULL'519assert dt.INTEGER(default=100) == 'INTEGER NULL DEFAULT 100'520assert dt.INTEGER(unsigned=True, default=100) == \521'INTEGER UNSIGNED NULL DEFAULT 100'522523assert dt.INTEGER_UNSIGNED() == 'INTEGER UNSIGNED NULL'524assert dt.INTEGER_UNSIGNED(5) == 'INTEGER(5) UNSIGNED NULL'525assert dt.INTEGER_UNSIGNED(nullable=False) == 'INTEGER UNSIGNED NOT NULL'526assert dt.INTEGER_UNSIGNED(default=100) == \527'INTEGER UNSIGNED NULL DEFAULT 100'528529assert dt.BIGINT() == 'BIGINT NULL'530assert dt.BIGINT(5) == 'BIGINT(5) NULL'531assert dt.BIGINT(nullable=False) == 'BIGINT NOT NULL'532assert dt.BIGINT(default=100) == 'BIGINT NULL DEFAULT 100'533assert dt.BIGINT(unsigned=True, default=100) == \534'BIGINT UNSIGNED NULL DEFAULT 100'535536assert dt.BIGINT_UNSIGNED() == 'BIGINT UNSIGNED NULL'537assert dt.BIGINT_UNSIGNED(5) == 'BIGINT(5) UNSIGNED NULL'538assert dt.BIGINT_UNSIGNED(nullable=False) == 'BIGINT UNSIGNED NOT NULL'539assert dt.BIGINT_UNSIGNED(default=100) == \540'BIGINT UNSIGNED NULL DEFAULT 100'541542assert dt.BIGINT() == 'BIGINT NULL'543assert dt.BIGINT(5) == 'BIGINT(5) NULL'544assert dt.BIGINT(nullable=False) == 'BIGINT NOT NULL'545assert dt.BIGINT(default=100) == 'BIGINT NULL DEFAULT 100'546assert dt.BIGINT(unsigned=True, default=100) == \547'BIGINT UNSIGNED NULL DEFAULT 100'548549assert dt.FLOAT() == 'FLOAT NULL'550assert dt.FLOAT(5) == 'FLOAT(5) NULL'551assert dt.FLOAT(nullable=False) == 'FLOAT NOT NULL'552assert dt.FLOAT(default=1.234) == 'FLOAT NULL DEFAULT 1.234e0'553554assert dt.DOUBLE() == 'DOUBLE NULL'555assert dt.DOUBLE(5) == 'DOUBLE(5) NULL'556assert dt.DOUBLE(nullable=False) == 'DOUBLE NOT NULL'557assert dt.DOUBLE(default=1.234) == 'DOUBLE NULL DEFAULT 1.234e0'558559assert dt.REAL() == 'REAL NULL'560assert dt.REAL(5) == 'REAL(5) NULL'561assert dt.REAL(nullable=False) == 'REAL NOT NULL'562assert dt.REAL(default=1.234) == 'REAL NULL DEFAULT 1.234e0'563564with self.assertRaises(TypeError):565dt.DECIMAL()566with self.assertRaises(TypeError):567dt.DECIMAL(5)568assert dt.DECIMAL(10, 5) == 'DECIMAL(10, 5) NULL'569assert dt.DECIMAL(10, 5, nullable=False) == 'DECIMAL(10, 5) NOT NULL'570assert dt.DECIMAL(10, 5, default=1.234) == \571'DECIMAL(10, 5) NULL DEFAULT 1.234e0'572573with self.assertRaises(TypeError):574dt.DEC()575with self.assertRaises(TypeError):576dt.DEC(5)577assert dt.DEC(10, 5) == 'DEC(10, 5) NULL'578assert dt.DEC(10, 5, nullable=False) == 'DEC(10, 5) NOT NULL'579assert dt.DEC(10, 5, default=1.234) == \580'DEC(10, 5) NULL DEFAULT 1.234e0'581582with self.assertRaises(TypeError):583dt.FIXED()584with self.assertRaises(TypeError):585dt.FIXED(5)586assert dt.FIXED(10, 5) == 'FIXED(10, 5) NULL'587assert dt.FIXED(10, 5, nullable=False) == 'FIXED(10, 5) NOT NULL'588assert dt.FIXED(10, 5, default=1.234) == \589'FIXED(10, 5) NULL DEFAULT 1.234e0'590591with self.assertRaises(TypeError):592dt.NUMERIC()593with self.assertRaises(TypeError):594dt.NUMERIC(5)595assert dt.NUMERIC(10, 5) == 'NUMERIC(10, 5) NULL'596assert dt.NUMERIC(10, 5, nullable=False) == 'NUMERIC(10, 5) NOT NULL'597assert dt.NUMERIC(10, 5, default=1.234) == \598'NUMERIC(10, 5) NULL DEFAULT 1.234e0'599600assert dt.DATE() == 'DATE NULL'601assert dt.DATE(nullable=False) == 'DATE NOT NULL'602assert dt.DATE(default=datetime.date(2020, 1, 2)) == \603"DATE NULL DEFAULT '2020-01-02'"604605assert dt.TIME() == 'TIME NULL'606assert dt.TIME(6) == 'TIME(6) NULL'607assert dt.TIME(nullable=False) == 'TIME NOT NULL'608assert dt.TIME(default=datetime.timedelta(seconds=1000)) == \609"TIME NULL DEFAULT '00:16:40'"610611assert dt.DATETIME() == 'DATETIME NULL'612assert dt.DATETIME(6) == 'DATETIME(6) NULL'613assert dt.DATETIME(nullable=False) == 'DATETIME NOT NULL'614assert dt.DATETIME(default=datetime.datetime(2020, 1, 2, 3, 4, 5)) == \615"DATETIME NULL DEFAULT '2020-01-02 03:04:05'"616617assert dt.TIMESTAMP() == 'TIMESTAMP NULL'618assert dt.TIMESTAMP(6) == 'TIMESTAMP(6) NULL'619assert dt.TIMESTAMP(nullable=False) == 'TIMESTAMP NOT NULL'620assert dt.TIMESTAMP(default=datetime.datetime(2020, 1, 2, 3, 4, 5)) == \621"TIMESTAMP NULL DEFAULT '2020-01-02 03:04:05'"622623assert dt.YEAR() == 'YEAR NULL'624assert dt.YEAR(nullable=False) == 'YEAR NOT NULL'625assert dt.YEAR(default=1961) == 'YEAR NULL DEFAULT 1961'626627assert dt.CHAR() == 'CHAR NULL'628assert dt.CHAR(10) == 'CHAR(10) NULL'629assert dt.CHAR(charset=dt.utf8, collate=dt.utf8_bin) == \630'CHAR CHARACTER SET utf8 COLLATE utf8_bin NULL'631assert dt.CHAR(nullable=False) == 'CHAR NOT NULL'632assert dt.CHAR(default='hi') == "CHAR NULL DEFAULT 'hi'"633634assert dt.VARCHAR() == 'VARCHAR NULL'635assert dt.VARCHAR(10) == 'VARCHAR(10) NULL'636assert dt.VARCHAR(charset=dt.utf8, collate=dt.utf8_bin) == \637'VARCHAR CHARACTER SET utf8 COLLATE utf8_bin NULL'638assert dt.VARCHAR(nullable=False) == 'VARCHAR NOT NULL'639assert dt.VARCHAR(default='hi') == "VARCHAR NULL DEFAULT 'hi'"640641assert dt.LONGTEXT() == 'LONGTEXT NULL'642assert dt.LONGTEXT(10) == 'LONGTEXT(10) NULL'643assert dt.LONGTEXT(charset=dt.utf8, collate=dt.utf8_bin) == \644'LONGTEXT CHARACTER SET utf8 COLLATE utf8_bin NULL'645assert dt.LONGTEXT(nullable=False) == 'LONGTEXT NOT NULL'646assert dt.LONGTEXT(default='hi') == "LONGTEXT NULL DEFAULT 'hi'"647648assert dt.MEDIUMTEXT() == 'MEDIUMTEXT NULL'649assert dt.MEDIUMTEXT(10) == 'MEDIUMTEXT(10) NULL'650assert dt.MEDIUMTEXT(charset=dt.utf8, collate=dt.utf8_bin) == \651'MEDIUMTEXT CHARACTER SET utf8 COLLATE utf8_bin NULL'652assert dt.MEDIUMTEXT(nullable=False) == 'MEDIUMTEXT NOT NULL'653assert dt.MEDIUMTEXT(default='hi') == "MEDIUMTEXT NULL DEFAULT 'hi'"654655assert dt.TEXT() == 'TEXT NULL'656assert dt.TEXT(10) == 'TEXT(10) NULL'657assert dt.TEXT(charset=dt.utf8, collate=dt.utf8_bin) == \658'TEXT CHARACTER SET utf8 COLLATE utf8_bin NULL'659assert dt.TEXT(nullable=False) == 'TEXT NOT NULL'660assert dt.TEXT(default='hi') == "TEXT NULL DEFAULT 'hi'"661662assert dt.TINYTEXT() == 'TINYTEXT NULL'663assert dt.TINYTEXT(10) == 'TINYTEXT(10) NULL'664assert dt.TINYTEXT(charset=dt.utf8, collate=dt.utf8_bin) == \665'TINYTEXT CHARACTER SET utf8 COLLATE utf8_bin NULL'666assert dt.TINYTEXT(nullable=False) == 'TINYTEXT NOT NULL'667assert dt.TINYTEXT(default='hi') == "TINYTEXT NULL DEFAULT 'hi'"668669assert dt.BINARY() == 'BINARY NULL'670assert dt.BINARY(10) == 'BINARY(10) NULL'671assert dt.BINARY(collate=dt.utf8_bin) == \672'BINARY COLLATE utf8_bin NULL'673assert dt.BINARY(nullable=False) == 'BINARY NOT NULL'674assert dt.BINARY(default='hi') == "BINARY NULL DEFAULT 'hi'"675676assert dt.VARBINARY() == 'VARBINARY NULL'677assert dt.VARBINARY(10) == 'VARBINARY(10) NULL'678assert dt.VARBINARY(collate=dt.utf8_bin) == \679'VARBINARY COLLATE utf8_bin NULL'680assert dt.VARBINARY(nullable=False) == 'VARBINARY NOT NULL'681assert dt.VARBINARY(default='hi') == "VARBINARY NULL DEFAULT 'hi'"682683assert dt.BLOB() == 'BLOB NULL'684assert dt.BLOB(10) == 'BLOB(10) NULL'685assert dt.BLOB(collate=dt.utf8_bin) == \686'BLOB COLLATE utf8_bin NULL'687assert dt.BLOB(nullable=False) == 'BLOB NOT NULL'688assert dt.BLOB(default='hi') == "BLOB NULL DEFAULT 'hi'"689690assert dt.TINYBLOB() == 'TINYBLOB NULL'691assert dt.TINYBLOB(10) == 'TINYBLOB(10) NULL'692assert dt.TINYBLOB(collate=dt.utf8_bin) == \693'TINYBLOB COLLATE utf8_bin NULL'694assert dt.TINYBLOB(nullable=False) == 'TINYBLOB NOT NULL'695assert dt.TINYBLOB(default='hi') == "TINYBLOB NULL DEFAULT 'hi'"696697assert dt.JSON() == 'JSON NULL'698assert dt.JSON(10) == 'JSON(10) NULL'699assert dt.JSON(charset=dt.utf8, collate=dt.utf8_bin) == \700'JSON CHARACTER SET utf8 COLLATE utf8_bin NULL'701assert dt.JSON(nullable=False) == 'JSON NOT NULL'702assert dt.JSON(default='hi') == "JSON NULL DEFAULT 'hi'"703704assert dt.GEOGRAPHYPOINT() == 'GEOGRAPHYPOINT NULL'705assert dt.GEOGRAPHYPOINT(nullable=False) == 'GEOGRAPHYPOINT NOT NULL'706assert dt.GEOGRAPHYPOINT(default='hi') == "GEOGRAPHYPOINT NULL DEFAULT 'hi'"707708assert dt.GEOGRAPHY() == 'GEOGRAPHY NULL'709assert dt.GEOGRAPHY(nullable=False) == 'GEOGRAPHY NOT NULL'710assert dt.GEOGRAPHY(default='hi') == "GEOGRAPHY NULL DEFAULT 'hi'"711712# with self.assertRaises(AssertionError):713# dt.RECORD()714# assert dt.RECORD(('a', dt.INT), ('b', dt.FLOAT)) == \715# 'RECORD(`a` INT NULL, `b` FLOAT NULL) NULL'716# assert dt.RECORD(('a', dt.INT), ('b', dt.FLOAT), nullable=False) == \717# 'RECORD(`a` INT NULL, `b` FLOAT NULL) NOT NULL'718719# assert dt.ARRAY(dt.INT) == 'ARRAY(INT NULL) NULL'720# assert dt.ARRAY(dt.INT, nullable=False) == 'ARRAY(INT NULL) NOT NULL'721722# assert dt.VECTOR(8) == 'VECTOR(8, F32) NULL'723# assert dt.VECTOR(8, dt.F32) == 'VECTOR(8, F32) NULL'724# assert dt.VECTOR(8, dt.F64) == 'VECTOR(8, F64) NULL'725# assert dt.VECTOR(8, dt.I8) == 'VECTOR(8, I8) NULL'726# assert dt.VECTOR(8, dt.I16) == 'VECTOR(8, I16) NULL'727# assert dt.VECTOR(8, dt.I32) == 'VECTOR(8, I32) NULL'728# assert dt.VECTOR(8, dt.I64) == 'VECTOR(8, I64) NULL'729730# assert dt.VECTOR(8, nullable=False) == 'VECTOR(8, F32) NOT NULL'731# assert dt.VECTOR(8, dt.F32, nullable=False) == 'VECTOR(8, F32) NOT NULL'732# assert dt.VECTOR(8, dt.F64, nullable=False) == 'VECTOR(8, F64) NOT NULL'733# assert dt.VECTOR(8, dt.I8, nullable=False) == 'VECTOR(8, I8) NOT NULL'734# assert dt.VECTOR(8, dt.I16, nullable=False) == 'VECTOR(8, I16) NOT NULL'735# assert dt.VECTOR(8, dt.I32, nullable=False) == 'VECTOR(8, I32) NOT NULL'736# assert dt.VECTOR(8, dt.I64, nullable=False) == 'VECTOR(8, I64) NOT NULL'737738739