DefPixel-PostgreSQL 0.1.6__91-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 (68) hide show
  1. DefPixel/DataAccessObject/Implements/PostgreSQL/Adapters/Array.py +16 -0
  2. DefPixel/DataAccessObject/Implements/PostgreSQL/Adapters/JavaScriptObjectNotation.py +74 -0
  3. DefPixel/DataAccessObject/Implements/PostgreSQL/Adapters/__init__.py +51 -0
  4. DefPixel/DataAccessObject/Implements/PostgreSQL/Column.py +34 -0
  5. DefPixel/DataAccessObject/Implements/PostgreSQL/Compiler.py +161 -0
  6. DefPixel/DataAccessObject/Implements/PostgreSQL/Configuration.py +116 -0
  7. DefPixel/DataAccessObject/Implements/PostgreSQL/Connection.py +138 -0
  8. DefPixel/DataAccessObject/Implements/PostgreSQL/Constraint.py +18 -0
  9. DefPixel/DataAccessObject/Implements/PostgreSQL/Constraints/Check.py +23 -0
  10. DefPixel/DataAccessObject/Implements/PostgreSQL/Constraints/Columns.py +24 -0
  11. DefPixel/DataAccessObject/Implements/PostgreSQL/Constraints/ForeignKey.py +56 -0
  12. DefPixel/DataAccessObject/Implements/PostgreSQL/Constraints/PrimaryKey.py +21 -0
  13. DefPixel/DataAccessObject/Implements/PostgreSQL/Constraints/Unique.py +25 -0
  14. DefPixel/DataAccessObject/Implements/PostgreSQL/Constraints/__init__.py +13 -0
  15. DefPixel/DataAccessObject/Implements/PostgreSQL/Context.py +48 -0
  16. DefPixel/DataAccessObject/Implements/PostgreSQL/Cursor.py +123 -0
  17. DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/Create.py +181 -0
  18. DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/Delete.py +31 -0
  19. DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/Drop.py +53 -0
  20. DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/Get.py +24 -0
  21. DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/Insert.py +98 -0
  22. DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/Query.py +37 -0
  23. DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/Select.py +122 -0
  24. DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/Update.py +57 -0
  25. DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/__init__.py +19 -0
  26. DefPixel/DataAccessObject/Implements/PostgreSQL/Expr.py +11 -0
  27. DefPixel/DataAccessObject/Implements/PostgreSQL/Exprs/Common.py +180 -0
  28. DefPixel/DataAccessObject/Implements/PostgreSQL/Exprs/Compare.py +87 -0
  29. DefPixel/DataAccessObject/Implements/PostgreSQL/Exprs/Condition.py +155 -0
  30. DefPixel/DataAccessObject/Implements/PostgreSQL/Exprs/JavaScriptObjectNotation.py +53 -0
  31. DefPixel/DataAccessObject/Implements/PostgreSQL/Exprs/Operator.py +42 -0
  32. DefPixel/DataAccessObject/Implements/PostgreSQL/Exprs/String.py +48 -0
  33. DefPixel/DataAccessObject/Implements/PostgreSQL/Exprs/__init__.py +75 -0
  34. DefPixel/DataAccessObject/Implements/PostgreSQL/Function.py +11 -0
  35. DefPixel/DataAccessObject/Implements/PostgreSQL/Functions/Common.py +142 -0
  36. DefPixel/DataAccessObject/Implements/PostgreSQL/Functions/DateTime.py +219 -0
  37. DefPixel/DataAccessObject/Implements/PostgreSQL/Functions/JavaScriptObjectNotation.py +100 -0
  38. DefPixel/DataAccessObject/Implements/PostgreSQL/Functions/Sequence.py +55 -0
  39. DefPixel/DataAccessObject/Implements/PostgreSQL/Functions/__init__.py +91 -0
  40. DefPixel/DataAccessObject/Implements/PostgreSQL/Index.py +135 -0
  41. DefPixel/DataAccessObject/Implements/PostgreSQL/Joins/FullOuter.py +15 -0
  42. DefPixel/DataAccessObject/Implements/PostgreSQL/Joins/Inner.py +15 -0
  43. DefPixel/DataAccessObject/Implements/PostgreSQL/Joins/Join.py +41 -0
  44. DefPixel/DataAccessObject/Implements/PostgreSQL/Joins/LeftOuter.py +15 -0
  45. DefPixel/DataAccessObject/Implements/PostgreSQL/Joins/RightOuter.py +15 -0
  46. DefPixel/DataAccessObject/Implements/PostgreSQL/Joins/__init__.py +15 -0
  47. DefPixel/DataAccessObject/Implements/PostgreSQL/Mapping.py +359 -0
  48. DefPixel/DataAccessObject/Implements/PostgreSQL/Orders.py +59 -0
  49. DefPixel/DataAccessObject/Implements/PostgreSQL/Pool.py +84 -0
  50. DefPixel/DataAccessObject/Implements/PostgreSQL/Schema.py +28 -0
  51. DefPixel/DataAccessObject/Implements/PostgreSQL/Sequence.py +55 -0
  52. DefPixel/DataAccessObject/Implements/PostgreSQL/Session.py +84 -0
  53. DefPixel/DataAccessObject/Implements/PostgreSQL/Type.py +113 -0
  54. DefPixel/DataAccessObject/Implements/PostgreSQL/Types/Array.py +61 -0
  55. DefPixel/DataAccessObject/Implements/PostgreSQL/Types/Binary.py +34 -0
  56. DefPixel/DataAccessObject/Implements/PostgreSQL/Types/Bool.py +29 -0
  57. DefPixel/DataAccessObject/Implements/PostgreSQL/Types/DateTime.py +120 -0
  58. DefPixel/DataAccessObject/Implements/PostgreSQL/Types/JavaScriptObjectNotation.py +52 -0
  59. DefPixel/DataAccessObject/Implements/PostgreSQL/Types/Numeric.py +151 -0
  60. DefPixel/DataAccessObject/Implements/PostgreSQL/Types/Size.py +13 -0
  61. DefPixel/DataAccessObject/Implements/PostgreSQL/Types/String.py +80 -0
  62. DefPixel/DataAccessObject/Implements/PostgreSQL/Types/__init__.py +76 -0
  63. DefPixel/DataAccessObject/Implements/PostgreSQL/__init__.py +85 -0
  64. defpixel_postgresql-0.1.6.dist-info/METADATA +184 -0
  65. defpixel_postgresql-0.1.6.dist-info/RECORD +68 -0
  66. defpixel_postgresql-0.1.6.dist-info/WHEEL +6 -0
  67. defpixel_postgresql-0.1.6.dist-info/licenses/LICENSE +674 -0
  68. defpixel_postgresql-0.1.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,113 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from dataclasses import MISSING
4
+ from typing import (
5
+ Any,
6
+ Callable,
7
+ Optional,
8
+ Tuple,
9
+ Type as PythonType,
10
+ Union,
11
+ )
12
+
13
+ from .Compiler import (
14
+ Compilable,
15
+ Compiler,
16
+ identifier,
17
+ qualified,
18
+ valuetype,
19
+ )
20
+
21
+ __all__ = (
22
+ 'Type',
23
+ )
24
+
25
+
26
+ class Type(Compilable):
27
+ """PostgreSQL column specification for SQL types and value conversion."""
28
+
29
+ typestr = ''
30
+
31
+ def __init__(
32
+ self,
33
+ key: Optional[str],
34
+ type: Union[PythonType, Tuple[PythonType, ...]],
35
+ typestr: Optional[str] = None,
36
+ va: Optional[Callable] = None,
37
+ null: bool = False,
38
+ default: Any = MISSING,
39
+ ):
40
+ if not isinstance(null, bool):
41
+ raise TypeError('null must be a bool')
42
+ self.key = key
43
+ self.type = type
44
+ if typestr is not None:
45
+ self.typestr = typestr
46
+ self.validator = va
47
+ self.null = null
48
+ self.coldef = default
49
+ self.model: Optional[str] = None
50
+ self.schema: Optional[str] = None
51
+ return
52
+
53
+ def __init_subclass__(
54
+ cls,
55
+ typestr: Optional[str] = None,
56
+ **kwargs,
57
+ ):
58
+ super().__init_subclass__(**kwargs)
59
+ if typestr is not None:
60
+ cls.typestr = typestr
61
+ return
62
+
63
+ def compile(self, compiler: Compiler) -> str:
64
+ if self.model is None or self.key is None:
65
+ raise ValueError('The column is not bound to a model')
66
+ if not compiler.qualify:
67
+ return identifier(self.key)
68
+ return '{}.{}'.format(qualified(self.model, self.schema), identifier(self.key))
69
+
70
+ def convert(self, value: Any) -> Any:
71
+ """Convert an accepted input representation before the type check."""
72
+ return value
73
+
74
+ def check(self, value: Any) -> bool:
75
+ if isinstance(self.type, tuple):
76
+ types = self.type
77
+ else:
78
+ types = (self.type,)
79
+ if bool not in types and isinstance(value, bool):
80
+ return False
81
+ return isinstance(value, types)
82
+
83
+ def validate(self, value: Any) -> Any:
84
+ if value is None:
85
+ if not self.null:
86
+ raise ValueError('Column {} does not allow None'.format(self.key))
87
+ return None
88
+ if self.validator is not None:
89
+ value = self.validator(value)
90
+ value = self.convert(value)
91
+ if not self.check(value):
92
+ raise TypeError('Column {} requires a value of type {}'.format(
93
+ self.key,
94
+ ' or '.join(t.__name__ for t in (self.type if isinstance(self.type, tuple) else (self.type,))),
95
+ ))
96
+ return value
97
+
98
+ def adapt(self, value: Any) -> Any:
99
+ """Wrap a validated value for the driver."""
100
+ return value
101
+
102
+ def encode(self, value: Any) -> Any:
103
+ value = self.validate(value)
104
+ return None if value is None else self.adapt(value)
105
+
106
+ def default(self) -> Optional[str]:
107
+ """Render the column DEFAULT clause body in DDL literal mode."""
108
+ if self.coldef is MISSING:
109
+ return None
110
+ compiler = Compiler(literal=True)
111
+ if isinstance(self.coldef, Compilable):
112
+ return compiler.compile(self.coldef)
113
+ return compiler.bind(self.encode(self.coldef), cast=valuetype(self))
@@ -0,0 +1,61 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from collections.abc import Sequence
4
+ from dataclasses import MISSING
5
+
6
+ from ..Compiler import typename
7
+ from ..Type import Type
8
+ from .Size import positive
9
+
10
+ __all__ = (
11
+ 'Array',
12
+ )
13
+
14
+
15
+ class Array(Type, typestr='ARRAY'):
16
+ """Array column of an element type; size sets declared dimensions, for example [3] or [2, 2]."""
17
+
18
+ def __init__(
19
+ self,
20
+ name=None,
21
+ type=None,
22
+ typesize=None,
23
+ size=None,
24
+ va=None,
25
+ null=False,
26
+ default=MISSING,
27
+ ):
28
+ if type is None:
29
+ raise ValueError('Array requires an element type')
30
+ element = typename(type, escape=False)
31
+ typesize = positive('typesize', typesize)
32
+ if size is None:
33
+ sizes = [None]
34
+ elif isinstance(size, Sequence) and not isinstance(size, str):
35
+ sizes = list(size)
36
+ if not sizes:
37
+ raise ValueError('size requires at least one dimension')
38
+ else:
39
+ sizes = [size]
40
+ dimensions = ''.join(
41
+ '[{}]'.format('' if value is None else positive('size', value))
42
+ for value in sizes
43
+ )
44
+ super().__init__(
45
+ key=name,
46
+ type=list,
47
+ typestr='{}{}{}'.format(
48
+ element,
49
+ '({})'.format(typesize) if typesize else '',
50
+ dimensions,
51
+ ),
52
+ va=va,
53
+ null=null,
54
+ default=default,
55
+ )
56
+ return
57
+
58
+ def convert(self, value):
59
+ if isinstance(value, tuple):
60
+ return list(value)
61
+ return value
@@ -0,0 +1,34 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from dataclasses import MISSING
4
+
5
+ from ..Type import Type
6
+
7
+ __all__ = (
8
+ 'Binary',
9
+ )
10
+
11
+
12
+ class Binary(Type, typestr='BYTEA'):
13
+ """BYTEA column accepting bytes, bytearray, or memoryview values as bytes."""
14
+
15
+ def __init__(
16
+ self,
17
+ name=None,
18
+ va=None,
19
+ null=False,
20
+ default=MISSING,
21
+ ):
22
+ super().__init__(
23
+ key=name,
24
+ type=bytes,
25
+ va=va,
26
+ null=null,
27
+ default=default,
28
+ )
29
+ return
30
+
31
+ def convert(self, value):
32
+ if isinstance(value, (bytearray, memoryview)):
33
+ return bytes(value)
34
+ return value
@@ -0,0 +1,29 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from dataclasses import MISSING
4
+
5
+ from ..Type import Type
6
+
7
+ __all__ = (
8
+ 'Bool',
9
+ )
10
+
11
+
12
+ class Bool(Type, typestr='BOOLEAN'):
13
+ """BOOLEAN column specification."""
14
+
15
+ def __init__(
16
+ self,
17
+ name=None,
18
+ va=None,
19
+ null=False,
20
+ default=MISSING,
21
+ ):
22
+ super().__init__(
23
+ key=name,
24
+ type=bool,
25
+ va=va,
26
+ null=null,
27
+ default=default,
28
+ )
29
+ return
@@ -0,0 +1,120 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from dataclasses import MISSING
4
+ from datetime import (
5
+ date,
6
+ datetime,
7
+ time,
8
+ timezone as tz,
9
+ )
10
+
11
+ from ..Type import Type
12
+
13
+ __all__ = (
14
+ 'Timestamp',
15
+ 'Date',
16
+ 'Time',
17
+ )
18
+
19
+
20
+ class Timestamp(Type, typestr='TIMESTAMP'):
21
+ """TIMESTAMP column; timezone=True requires aware values, otherwise values must be naive."""
22
+
23
+ def __init__(
24
+ self,
25
+ name=None,
26
+ timezone=False,
27
+ va=None,
28
+ null=False,
29
+ default=MISSING,
30
+ ):
31
+ if not isinstance(timezone, bool):
32
+ raise TypeError('timezone must be a bool')
33
+ super().__init__(
34
+ key=name,
35
+ type=datetime,
36
+ typestr='TIMESTAMP WITH TIME ZONE' if timezone else 'TIMESTAMP',
37
+ va=va,
38
+ null=null,
39
+ default=default,
40
+ )
41
+ self.timezone = timezone
42
+ return
43
+
44
+ def convert(self, value):
45
+ if isinstance(value, str):
46
+ return datetime.fromisoformat(value)
47
+ if isinstance(value, float):
48
+ return datetime.fromtimestamp(value, tz=tz.utc if self.timezone else None)
49
+ return value
50
+
51
+ def check(self, value) -> bool:
52
+ if not super().check(value):
53
+ return False
54
+ aware = value.tzinfo is not None and value.tzinfo.utcoffset(value) is not None
55
+ if aware != self.timezone:
56
+ raise ValueError('Column {} requires a timezone-{} datetime'.format(
57
+ self.key,
58
+ 'aware' if self.timezone else 'naive',
59
+ ))
60
+ return True
61
+
62
+
63
+ class Date(Type, typestr='DATE'):
64
+ """DATE column accepting date objects or ISO strings; datetime values are rejected."""
65
+
66
+ def __init__(
67
+ self,
68
+ name=None,
69
+ va=None,
70
+ null=False,
71
+ default=MISSING,
72
+ ):
73
+ super().__init__(
74
+ key=name,
75
+ type=date,
76
+ va=va,
77
+ null=null,
78
+ default=default,
79
+ )
80
+ return
81
+
82
+ def convert(self, value):
83
+ if isinstance(value, str):
84
+ return date.fromisoformat(value)
85
+ return value
86
+
87
+ def check(self, value) -> bool:
88
+ return super().check(value) and not isinstance(value, datetime)
89
+
90
+
91
+ class Time(Type, typestr='TIME'):
92
+ """TIME column accepting only timezone-naive time objects or ISO strings."""
93
+
94
+ def __init__(
95
+ self,
96
+ name=None,
97
+ va=None,
98
+ null=False,
99
+ default=MISSING,
100
+ ):
101
+ super().__init__(
102
+ key=name,
103
+ type=time,
104
+ va=va,
105
+ null=null,
106
+ default=default,
107
+ )
108
+ return
109
+
110
+ def convert(self, value):
111
+ if isinstance(value, str):
112
+ return time.fromisoformat(value)
113
+ return value
114
+
115
+ def check(self, value) -> bool:
116
+ if not super().check(value):
117
+ return False
118
+ if value.tzinfo is not None and value.utcoffset() is not None:
119
+ raise ValueError('Column {} requires a timezone-naive time'.format(self.key))
120
+ return True
@@ -0,0 +1,52 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from dataclasses import MISSING
4
+
5
+ from psycopg.types.json import (
6
+ Json,
7
+ Jsonb,
8
+ )
9
+
10
+ from ..Adapters.JavaScriptObjectNotation import encode
11
+ from ..Type import Type
12
+
13
+ __all__ = (
14
+ 'JavaScriptObjectNotation',
15
+ 'JavaScriptObjectNotationByteArray',
16
+ )
17
+
18
+
19
+ def dumps(value) -> str:
20
+ from json import dumps as serialize
21
+ return serialize(value, default=encode, allow_nan=False, ensure_ascii=False)
22
+
23
+
24
+ class JavaScriptObjectNotation(Type, typestr='JSON'):
25
+ """JSON column accepting dict or list values."""
26
+
27
+ wrapper = Json
28
+
29
+ def __init__(
30
+ self,
31
+ name=None,
32
+ va=None,
33
+ null=False,
34
+ default=MISSING,
35
+ ):
36
+ super().__init__(
37
+ key=name,
38
+ type=(dict, list),
39
+ va=va,
40
+ null=null,
41
+ default=default,
42
+ )
43
+ return
44
+
45
+ def adapt(self, value):
46
+ return self.wrapper(value, dumps=dumps)
47
+
48
+
49
+ class JavaScriptObjectNotationByteArray(JavaScriptObjectNotation, typestr='JSONB'):
50
+ """JSONB column accepting dict or list values."""
51
+
52
+ wrapper = Jsonb
@@ -0,0 +1,151 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from dataclasses import MISSING
4
+ from decimal import Decimal as PythonDecimal
5
+
6
+ from ..Type import Type
7
+ from .Size import positive
8
+
9
+ __all__ = (
10
+ 'Short',
11
+ 'Integer',
12
+ 'Long',
13
+ 'Float',
14
+ 'Double',
15
+ 'Decimal',
16
+ )
17
+
18
+
19
+ class Short(Type, typestr='SMALLINT'):
20
+ """SMALLINT column specification."""
21
+
22
+ def __init__(
23
+ self,
24
+ name=None,
25
+ va=None,
26
+ null=False,
27
+ default=MISSING,
28
+ ):
29
+ super().__init__(
30
+ key=name,
31
+ type=int,
32
+ va=va,
33
+ null=null,
34
+ default=default,
35
+ )
36
+ return
37
+
38
+
39
+ class Integer(Type, typestr='INTEGER'):
40
+ """INTEGER column specification."""
41
+
42
+ def __init__(
43
+ self,
44
+ name=None,
45
+ va=None,
46
+ null=False,
47
+ default=MISSING,
48
+ ):
49
+ super().__init__(
50
+ key=name,
51
+ type=int,
52
+ va=va,
53
+ null=null,
54
+ default=default,
55
+ )
56
+ return
57
+
58
+
59
+ class Long(Type, typestr='BIGINT'):
60
+ """BIGINT column specification."""
61
+
62
+ def __init__(
63
+ self,
64
+ name=None,
65
+ va=None,
66
+ null=False,
67
+ default=MISSING,
68
+ ):
69
+ super().__init__(
70
+ key=name,
71
+ type=int,
72
+ va=va,
73
+ null=null,
74
+ default=default,
75
+ )
76
+ return
77
+
78
+
79
+ class FloatingPoint(Type):
80
+ """Floating-point column accepting int values as floats."""
81
+
82
+ def __init__(
83
+ self,
84
+ name=None,
85
+ va=None,
86
+ null=False,
87
+ default=MISSING,
88
+ ):
89
+ super().__init__(
90
+ key=name,
91
+ type=float,
92
+ va=va,
93
+ null=null,
94
+ default=default,
95
+ )
96
+ return
97
+
98
+ def convert(self, value):
99
+ if isinstance(value, int) and not isinstance(value, bool):
100
+ return float(value)
101
+ return value
102
+
103
+
104
+ class Float(FloatingPoint, typestr='REAL'):
105
+ """REAL column specification."""
106
+
107
+
108
+ class Double(FloatingPoint, typestr='DOUBLE PRECISION'):
109
+ """DOUBLE PRECISION column specification."""
110
+
111
+
112
+ class Decimal(Type, typestr='NUMERIC'):
113
+ """NUMERIC(precision, scale) column specification accepting int values as Decimal."""
114
+
115
+ def __init__(
116
+ self,
117
+ name=None,
118
+ precision=None,
119
+ scale=None,
120
+ va=None,
121
+ null=False,
122
+ default=MISSING,
123
+ ):
124
+ precision = positive('precision', precision)
125
+ if scale is not None:
126
+ if precision is None:
127
+ raise ValueError('scale requires precision')
128
+ if type(scale) is not int:
129
+ raise ValueError('scale must be an int')
130
+ if precision is None:
131
+ typestr = 'NUMERIC'
132
+ elif scale is None:
133
+ typestr = 'NUMERIC({})'.format(precision)
134
+ else:
135
+ typestr = 'NUMERIC({},{})'.format(precision, scale)
136
+ super().__init__(
137
+ key=name,
138
+ type=PythonDecimal,
139
+ typestr=typestr,
140
+ va=va,
141
+ null=null,
142
+ default=default,
143
+ )
144
+ self.precision = precision
145
+ self.scale = scale
146
+ return
147
+
148
+ def convert(self, value):
149
+ if isinstance(value, int) and not isinstance(value, bool):
150
+ return PythonDecimal(value)
151
+ return value
@@ -0,0 +1,13 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ __all__ = (
4
+ 'positive',
5
+ )
6
+
7
+
8
+ def positive(name: str, value, null: bool = True):
9
+ if value is None and null:
10
+ return None
11
+ if type(value) is not int or value < 1:
12
+ raise ValueError('{} must be a positive int'.format(name))
13
+ return value
@@ -0,0 +1,80 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from dataclasses import MISSING
4
+
5
+ from ..Type import Type
6
+ from .Size import positive
7
+
8
+ __all__ = (
9
+ 'Char',
10
+ 'String',
11
+ 'Text',
12
+ )
13
+
14
+
15
+ class Char(Type, typestr='CHAR'):
16
+ """CHAR(size) column specification; PostgreSQL pads stored values with spaces."""
17
+
18
+ def __init__(
19
+ self,
20
+ name=None,
21
+ size=None,
22
+ va=None,
23
+ null=False,
24
+ default=MISSING,
25
+ ):
26
+ size = positive('size', size)
27
+ super().__init__(
28
+ key=name,
29
+ type=str,
30
+ typestr='CHAR({})'.format(size) if size else 'CHAR',
31
+ va=va,
32
+ null=null,
33
+ default=default,
34
+ )
35
+ self.size = size
36
+ return
37
+
38
+
39
+ class String(Type, typestr='VARCHAR'):
40
+ """VARCHAR(size) column specification."""
41
+
42
+ def __init__(
43
+ self,
44
+ name=None,
45
+ size=None,
46
+ va=None,
47
+ null=False,
48
+ default=MISSING,
49
+ ):
50
+ size = positive('size', size)
51
+ super().__init__(
52
+ key=name,
53
+ type=str,
54
+ typestr='VARCHAR({})'.format(size) if size else 'VARCHAR',
55
+ va=va,
56
+ null=null,
57
+ default=default,
58
+ )
59
+ self.size = size
60
+ return
61
+
62
+
63
+ class Text(Type, typestr='TEXT'):
64
+ """TEXT column specification."""
65
+
66
+ def __init__(
67
+ self,
68
+ name=None,
69
+ va=None,
70
+ null=False,
71
+ default=MISSING,
72
+ ):
73
+ super().__init__(
74
+ key=name,
75
+ type=str,
76
+ va=va,
77
+ null=null,
78
+ default=default,
79
+ )
80
+ return