Coverage for dj/sql/parsing/types.py: 92%
274 statements
« prev ^ index » next coverage.py v7.2.3, created at 2023-04-17 20:05 -0700
« prev ^ index » next coverage.py v7.2.3, created at 2023-04-17 20:05 -0700
1"""DJ Column Types
3 Example:
4 >>> StructType( \
5 NestedField("required_field", StringType(), False, "a required field"), \
6 NestedField("optional_field", IntegerType(), True, "an optional field") \
7 )
8 StructType(NestedField(name=Name(name='required_field', quote_style='', namespace=None), \
9field_type=StringType(), is_optional=False, doc='a required field'), \
10NestedField(name=Name(name='optional_field', quote_style='', namespace=None), \
11field_type=IntegerType(), is_optional=True, doc='an optional field'))
13"""
15import re
16from enum import Enum
17from typing import TYPE_CHECKING, Any, ClassVar, Dict, Generator, Optional, Tuple, cast
19from pydantic import BaseModel, Extra
20from pydantic.class_validators import AnyCallable
22if TYPE_CHECKING:
23 from dj.sql.parsing import ast
26DECIMAL_REGEX = re.compile(r"(?i)decimal\((?P<precision>\d+),\s*(?P<scale>\d+)\)")
27FIXED_PARSER = re.compile(r"(?i)fixed\((?P<length>\d+)\)")
30class Singleton: # pylint: disable=too-few-public-methods
31 """
32 Singleton for types
33 """
35 _instance = None
37 def __new__(cls, *args, **kwargs): # pylint: disable=unused-argument
38 if not isinstance(cls._instance, cls):
39 cls._instance = super(Singleton, cls).__new__(cls)
40 return cls._instance
43class ColumnType(BaseModel):
44 """
45 Base type for all Column Types
46 """
48 _initialized = False
50 class Config: # pylint: disable=missing-class-docstring, too-few-public-methods
51 extra = Extra.allow
52 arbitrary_types_allowed = True
53 underscore_attrs_are_private = False
55 def __init__( # pylint: disable=keyword-arg-before-vararg
56 self,
57 type_string: str,
58 repr_string: str = None,
59 *args,
60 **kwargs,
61 ):
62 super().__init__(*args, **kwargs)
63 self._type_string = type_string
64 self._repr_string = repr_string if repr_string else self._type_string
65 self._initialized = True
67 def __repr__(self):
68 return self._repr_string
70 def __str__(self):
71 return self._type_string
73 def __deepcopy__(self, memo):
74 return self
76 @classmethod
77 def __get_validators__(cls) -> Generator[AnyCallable, None, None]:
78 """
79 One or more validators may be yielded which will be called in the
80 order to validate the input, each validator will receive as an input
81 the value returned from the previous validator
82 """
83 yield cls.validate
85 @classmethod
86 def validate( # pylint: disable=too-many-return-statements
87 cls,
88 v: Any,
89 ) -> "ColumnType":
90 """
91 Parses the column type
92 """
93 from dj.sql.parsing.backends.antlr4 import ( # pylint: disable=import-outside-toplevel
94 parse_rule,
95 )
97 return cast(ColumnType, parse_rule(str(v), "dataType"))
99 def __eq__(self, other: "ColumnType"): # type: ignore
100 """
101 Equality is dependent on the string representation of the column type.
102 """
103 return str(other) == str(self)
105 def __hash__(self):
106 """
107 Equality is dependent on the string representation of the column type.
108 """
109 return hash(str(self))
111 def is_compatible(self, other: "ColumnType") -> bool:
112 """
113 Returns whether the two types are compatible with each other by
114 checking their ancestors.
115 """
116 if self == other:
117 return True # quick return
119 def has_common_ancestor(type1, type2) -> bool:
120 """
121 Helper function to check whether two column types have common ancestors,
122 other than the highest-level ancestor types like ColumnType itself. This
123 determines whether they're part of the same type group and are compatible
124 with each other when performing type compatibility checks.
125 """
126 base_types = (ColumnType, Singleton, PrimitiveType)
127 if type1 in base_types or type2 in base_types:
128 return False
129 if type1 == type2:
130 return True
131 current_has = False
132 for ancestor in type1.__bases__:
133 for ancestor2 in type2.__bases__:
134 current_has = current_has or has_common_ancestor(
135 ancestor,
136 ancestor2,
137 )
138 if current_has:
139 return current_has
140 return False
142 return has_common_ancestor(self.__class__, other.__class__)
145class PrimitiveType(ColumnType): # pylint: disable=too-few-public-methods
146 """Base class for all Column Primitive Types"""
149class NumberType(PrimitiveType): # pylint: disable=too-few-public-methods
150 """Base class for all Column Number Types"""
153class NullType(PrimitiveType, Singleton): # pylint: disable=too-few-public-methods
154 """A data type for NULL
156 Example:
157 >>> NullType()
158 NullType()
159 """
161 def __init__(self):
162 super().__init__("NULL", "NullType()")
165class FixedType(PrimitiveType):
166 """A fixed data type.
168 Example:
169 >>> FixedType(8)
170 FixedType(length=8)
171 >>> FixedType(8)==FixedType(8)
172 True
173 """
175 _instances: Dict[int, "FixedType"] = {}
177 def __new__(cls, length: int):
178 cls._instances[length] = cls._instances.get(length) or object.__new__(cls)
179 return cls._instances[length]
181 def __init__(self, length: int):
182 if not self._initialized:
183 super().__init__(f"fixed({length})", f"FixedType(length={length})")
184 self._length = length
186 @property
187 def length(self) -> int: # pragma: no cover
188 """
189 The length of the fixed type
190 """
191 return self._length
194class DecimalType(NumberType):
195 """A fixed data type.
197 Example:
198 >>> DecimalType(32, 3)
199 DecimalType(precision=32, scale=3)
200 >>> DecimalType(8, 3)==DecimalType(8, 3)
201 True
202 """
204 max_precision: ClassVar[int] = 38
205 max_scale: ClassVar[int] = 38
206 _instances: Dict[Tuple[int, int], "DecimalType"] = {}
208 def __new__(cls, precision: int, scale: int):
209 key = (
210 min(precision, DecimalType.max_precision),
211 min(scale, DecimalType.max_scale),
212 )
213 cls._instances[key] = cls._instances.get(key) or object.__new__(cls)
214 return cls._instances[key]
216 def __init__(self, precision: int, scale: int):
218 if not self._initialized:
219 super().__init__(
220 f"decimal({precision}, {scale})",
221 f"DecimalType(precision={precision}, scale={scale})",
222 )
223 self._precision = min(precision, DecimalType.max_precision)
224 self._scale = min(scale, DecimalType.max_scale)
226 @property
227 def precision(self) -> int: # pragma: no cover
228 """
229 Decimal's precision
230 """
231 return self._precision
233 @property
234 def scale(self) -> int: # pragma: no cover
235 """
236 Decimal's scale
237 """
238 return self._scale
241class NestedField(ColumnType):
242 """Represents a field of a struct, a map key, a map value, or a list element.
244 This is where field IDs, names, docs, and nullability are tracked.
245 """
247 _instances: Dict[
248 Tuple[bool, str, ColumnType, Optional[str]],
249 "NestedField",
250 ] = {}
252 def __new__(
253 cls,
254 name: "ast.Name",
255 field_type: ColumnType,
256 is_optional: bool = True,
257 doc: Optional[str] = None,
258 ):
259 if isinstance(name, str): # pragma: no cover
260 from dj.sql.parsing.ast import ( # pylint: disable=import-outside-toplevel
261 Name,
262 )
264 name = Name(name)
266 key = (is_optional, name.name, field_type, doc)
267 cls._instances[key] = cls._instances.get(key) or object.__new__(cls)
268 return cls._instances[key]
270 def __init__(
271 self,
272 name: "ast.Name",
273 field_type: ColumnType,
274 is_optional: bool = True,
275 doc: Optional[str] = None,
276 ):
277 if not self._initialized:
278 if isinstance(name, str): # pragma: no cover
279 from dj.sql.parsing.ast import ( # pylint: disable=import-outside-toplevel
280 Name,
281 )
283 name = Name(name)
284 doc_string = "" if doc is None else f", doc={repr(doc)}"
285 super().__init__(
286 (
287 f"{name}: {field_type}"
288 f"{' NOT NULL' if not is_optional else ''}"
289 + ("" if doc is None else f" {doc}")
290 ),
291 f"NestedField(name={repr(name)}, "
292 f"field_type={repr(field_type)}, "
293 f"is_optional={is_optional}"
294 f"{doc_string})",
295 )
296 self._is_optional = is_optional
297 self._name = name
298 self._type = field_type
299 self._doc = doc
301 @property
302 def is_optional(self) -> bool:
303 """
304 Whether the field is optional
305 """
306 return self._is_optional # pragma: no cover
308 @property
309 def is_required(self) -> bool:
310 """
311 Whether the field is required
312 """
313 return not self._is_optional # pragma: no cover
315 @property
316 def name(self) -> "ast.Name":
317 """
318 The name of the field
319 """
320 return self._name
322 @property
323 def doc(self) -> Optional[str]:
324 """
325 The docstring of the field
326 """
327 return self._doc # pragma: no cover
329 @property
330 def type(self) -> ColumnType:
331 """
332 The field's type
333 """
334 return self._type
337class StructType(ColumnType):
338 """A struct type
340 Example:
341 >>> StructType( \
342 NestedField("required_field", StringType(), False, "a required field"), \
343 NestedField("optional_field", IntegerType(), True, "an optional field") \
344 )
345 StructType(NestedField(name=Name(name='required_field', quote_style='', namespace=None), \
346field_type=StringType(), is_optional=False, doc='a required field'), \
347NestedField(name=Name(name='optional_field', quote_style='', namespace=None), \
348field_type=IntegerType(), is_optional=True, doc='an optional field'))
349 """
351 _instances: Dict[Tuple[NestedField, ...], "StructType"] = {}
353 def __new__(cls, *fields: NestedField):
354 cls._instances[fields] = cls._instances.get(fields) or object.__new__(cls)
355 return cls._instances[fields]
357 def __init__(self, *fields: NestedField):
358 if not self._initialized:
359 super().__init__(
360 f"struct<{', '.join(map(str, fields))}>",
361 f"StructType{repr(fields)}",
362 )
363 self._fields = fields
365 @property
366 def fields(self) -> Tuple[NestedField, ...]:
367 """
368 Returns the struct's fields.
369 """
370 return self._fields # pragma: no cover
373class ListType(ColumnType):
374 """A list type
376 Example:
377 >>> ListType(element_type=StringType())
378 ListType(element_type=StringType())
379 """
381 _instances: Dict[Tuple[bool, int, ColumnType], "ListType"] = {}
383 def __new__(
384 cls,
385 element_type: ColumnType,
386 ):
387 key = (element_type,)
388 cls._instances[key] = cls._instances.get(key) or object.__new__(cls) # type: ignore
389 return cls._instances[key] # type: ignore
391 def __init__(
392 self,
393 element_type: ColumnType,
394 ):
396 if not self._initialized:
397 super().__init__(
398 f"array<{element_type}>",
399 f"ListType(element_type={repr(element_type)})",
400 )
401 self._element_field = NestedField(
402 name="col", # type: ignore
403 field_type=element_type,
404 is_optional=False, # type: ignore
405 )
407 @property
408 def element(self) -> NestedField:
409 """
410 Returns the list's element
411 """
412 return self._element_field
415class MapType(ColumnType):
416 """A map type"""
418 _instances: Dict[Tuple[ColumnType, ColumnType], "MapType"] = {}
420 def __new__(
421 cls,
422 key_type: ColumnType,
423 value_type: ColumnType,
424 ):
425 impl_key = (key_type, value_type)
426 cls._instances[impl_key] = cls._instances.get(impl_key) or object.__new__(cls)
427 return cls._instances[impl_key]
429 def __init__(
430 self,
431 key_type: ColumnType,
432 value_type: ColumnType,
433 ):
435 if not self._initialized:
436 super().__init__(
437 f"map<{key_type}, {value_type}>",
438 )
439 self._key_field = NestedField(
440 name="key", # type: ignore
441 field_type=key_type,
442 is_optional=False, # type: ignore
443 )
444 self._value_field = NestedField(
445 name="value", # type: ignore
446 field_type=value_type,
447 is_optional=False, # type: ignore
448 )
450 @property
451 def key(self) -> NestedField:
452 """
453 The map's key
454 """
455 return self._key_field
457 @property
458 def value(self) -> NestedField:
459 """
460 The map's value
461 """
462 return self._value_field
465class BooleanType(PrimitiveType, Singleton):
466 """A boolean data type can be represented using an instance of this class.
468 Example:
469 >>> column_foo = BooleanType()
470 >>> isinstance(column_foo, BooleanType)
471 True
472 """
474 def __init__(self):
475 super().__init__("boolean", "BooleanType()")
478class IntegerBase(NumberType, Singleton):
479 """Base class for all integer types"""
481 max: ClassVar[int]
482 min: ClassVar[int]
484 def check_bounds(self, value: int) -> bool:
485 """
486 Check whether a value fits within the Integer min and max
487 """
488 return self.__class__.min < value < self.__class__.max
491class IntegerType(IntegerBase):
492 """An Integer data type can be represented using an instance of this class. Integers are
493 32-bit signed and can be promoted to Longs.
495 Example:
496 >>> column_foo = IntegerType()
497 >>> isinstance(column_foo, IntegerType)
498 True
500 Attributes:
501 max (int): The maximum allowed value for Integers, inherited from the
502 canonical Column implementation
503 in Java (returns `2147483647`)
504 min (int): The minimum allowed value for Integers, inherited from the
505 canonical Column implementation
506 in Java (returns `-2147483648`)
507 """
509 max: ClassVar[int] = 2147483647
511 min: ClassVar[int] = -2147483648
513 def __init__(self):
514 super().__init__("int", "IntegerType()")
517class TinyIntType(IntegerBase):
518 """A TinyInt data type can be represented using an instance of this class. TinyInts are
519 8-bit signed integers.
521 Example:
522 >>> column_foo = TinyIntType()
523 >>> isinstance(column_foo, TinyIntType)
524 True
526 Attributes:
527 max (int): The maximum allowed value for TinyInts (returns `127`).
528 min (int): The minimum allowed value for TinyInts (returns `-128`).
529 """
531 max: ClassVar[int] = 127
533 min: ClassVar[int] = -128
535 def __init__(self):
536 super().__init__("tinyint", "TinyIntType()")
539class SmallIntType(IntegerBase): # pylint: disable=R0901
540 """A SmallInt data type can be represented using an instance of this class. SmallInts are
541 16-bit signed integers.
543 Example:
544 >>> column_foo = SmallIntType()
545 >>> isinstance(column_foo, SmallIntType)
546 True
548 Attributes:
549 max (int): The maximum allowed value for SmallInts (returns `32767`).
550 min (int): The minimum allowed value for SmallInts (returns `-32768`).
551 """
553 max: ClassVar[int] = 32767
555 min: ClassVar[int] = -32768
557 def __init__(self):
558 super().__init__("smallint", "SmallIntType()")
561class BigIntType(IntegerBase):
562 """A Long data type can be represented using an instance of this class. Longs are
563 64-bit signed integers.
565 Example:
566 >>> column_foo = BigIntType()
567 >>> isinstance(column_foo, BigIntType)
568 True
570 Attributes:
571 max (int): The maximum allowed value for Longs, inherited from the
572 canonical Column implementation
573 in Java. (returns `9223372036854775807`)
574 min (int): The minimum allowed value for Longs, inherited from the
575 canonical Column implementation
576 in Java (returns `-9223372036854775808`)
577 """
579 max: ClassVar[int] = 9223372036854775807
581 min: ClassVar[int] = -9223372036854775808
583 def __init__(self):
584 super().__init__("bigint", "BigIntType()")
587class LongType(BigIntType): # pylint: disable=R0901
588 """A Long data type can be represented using an instance of this class. Longs are
589 64-bit signed integers.
591 Example:
592 >>> column_foo = LongType()
593 >>> column_foo == LongType()
594 True
596 Attributes:
597 max (int): The maximum allowed value for Longs, inherited from the
598 canonical Column implementation
599 in Java. (returns `9223372036854775807`)
600 min (int): The minimum allowed value for Longs, inherited from the
601 canonical Column implementation
602 in Java (returns `-9223372036854775808`)
603 """
605 def __new__(cls, *args, **kwargs):
606 self = super().__new__(BigIntType, *args, **kwargs)
607 super(BigIntType, self).__init__("long", "LongType()")
608 return self
611class FloatingBase(NumberType, Singleton):
612 """Base class for all floating types"""
615class FloatType(FloatingBase):
616 """A Float data type can be represented using an instance of this class. Floats are
617 32-bit IEEE 754 floating points and can be promoted to Doubles.
619 Example:
620 >>> column_foo = FloatType()
621 >>> isinstance(column_foo, FloatType)
622 True
623 """
625 def __init__(self):
626 super().__init__("float", "FloatType()")
629class DoubleType(FloatingBase):
630 """A Double data type can be represented using an instance of this class. Doubles are
631 64-bit IEEE 754 floating points.
633 Example:
634 >>> column_foo = DoubleType()
635 >>> isinstance(column_foo, DoubleType)
636 True
637 """
639 def __init__(self):
640 super().__init__("double", "DoubleType()")
643class DateTimeBase(PrimitiveType, Singleton):
644 """
645 Base class for date and time types.
646 """
648 # pylint: disable=invalid-name
649 class Unit(str, Enum):
650 """
651 Units used for date and time functions and intervals
652 """
654 dayofyear = "DAYOFYEAR"
655 year = "YEAR"
656 day = "DAY"
657 microsecond = "MICROSECOND"
658 month = "MONTH"
659 week = "WEEK"
660 minute = "MINUTE"
661 second = "SECOND"
662 quarter = "QUARTER"
663 hour = "HOUR"
664 millisecond = "MILLISECOND"
666 # pylint: enable=invalid-name
669class DateType(DateTimeBase):
670 """A Date data type can be represented using an instance of this class. Dates are
671 calendar dates without a timezone or time.
673 Example:
674 >>> column_foo = DateType()
675 >>> isinstance(column_foo, DateType)
676 True
677 """
679 def __init__(self):
680 super().__init__("date", "DateType()")
683class TimeType(DateTimeBase):
684 """A Time data type can be represented using an instance of this class. Times
685 have microsecond precision and are a time of day without a date or timezone.
687 Example:
688 >>> column_foo = TimeType()
689 >>> isinstance(column_foo, TimeType)
690 True
691 """
693 def __init__(self):
694 super().__init__("time", "TimeType()")
697class TimestampType(PrimitiveType, Singleton):
698 """A Timestamp data type can be represented using an instance of this class. Timestamps in
699 Column have microsecond precision and include a date and a time of day without a timezone.
701 Example:
702 >>> column_foo = TimestampType()
703 >>> isinstance(column_foo, TimestampType)
704 True
705 """
707 def __init__(self):
708 super().__init__("timestamp", "TimestampType()")
711class TimestamptzType(PrimitiveType, Singleton):
712 """A Timestamptz data type can be represented using an instance of this class. Timestamptzs in
713 Column are stored as UTC and include a date and a time of day with a timezone.
715 Example:
716 >>> column_foo = TimestamptzType()
717 >>> isinstance(column_foo, TimestamptzType)
718 True
719 """
721 def __init__(self):
722 super().__init__("timestamptz", "TimestamptzType()")
725class IntervalTypeBase(PrimitiveType):
726 """A base class for all interval types"""
729class DayTimeIntervalType(IntervalTypeBase):
730 """A DayTimeIntervalType type.
732 Example:
733 >>> DayTimeIntervalType()==DayTimeIntervalType("DAY", "SECOND")
734 True
735 """
737 _instances: Dict[Tuple[str, str], "DayTimeIntervalType"] = {}
739 def __new__(
740 cls,
741 from_: DateTimeBase.Unit = DateTimeBase.Unit.day,
742 to_: Optional[DateTimeBase.Unit] = DateTimeBase.Unit.second,
743 ):
744 key = (from_.upper(), to_.upper()) # type: ignore
745 cls._instances[key] = cls._instances.get(key) or object.__new__(cls)
746 return cls._instances[key]
748 def __init__(
749 self,
750 from_: DateTimeBase.Unit = DateTimeBase.Unit.day,
751 to_: Optional[DateTimeBase.Unit] = DateTimeBase.Unit.second,
752 ):
753 if not self._initialized:
754 from_ = from_.upper() # type: ignore
755 to_ = to_.upper() # type: ignore
756 to_str = f" TO {to_}" if to_ else ""
757 to_repr = f', to="{to_}"' if to_ else ""
758 super().__init__(
759 f"INTERVAL {from_}{to_str}",
760 f'DayTimeIntervalType(from="{from_}"{to_repr})',
761 )
762 self._from = from_
763 self._to = to_
765 @property
766 def from_(self) -> str: # pylint: disable=missing-function-docstring
767 return self._from # pragma: no cover
769 @property
770 def to_( # pylint: disable=missing-function-docstring
771 self,
772 ) -> Optional[str]:
773 return self._to # pragma: no cover
776class YearMonthIntervalType(IntervalTypeBase):
777 """A YearMonthIntervalType type.
779 Example:
780 >>> YearMonthIntervalType()==YearMonthIntervalType("YEAR", "MONTH")
781 True
782 """
784 _instances: Dict[Tuple[str, str], "YearMonthIntervalType"] = {}
786 def __new__(
787 cls,
788 from_: DateTimeBase.Unit = DateTimeBase.Unit.year,
789 to_: Optional[DateTimeBase.Unit] = DateTimeBase.Unit.month,
790 ):
791 key = (from_.upper(), to_.upper()) # type: ignore
792 cls._instances[key] = cls._instances.get(key) or object.__new__(cls)
793 return cls._instances[key]
795 def __init__(
796 self,
797 from_: DateTimeBase.Unit = DateTimeBase.Unit.year,
798 to_: Optional[DateTimeBase.Unit] = DateTimeBase.Unit.month,
799 ):
800 if not self._initialized:
801 from_ = from_.upper() # type: ignore
802 to_ = to_.upper() # type: ignore
803 to_str = f" TO {to_}" if to_ else ""
804 to_repr = f', to="{to_}"' if to_ else ""
805 super().__init__(
806 f"INTERVAL {from_}{to_str}",
807 f'YearMonthIntervalType(from="{from_}"{to_repr})',
808 )
809 self._from = from_
810 self._to = to_
812 @property
813 def from_(self) -> str: # pylint: disable=missing-function-docstring
814 return self._from # pragma: no cover
816 @property
817 def to_( # pylint: disable=missing-function-docstring
818 self,
819 ) -> Optional[str]:
820 return self._to # pragma: no cover
823class StringBase(PrimitiveType, Singleton):
824 """Base class for all string types"""
827class StringType(StringBase):
828 """A String data type can be represented using an instance of this class. Strings in
829 Column are arbitrary-length character sequences and are encoded with UTF-8.
831 Example:
832 >>> column_foo = StringType()
833 >>> isinstance(column_foo, StringType)
834 True
835 """
837 def __init__(self):
838 super().__init__("string", "StringType()")
841class VarcharType(StringBase):
842 """A VarcharType data type can be represented using an instance of this class.
843 Varchars in Column are arbitrary-length character sequences and are
844 encoded with UTF-8.
846 Example:
847 >>> column_foo = VarcharType()
848 >>> isinstance(column_foo, VarcharType)
849 True
850 """
852 def __init__(self):
853 super().__init__("varchar", "VarcharType()")
856class UUIDType(PrimitiveType, Singleton):
857 """A UUID data type can be represented using an instance of this class. UUIDs in
858 Column are universally unique identifiers.
860 Example:
861 >>> column_foo = UUIDType()
862 >>> isinstance(column_foo, UUIDType)
863 True
864 """
866 def __init__(self):
867 super().__init__("uuid", "UUIDType()")
870class BinaryType(PrimitiveType, Singleton):
871 """A Binary data type can be represented using an instance of this class. Binarys in
872 Column are arbitrary-length byte arrays.
874 Example:
875 >>> column_foo = BinaryType()
876 >>> isinstance(column_foo, BinaryType)
877 True
878 """
880 def __init__(self):
881 super().__init__("binary", "BinaryType()")
884class WildcardType(PrimitiveType, Singleton):
885 """A Wildcard datatype.
887 Example:
888 >>> column_foo = WildcardType()
889 >>> isinstance(column_foo, WildcardType)
890 True
891 """
893 def __init__(self):
894 super().__init__("wildcard", "WildcardType()")
897# Define the primitive data types and their corresponding Python classes
898PRIMITIVE_TYPES: Dict[str, PrimitiveType] = {
899 "bool": BooleanType(),
900 "boolean": BooleanType(),
901 "varchar": VarcharType(),
902 "bigint": BigIntType(),
903 "int": IntegerType(),
904 "long": BigIntType(),
905 "float": FloatType(),
906 "double": DoubleType(),
907 "date": DateType(),
908 "time": TimeType(),
909 "timestamp": TimestampType(),
910 "timestamptz": TimestamptzType(),
911 "string": StringType(),
912 "uuid": UUIDType(),
913 "byte": BinaryType(),
914 "binary": BinaryType(),
915 "none": NullType(),
916 "null": NullType(),
917}