Skip to content

Commit 70bdfa1

Browse files
committed
Refactor data type implementations to use their own file each
1 parent af5f967 commit 70bdfa1

File tree

11 files changed

+154
-146
lines changed

11 files changed

+154
-146
lines changed

src/sqlalchemy_cratedb/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@
2323
from .dialect import CrateDialect
2424
from .sa_version import SA_1_4, SA_2_0, SA_VERSION
2525
from .support import insert_bulk
26-
from .types import Geopoint, Geoshape, ObjectArray, ObjectType
27-
26+
from .type.array import ObjectArray
27+
from .type.geo import Geopoint, Geoshape
28+
from .type.object import ObjectType
2829

2930
if SA_VERSION < SA_1_4:
3031
import textwrap

src/sqlalchemy_cratedb/compiler.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
from sqlalchemy.dialects.postgresql.base import PGCompiler
2828
from sqlalchemy.sql import compiler
2929
from sqlalchemy.types import String
30-
from .types import MutableDict, ObjectTypeImpl, Geopoint, Geoshape
30+
from .type.geo import Geopoint, Geoshape
31+
from .type.object import MutableDict, ObjectTypeImpl
3132
from .sa_version import SA_VERSION, SA_1_4
3233

3334

src/sqlalchemy_cratedb/dialect.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
)
3434
from crate.client.exceptions import TimezoneUnawareException
3535
from .sa_version import SA_VERSION, SA_1_4, SA_2_0
36-
from .types import ObjectType, ObjectArray
36+
from .type import ObjectArray, ObjectType
3737

3838
TYPES_MAP = {
3939
"boolean": sqltypes.Boolean,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .array import ObjectArray
2+
from .geo import Geopoint, Geoshape
3+
from .object import ObjectType

src/sqlalchemy_cratedb/types.py renamed to src/sqlalchemy_cratedb/type/array.py

Lines changed: 0 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,12 @@
1818
# However, if you have executed another commercial license agreement
1919
# with Crate these terms will supersede the license and you may use the
2020
# software solely pursuant to the terms of the relevant commercial agreement.
21-
import warnings
2221

2322
import sqlalchemy.types as sqltypes
2423
from sqlalchemy.sql import operators, expression
2524
from sqlalchemy.sql import default_comparator
2625
from sqlalchemy.ext.mutable import Mutable
2726

28-
import geojson
29-
3027

3128
class MutableList(Mutable, list):
3229

@@ -74,91 +71,6 @@ def remove(self, item):
7471
self.changed()
7572

7673

77-
class MutableDict(Mutable, dict):
78-
79-
@classmethod
80-
def coerce(cls, key, value):
81-
"Convert plain dictionaries to MutableDict."
82-
83-
if not isinstance(value, MutableDict):
84-
if isinstance(value, dict):
85-
return MutableDict(value)
86-
87-
# this call will raise ValueError
88-
return Mutable.coerce(key, value)
89-
else:
90-
return value
91-
92-
def __init__(self, initval=None, to_update=None, root_change_key=None):
93-
initval = initval or {}
94-
self._changed_keys = set()
95-
self._deleted_keys = set()
96-
self._overwrite_key = root_change_key
97-
self.to_update = self if to_update is None else to_update
98-
for k in initval:
99-
initval[k] = self._convert_dict(initval[k],
100-
overwrite_key=k if self._overwrite_key is None else self._overwrite_key
101-
)
102-
dict.__init__(self, initval)
103-
104-
def __setitem__(self, key, value):
105-
value = self._convert_dict(value, key if self._overwrite_key is None else self._overwrite_key)
106-
dict.__setitem__(self, key, value)
107-
self.to_update.on_key_changed(
108-
key if self._overwrite_key is None else self._overwrite_key
109-
)
110-
111-
def __delitem__(self, key):
112-
dict.__delitem__(self, key)
113-
# add the key to the deleted keys if this is the root object
114-
# otherwise update on root object
115-
if self._overwrite_key is None:
116-
self._deleted_keys.add(key)
117-
self.changed()
118-
else:
119-
self.to_update.on_key_changed(self._overwrite_key)
120-
121-
def on_key_changed(self, key):
122-
self._deleted_keys.discard(key)
123-
self._changed_keys.add(key)
124-
self.changed()
125-
126-
def _convert_dict(self, value, overwrite_key):
127-
if isinstance(value, dict) and not isinstance(value, MutableDict):
128-
return MutableDict(value, self.to_update, overwrite_key)
129-
return value
130-
131-
def __eq__(self, other):
132-
return dict.__eq__(self, other)
133-
134-
135-
class ObjectTypeImpl(sqltypes.UserDefinedType, sqltypes.JSON):
136-
137-
__visit_name__ = "OBJECT"
138-
139-
cache_ok = False
140-
none_as_null = False
141-
142-
143-
# Designated name to refer to. `Object` is too ambiguous.
144-
ObjectType = MutableDict.as_mutable(ObjectTypeImpl)
145-
146-
# Backward-compatibility aliases.
147-
_deprecated_Craty = ObjectType
148-
_deprecated_Object = ObjectType
149-
150-
# https://www.lesinskis.com/deprecating-module-scope-variables.html
151-
deprecated_names = ["Craty", "Object"]
152-
153-
154-
def __getattr__(name):
155-
if name in deprecated_names:
156-
warnings.warn(f"{name} is deprecated and will be removed in future releases. "
157-
f"Please use ObjectType instead.", DeprecationWarning)
158-
return globals()[f"_deprecated_{name}"]
159-
raise AttributeError(f"module {__name__} has no attribute {name}")
160-
161-
16274
class Any(expression.ColumnElement):
16375
"""Represent the clause ``left operator ANY (right)``. ``right`` must be
16476
an array expression.
@@ -230,48 +142,3 @@ def get_col_spec(self, **kws):
230142

231143

232144
ObjectArray = MutableList.as_mutable(_ObjectArray)
233-
234-
235-
class Geopoint(sqltypes.UserDefinedType):
236-
cache_ok = True
237-
238-
class Comparator(sqltypes.TypeEngine.Comparator):
239-
240-
def __getitem__(self, key):
241-
return default_comparator._binary_operate(self.expr,
242-
operators.getitem,
243-
key)
244-
245-
def get_col_spec(self):
246-
return 'GEO_POINT'
247-
248-
def bind_processor(self, dialect):
249-
def process(value):
250-
if isinstance(value, geojson.Point):
251-
return value.coordinates
252-
return value
253-
return process
254-
255-
def result_processor(self, dialect, coltype):
256-
return tuple
257-
258-
comparator_factory = Comparator
259-
260-
261-
class Geoshape(sqltypes.UserDefinedType):
262-
cache_ok = True
263-
264-
class Comparator(sqltypes.TypeEngine.Comparator):
265-
266-
def __getitem__(self, key):
267-
return default_comparator._binary_operate(self.expr,
268-
operators.getitem,
269-
key)
270-
271-
def get_col_spec(self):
272-
return 'GEO_SHAPE'
273-
274-
def result_processor(self, dialect, coltype):
275-
return geojson.GeoJSON.to_instance
276-
277-
comparator_factory = Comparator

src/sqlalchemy_cratedb/type/geo.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import geojson
2+
from sqlalchemy import types as sqltypes
3+
from sqlalchemy.sql import default_comparator, operators
4+
5+
6+
class Geopoint(sqltypes.UserDefinedType):
7+
cache_ok = True
8+
9+
class Comparator(sqltypes.TypeEngine.Comparator):
10+
11+
def __getitem__(self, key):
12+
return default_comparator._binary_operate(self.expr,
13+
operators.getitem,
14+
key)
15+
16+
def get_col_spec(self):
17+
return 'GEO_POINT'
18+
19+
def bind_processor(self, dialect):
20+
def process(value):
21+
if isinstance(value, geojson.Point):
22+
return value.coordinates
23+
return value
24+
return process
25+
26+
def result_processor(self, dialect, coltype):
27+
return tuple
28+
29+
comparator_factory = Comparator
30+
31+
32+
class Geoshape(sqltypes.UserDefinedType):
33+
cache_ok = True
34+
35+
class Comparator(sqltypes.TypeEngine.Comparator):
36+
37+
def __getitem__(self, key):
38+
return default_comparator._binary_operate(self.expr,
39+
operators.getitem,
40+
key)
41+
42+
def get_col_spec(self):
43+
return 'GEO_SHAPE'
44+
45+
def result_processor(self, dialect, coltype):
46+
return geojson.GeoJSON.to_instance
47+
48+
comparator_factory = Comparator
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import warnings
2+
3+
from sqlalchemy import types as sqltypes
4+
from sqlalchemy.ext.mutable import Mutable
5+
6+
7+
class MutableDict(Mutable, dict):
8+
9+
@classmethod
10+
def coerce(cls, key, value):
11+
"Convert plain dictionaries to MutableDict."
12+
13+
if not isinstance(value, MutableDict):
14+
if isinstance(value, dict):
15+
return MutableDict(value)
16+
17+
# this call will raise ValueError
18+
return Mutable.coerce(key, value)
19+
else:
20+
return value
21+
22+
def __init__(self, initval=None, to_update=None, root_change_key=None):
23+
initval = initval or {}
24+
self._changed_keys = set()
25+
self._deleted_keys = set()
26+
self._overwrite_key = root_change_key
27+
self.to_update = self if to_update is None else to_update
28+
for k in initval:
29+
initval[k] = self._convert_dict(initval[k],
30+
overwrite_key=k if self._overwrite_key is None else self._overwrite_key
31+
)
32+
dict.__init__(self, initval)
33+
34+
def __setitem__(self, key, value):
35+
value = self._convert_dict(value, key if self._overwrite_key is None else self._overwrite_key)
36+
dict.__setitem__(self, key, value)
37+
self.to_update.on_key_changed(
38+
key if self._overwrite_key is None else self._overwrite_key
39+
)
40+
41+
def __delitem__(self, key):
42+
dict.__delitem__(self, key)
43+
# add the key to the deleted keys if this is the root object
44+
# otherwise update on root object
45+
if self._overwrite_key is None:
46+
self._deleted_keys.add(key)
47+
self.changed()
48+
else:
49+
self.to_update.on_key_changed(self._overwrite_key)
50+
51+
def on_key_changed(self, key):
52+
self._deleted_keys.discard(key)
53+
self._changed_keys.add(key)
54+
self.changed()
55+
56+
def _convert_dict(self, value, overwrite_key):
57+
if isinstance(value, dict) and not isinstance(value, MutableDict):
58+
return MutableDict(value, self.to_update, overwrite_key)
59+
return value
60+
61+
def __eq__(self, other):
62+
return dict.__eq__(self, other)
63+
64+
65+
class ObjectTypeImpl(sqltypes.UserDefinedType, sqltypes.JSON):
66+
67+
__visit_name__ = "OBJECT"
68+
69+
cache_ok = False
70+
none_as_null = False
71+
72+
73+
# Designated name to refer to. `Object` is too ambiguous.
74+
ObjectType = MutableDict.as_mutable(ObjectTypeImpl)
75+
76+
# Backward-compatibility aliases.
77+
_deprecated_Craty = ObjectType
78+
_deprecated_Object = ObjectType
79+
80+
# https://www.lesinskis.com/deprecating-module-scope-variables.html
81+
deprecated_names = ["Craty", "Object"]
82+
83+
84+
def __getattr__(name):
85+
if name in deprecated_names:
86+
warnings.warn(f"{name} is deprecated and will be removed in future releases. "
87+
f"Please use ObjectType instead.", DeprecationWarning)
88+
return globals()[f"_deprecated_{name}"]
89+
raise AttributeError(f"module {__name__} has no attribute {name}")
90+
91+
92+
__all__ = deprecated_names

tests/compiler_test.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@
3737
except ImportError:
3838
from sqlalchemy.ext.declarative import declarative_base
3939

40-
from sqlalchemy_cratedb import SA_VERSION, SA_1_4, SA_2_0
41-
from sqlalchemy_cratedb import ObjectType
40+
from sqlalchemy_cratedb import SA_VERSION, SA_1_4, SA_2_0, ObjectType
4241
from crate.client.test_util import ParametrizedTestCase
4342

4443

tests/dialect_test.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@
2626
import sqlalchemy as sa
2727

2828
from crate.client.cursor import Cursor
29-
from sqlalchemy_cratedb import SA_VERSION
29+
from sqlalchemy_cratedb import SA_VERSION, ObjectType
3030
from sqlalchemy_cratedb import SA_1_4, SA_2_0
31-
from sqlalchemy_cratedb import ObjectType
3231
from sqlalchemy import inspect
3332
from sqlalchemy.orm import Session
3433
try:

tests/query_caching.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,14 @@
2626
from sqlalchemy.orm import Session
2727
from sqlalchemy.sql.operators import eq
2828

29-
from sqlalchemy_cratedb import SA_VERSION, SA_1_4
29+
from sqlalchemy_cratedb import SA_VERSION, SA_1_4, ObjectArray, ObjectType
3030
from crate.testing.settings import crate_host
3131

3232
try:
3333
from sqlalchemy.orm import declarative_base
3434
except ImportError:
3535
from sqlalchemy.ext.declarative import declarative_base
3636

37-
from sqlalchemy_cratedb import ObjectType, ObjectArray
38-
3937

4038
class SqlAlchemyQueryCompilationCaching(TestCase):
4139

0 commit comments

Comments
 (0)