crate 0.35.2__py2.py3-none-any.whl → 1.0.0.dev0__py2.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.
- crate/client/__init__.py +1 -1
- crate/testing/test_datetime_old.py +90 -0
- crate-1.0.0.dev0-py3.11-nspkg.pth +1 -0
- {crate-0.35.2.dist-info → crate-1.0.0.dev0.dist-info}/METADATA +15 -19
- crate-1.0.0.dev0.dist-info/RECORD +26 -0
- {crate-0.35.2.dist-info → crate-1.0.0.dev0.dist-info}/WHEEL +1 -1
- crate/client/sqlalchemy/__init__.py +0 -50
- crate/client/sqlalchemy/compat/__init__.py +0 -0
- crate/client/sqlalchemy/compat/api13.py +0 -156
- crate/client/sqlalchemy/compat/core10.py +0 -264
- crate/client/sqlalchemy/compat/core14.py +0 -359
- crate/client/sqlalchemy/compat/core20.py +0 -447
- crate/client/sqlalchemy/compiler.py +0 -318
- crate/client/sqlalchemy/dialect.py +0 -369
- crate/client/sqlalchemy/predicates/__init__.py +0 -99
- crate/client/sqlalchemy/sa_version.py +0 -28
- crate/client/sqlalchemy/support.py +0 -62
- crate/client/sqlalchemy/tests/__init__.py +0 -59
- crate/client/sqlalchemy/tests/array_test.py +0 -111
- crate/client/sqlalchemy/tests/bulk_test.py +0 -256
- crate/client/sqlalchemy/tests/compiler_test.py +0 -434
- crate/client/sqlalchemy/tests/connection_test.py +0 -129
- crate/client/sqlalchemy/tests/create_table_test.py +0 -313
- crate/client/sqlalchemy/tests/datetime_test.py +0 -90
- crate/client/sqlalchemy/tests/dialect_test.py +0 -156
- crate/client/sqlalchemy/tests/dict_test.py +0 -460
- crate/client/sqlalchemy/tests/function_test.py +0 -47
- crate/client/sqlalchemy/tests/insert_from_select_test.py +0 -85
- crate/client/sqlalchemy/tests/match_test.py +0 -137
- crate/client/sqlalchemy/tests/query_caching.py +0 -143
- crate/client/sqlalchemy/tests/update_test.py +0 -115
- crate/client/sqlalchemy/tests/warnings_test.py +0 -64
- crate/client/sqlalchemy/types.py +0 -277
- crate/client/tests.py +0 -416
- crate/testing/tests.py +0 -34
- crate-0.35.2-py3.11-nspkg.pth +0 -1
- crate-0.35.2.dist-info/RECORD +0 -55
- crate-0.35.2.dist-info/entry_points.txt +0 -2
- {crate-0.35.2.dist-info → crate-1.0.0.dev0.dist-info}/LICENSE +0 -0
- {crate-0.35.2.dist-info → crate-1.0.0.dev0.dist-info}/NOTICE +0 -0
- {crate-0.35.2.dist-info → crate-1.0.0.dev0.dist-info}/namespace_packages.txt +0 -0
- {crate-0.35.2.dist-info → crate-1.0.0.dev0.dist-info}/top_level.txt +0 -0
@@ -1,460 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8; -*-
|
2
|
-
#
|
3
|
-
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
|
-
# license agreements. See the NOTICE file distributed with this work for
|
5
|
-
# additional information regarding copyright ownership. Crate licenses
|
6
|
-
# this file to you under the Apache License, Version 2.0 (the "License");
|
7
|
-
# you may not use this file except in compliance with the License. You may
|
8
|
-
# obtain a copy of the License at
|
9
|
-
#
|
10
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
#
|
12
|
-
# Unless required by applicable law or agreed to in writing, software
|
13
|
-
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
-
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
-
# License for the specific language governing permissions and limitations
|
16
|
-
# under the License.
|
17
|
-
#
|
18
|
-
# However, if you have executed another commercial license agreement
|
19
|
-
# with Crate these terms will supersede the license and you may use the
|
20
|
-
# software solely pursuant to the terms of the relevant commercial agreement.
|
21
|
-
|
22
|
-
from __future__ import absolute_import
|
23
|
-
from unittest import TestCase
|
24
|
-
from unittest.mock import patch, MagicMock
|
25
|
-
|
26
|
-
import sqlalchemy as sa
|
27
|
-
from sqlalchemy.sql import select
|
28
|
-
from sqlalchemy.orm import Session
|
29
|
-
try:
|
30
|
-
from sqlalchemy.orm import declarative_base
|
31
|
-
except ImportError:
|
32
|
-
from sqlalchemy.ext.declarative import declarative_base
|
33
|
-
|
34
|
-
from crate.client.sqlalchemy.types import ObjectArray, ObjectType
|
35
|
-
from crate.client.cursor import Cursor
|
36
|
-
|
37
|
-
|
38
|
-
fake_cursor = MagicMock(name='fake_cursor')
|
39
|
-
FakeCursor = MagicMock(name='FakeCursor', spec=Cursor)
|
40
|
-
FakeCursor.return_value = fake_cursor
|
41
|
-
|
42
|
-
|
43
|
-
class SqlAlchemyDictTypeTest(TestCase):
|
44
|
-
|
45
|
-
def setUp(self):
|
46
|
-
self.engine = sa.create_engine('crate://')
|
47
|
-
metadata = sa.MetaData()
|
48
|
-
self.mytable = sa.Table('mytable', metadata,
|
49
|
-
sa.Column('name', sa.String),
|
50
|
-
sa.Column('data', ObjectType))
|
51
|
-
|
52
|
-
def assertSQL(self, expected_str, selectable):
|
53
|
-
actual_expr = selectable.compile(bind=self.engine)
|
54
|
-
self.assertEqual(expected_str, str(actual_expr).replace('\n', ''))
|
55
|
-
|
56
|
-
def test_select_with_dict_column(self):
|
57
|
-
mytable = self.mytable
|
58
|
-
self.assertSQL(
|
59
|
-
"SELECT mytable.data['x'] AS anon_1 FROM mytable",
|
60
|
-
select(mytable.c.data['x'])
|
61
|
-
)
|
62
|
-
|
63
|
-
def test_select_with_dict_column_where_clause(self):
|
64
|
-
mytable = self.mytable
|
65
|
-
s = select(mytable.c.data).\
|
66
|
-
where(mytable.c.data['x'] == 1)
|
67
|
-
self.assertSQL(
|
68
|
-
"SELECT mytable.data FROM mytable WHERE mytable.data['x'] = ?",
|
69
|
-
s
|
70
|
-
)
|
71
|
-
|
72
|
-
def test_select_with_dict_column_nested_where(self):
|
73
|
-
mytable = self.mytable
|
74
|
-
s = select(mytable.c.name)
|
75
|
-
s = s.where(mytable.c.data['x']['y'] == 1)
|
76
|
-
self.assertSQL(
|
77
|
-
"SELECT mytable.name FROM mytable " +
|
78
|
-
"WHERE mytable.data['x']['y'] = ?",
|
79
|
-
s
|
80
|
-
)
|
81
|
-
|
82
|
-
def test_select_with_dict_column_where_clause_gt(self):
|
83
|
-
mytable = self.mytable
|
84
|
-
s = select(mytable.c.data).\
|
85
|
-
where(mytable.c.data['x'] > 1)
|
86
|
-
self.assertSQL(
|
87
|
-
"SELECT mytable.data FROM mytable WHERE mytable.data['x'] > ?",
|
88
|
-
s
|
89
|
-
)
|
90
|
-
|
91
|
-
def test_select_with_dict_column_where_clause_other_col(self):
|
92
|
-
mytable = self.mytable
|
93
|
-
s = select(mytable.c.name)
|
94
|
-
s = s.where(mytable.c.data['x'] == mytable.c.name)
|
95
|
-
self.assertSQL(
|
96
|
-
"SELECT mytable.name FROM mytable " +
|
97
|
-
"WHERE mytable.data['x'] = mytable.name",
|
98
|
-
s
|
99
|
-
)
|
100
|
-
|
101
|
-
def test_update_with_dict_column(self):
|
102
|
-
mytable = self.mytable
|
103
|
-
stmt = mytable.update().\
|
104
|
-
where(mytable.c.name == 'Arthur Dent').\
|
105
|
-
values({
|
106
|
-
"data['x']": "Trillian"
|
107
|
-
})
|
108
|
-
self.assertSQL(
|
109
|
-
"UPDATE mytable SET data['x'] = ? WHERE mytable.name = ?",
|
110
|
-
stmt
|
111
|
-
)
|
112
|
-
|
113
|
-
def set_up_character_and_cursor(self, return_value=None):
|
114
|
-
return_value = return_value or [('Trillian', {})]
|
115
|
-
fake_cursor.fetchall.return_value = return_value
|
116
|
-
fake_cursor.description = (
|
117
|
-
('characters_name', None, None, None, None, None, None),
|
118
|
-
('characters_data', None, None, None, None, None, None)
|
119
|
-
)
|
120
|
-
fake_cursor.rowcount = 1
|
121
|
-
Base = declarative_base()
|
122
|
-
|
123
|
-
class Character(Base):
|
124
|
-
__tablename__ = 'characters'
|
125
|
-
name = sa.Column(sa.String, primary_key=True)
|
126
|
-
age = sa.Column(sa.Integer)
|
127
|
-
data = sa.Column(ObjectType)
|
128
|
-
data_list = sa.Column(ObjectArray)
|
129
|
-
|
130
|
-
session = Session(bind=self.engine)
|
131
|
-
return session, Character
|
132
|
-
|
133
|
-
def test_assign_null_to_object_array(self):
|
134
|
-
session, Character = self.set_up_character_and_cursor()
|
135
|
-
char_1 = Character(name='Trillian', data_list=None)
|
136
|
-
self.assertIsNone(char_1.data_list)
|
137
|
-
char_2 = Character(name='Trillian', data_list=1)
|
138
|
-
self.assertEqual(char_2.data_list, [1])
|
139
|
-
char_3 = Character(name='Trillian', data_list=[None])
|
140
|
-
self.assertEqual(char_3.data_list, [None])
|
141
|
-
|
142
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
143
|
-
def test_assign_to_object_type_after_commit(self):
|
144
|
-
session, Character = self.set_up_character_and_cursor(
|
145
|
-
return_value=[('Trillian', None)]
|
146
|
-
)
|
147
|
-
char = Character(name='Trillian')
|
148
|
-
session.add(char)
|
149
|
-
session.commit()
|
150
|
-
char.data = {'x': 1}
|
151
|
-
self.assertIn(char, session.dirty)
|
152
|
-
session.commit()
|
153
|
-
fake_cursor.execute.assert_called_with(
|
154
|
-
"UPDATE characters SET data = ? WHERE characters.name = ?",
|
155
|
-
({'x': 1}, 'Trillian',)
|
156
|
-
)
|
157
|
-
|
158
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
159
|
-
def test_change_tracking(self):
|
160
|
-
session, Character = self.set_up_character_and_cursor()
|
161
|
-
char = Character(name='Trillian')
|
162
|
-
session.add(char)
|
163
|
-
session.commit()
|
164
|
-
|
165
|
-
try:
|
166
|
-
char.data['x'] = 1
|
167
|
-
except Exception:
|
168
|
-
print(fake_cursor.fetchall.called)
|
169
|
-
print(fake_cursor.mock_calls)
|
170
|
-
raise
|
171
|
-
|
172
|
-
self.assertIn(char, session.dirty)
|
173
|
-
try:
|
174
|
-
session.commit()
|
175
|
-
except Exception:
|
176
|
-
print(fake_cursor.mock_calls)
|
177
|
-
raise
|
178
|
-
self.assertNotIn(char, session.dirty)
|
179
|
-
|
180
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
181
|
-
def test_partial_dict_update(self):
|
182
|
-
session, Character = self.set_up_character_and_cursor()
|
183
|
-
char = Character(name='Trillian')
|
184
|
-
session.add(char)
|
185
|
-
session.commit()
|
186
|
-
char.data['x'] = 1
|
187
|
-
char.data['y'] = 2
|
188
|
-
session.commit()
|
189
|
-
|
190
|
-
# on python 3 dicts aren't sorted so the order if x or y is updated
|
191
|
-
# first isn't deterministic
|
192
|
-
try:
|
193
|
-
fake_cursor.execute.assert_called_with(
|
194
|
-
("UPDATE characters SET data['y'] = ?, data['x'] = ? "
|
195
|
-
"WHERE characters.name = ?"),
|
196
|
-
(2, 1, 'Trillian')
|
197
|
-
)
|
198
|
-
except AssertionError:
|
199
|
-
fake_cursor.execute.assert_called_with(
|
200
|
-
("UPDATE characters SET data['x'] = ?, data['y'] = ? "
|
201
|
-
"WHERE characters.name = ?"),
|
202
|
-
(1, 2, 'Trillian')
|
203
|
-
)
|
204
|
-
|
205
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
206
|
-
def test_partial_dict_update_only_one_key_changed(self):
|
207
|
-
"""
|
208
|
-
If only one attribute of Crate is changed
|
209
|
-
the update should only update that attribute
|
210
|
-
not all attributes of Crate.
|
211
|
-
"""
|
212
|
-
session, Character = self.set_up_character_and_cursor(
|
213
|
-
return_value=[('Trillian', dict(x=1, y=2))]
|
214
|
-
)
|
215
|
-
|
216
|
-
char = Character(name='Trillian')
|
217
|
-
char.data = dict(x=1, y=2)
|
218
|
-
session.add(char)
|
219
|
-
session.commit()
|
220
|
-
char.data['y'] = 3
|
221
|
-
session.commit()
|
222
|
-
fake_cursor.execute.assert_called_with(
|
223
|
-
("UPDATE characters SET data['y'] = ? "
|
224
|
-
"WHERE characters.name = ?"),
|
225
|
-
(3, 'Trillian')
|
226
|
-
)
|
227
|
-
|
228
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
229
|
-
def test_partial_dict_update_with_regular_column(self):
|
230
|
-
session, Character = self.set_up_character_and_cursor()
|
231
|
-
|
232
|
-
char = Character(name='Trillian')
|
233
|
-
session.add(char)
|
234
|
-
session.commit()
|
235
|
-
char.data['x'] = 1
|
236
|
-
char.age = 20
|
237
|
-
session.commit()
|
238
|
-
fake_cursor.execute.assert_called_with(
|
239
|
-
("UPDATE characters SET age = ?, data['x'] = ? "
|
240
|
-
"WHERE characters.name = ?"),
|
241
|
-
(20, 1, 'Trillian')
|
242
|
-
)
|
243
|
-
|
244
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
245
|
-
def test_partial_dict_update_with_delitem(self):
|
246
|
-
session, Character = self.set_up_character_and_cursor(
|
247
|
-
return_value=[('Trillian', {'x': 1})]
|
248
|
-
)
|
249
|
-
|
250
|
-
char = Character(name='Trillian')
|
251
|
-
char.data = {'x': 1}
|
252
|
-
session.add(char)
|
253
|
-
session.commit()
|
254
|
-
del char.data['x']
|
255
|
-
self.assertIn(char, session.dirty)
|
256
|
-
session.commit()
|
257
|
-
fake_cursor.execute.assert_called_with(
|
258
|
-
("UPDATE characters SET data['x'] = ? "
|
259
|
-
"WHERE characters.name = ?"),
|
260
|
-
(None, 'Trillian')
|
261
|
-
)
|
262
|
-
|
263
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
264
|
-
def test_partial_dict_update_with_delitem_setitem(self):
|
265
|
-
""" test that the change tracking doesn't get messed up
|
266
|
-
|
267
|
-
delitem -> setitem
|
268
|
-
"""
|
269
|
-
session, Character = self.set_up_character_and_cursor(
|
270
|
-
return_value=[('Trillian', {'x': 1})]
|
271
|
-
)
|
272
|
-
|
273
|
-
session = Session(bind=self.engine)
|
274
|
-
char = Character(name='Trillian')
|
275
|
-
char.data = {'x': 1}
|
276
|
-
session.add(char)
|
277
|
-
session.commit()
|
278
|
-
del char.data['x']
|
279
|
-
char.data['x'] = 4
|
280
|
-
self.assertIn(char, session.dirty)
|
281
|
-
session.commit()
|
282
|
-
fake_cursor.execute.assert_called_with(
|
283
|
-
("UPDATE characters SET data['x'] = ? "
|
284
|
-
"WHERE characters.name = ?"),
|
285
|
-
(4, 'Trillian')
|
286
|
-
)
|
287
|
-
|
288
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
289
|
-
def test_partial_dict_update_with_setitem_delitem(self):
|
290
|
-
""" test that the change tracking doesn't get messed up
|
291
|
-
|
292
|
-
setitem -> delitem
|
293
|
-
"""
|
294
|
-
session, Character = self.set_up_character_and_cursor(
|
295
|
-
return_value=[('Trillian', {'x': 1})]
|
296
|
-
)
|
297
|
-
|
298
|
-
char = Character(name='Trillian')
|
299
|
-
char.data = {'x': 1}
|
300
|
-
session.add(char)
|
301
|
-
session.commit()
|
302
|
-
char.data['x'] = 4
|
303
|
-
del char.data['x']
|
304
|
-
self.assertIn(char, session.dirty)
|
305
|
-
session.commit()
|
306
|
-
fake_cursor.execute.assert_called_with(
|
307
|
-
("UPDATE characters SET data['x'] = ? "
|
308
|
-
"WHERE characters.name = ?"),
|
309
|
-
(None, 'Trillian')
|
310
|
-
)
|
311
|
-
|
312
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
313
|
-
def test_partial_dict_update_with_setitem_delitem_setitem(self):
|
314
|
-
""" test that the change tracking doesn't get messed up
|
315
|
-
|
316
|
-
setitem -> delitem -> setitem
|
317
|
-
"""
|
318
|
-
session, Character = self.set_up_character_and_cursor(
|
319
|
-
return_value=[('Trillian', {'x': 1})]
|
320
|
-
)
|
321
|
-
|
322
|
-
char = Character(name='Trillian')
|
323
|
-
char.data = {'x': 1}
|
324
|
-
session.add(char)
|
325
|
-
session.commit()
|
326
|
-
char.data['x'] = 4
|
327
|
-
del char.data['x']
|
328
|
-
char.data['x'] = 3
|
329
|
-
self.assertIn(char, session.dirty)
|
330
|
-
session.commit()
|
331
|
-
fake_cursor.execute.assert_called_with(
|
332
|
-
("UPDATE characters SET data['x'] = ? "
|
333
|
-
"WHERE characters.name = ?"),
|
334
|
-
(3, 'Trillian')
|
335
|
-
)
|
336
|
-
|
337
|
-
def set_up_character_and_cursor_data_list(self, return_value=None):
|
338
|
-
return_value = return_value or [('Trillian', {})]
|
339
|
-
fake_cursor.fetchall.return_value = return_value
|
340
|
-
fake_cursor.description = (
|
341
|
-
('characters_name', None, None, None, None, None, None),
|
342
|
-
('characters_data_list', None, None, None, None, None, None)
|
343
|
-
|
344
|
-
)
|
345
|
-
fake_cursor.rowcount = 1
|
346
|
-
Base = declarative_base()
|
347
|
-
|
348
|
-
class Character(Base):
|
349
|
-
__tablename__ = 'characters'
|
350
|
-
name = sa.Column(sa.String, primary_key=True)
|
351
|
-
data_list = sa.Column(ObjectArray)
|
352
|
-
|
353
|
-
session = Session(bind=self.engine)
|
354
|
-
return session, Character
|
355
|
-
|
356
|
-
def _setup_object_array_char(self):
|
357
|
-
session, Character = self.set_up_character_and_cursor_data_list(
|
358
|
-
return_value=[('Trillian', [{'1': 1}, {'2': 2}])]
|
359
|
-
)
|
360
|
-
char = Character(name='Trillian', data_list=[{'1': 1}, {'2': 2}])
|
361
|
-
session.add(char)
|
362
|
-
session.commit()
|
363
|
-
return session, char
|
364
|
-
|
365
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
366
|
-
def test_object_array_setitem_change_tracking(self):
|
367
|
-
session, char = self._setup_object_array_char()
|
368
|
-
char.data_list[1] = {'3': 3}
|
369
|
-
self.assertIn(char, session.dirty)
|
370
|
-
session.commit()
|
371
|
-
fake_cursor.execute.assert_called_with(
|
372
|
-
("UPDATE characters SET data_list = ? "
|
373
|
-
"WHERE characters.name = ?"),
|
374
|
-
([{'1': 1}, {'3': 3}], 'Trillian')
|
375
|
-
)
|
376
|
-
|
377
|
-
def _setup_nested_object_char(self):
|
378
|
-
session, Character = self.set_up_character_and_cursor(
|
379
|
-
return_value=[('Trillian', {'nested': {'x': 1, 'y': {'z': 2}}})]
|
380
|
-
)
|
381
|
-
char = Character(name='Trillian')
|
382
|
-
char.data = {'nested': {'x': 1, 'y': {'z': 2}}}
|
383
|
-
session.add(char)
|
384
|
-
session.commit()
|
385
|
-
return session, char
|
386
|
-
|
387
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
388
|
-
def test_nested_object_change_tracking(self):
|
389
|
-
session, char = self._setup_nested_object_char()
|
390
|
-
char.data["nested"]["x"] = 3
|
391
|
-
self.assertIn(char, session.dirty)
|
392
|
-
session.commit()
|
393
|
-
fake_cursor.execute.assert_called_with(
|
394
|
-
("UPDATE characters SET data['nested'] = ? "
|
395
|
-
"WHERE characters.name = ?"),
|
396
|
-
({'y': {'z': 2}, 'x': 3}, 'Trillian')
|
397
|
-
)
|
398
|
-
|
399
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
400
|
-
def test_deep_nested_object_change_tracking(self):
|
401
|
-
session, char = self._setup_nested_object_char()
|
402
|
-
# change deep nested object
|
403
|
-
char.data["nested"]["y"]["z"] = 5
|
404
|
-
self.assertIn(char, session.dirty)
|
405
|
-
session.commit()
|
406
|
-
fake_cursor.execute.assert_called_with(
|
407
|
-
("UPDATE characters SET data['nested'] = ? "
|
408
|
-
"WHERE characters.name = ?"),
|
409
|
-
({'y': {'z': 5}, 'x': 1}, 'Trillian')
|
410
|
-
)
|
411
|
-
|
412
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
413
|
-
def test_delete_nested_object_tracking(self):
|
414
|
-
session, char = self._setup_nested_object_char()
|
415
|
-
# delete nested object
|
416
|
-
del char.data["nested"]["y"]["z"]
|
417
|
-
self.assertIn(char, session.dirty)
|
418
|
-
session.commit()
|
419
|
-
fake_cursor.execute.assert_called_with(
|
420
|
-
("UPDATE characters SET data['nested'] = ? "
|
421
|
-
"WHERE characters.name = ?"),
|
422
|
-
({'y': {}, 'x': 1}, 'Trillian')
|
423
|
-
)
|
424
|
-
|
425
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
426
|
-
def test_object_array_append_change_tracking(self):
|
427
|
-
session, char = self._setup_object_array_char()
|
428
|
-
char.data_list.append({'3': 3})
|
429
|
-
self.assertIn(char, session.dirty)
|
430
|
-
|
431
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
432
|
-
def test_object_array_insert_change_tracking(self):
|
433
|
-
session, char = self._setup_object_array_char()
|
434
|
-
char.data_list.insert(0, {'3': 3})
|
435
|
-
self.assertIn(char, session.dirty)
|
436
|
-
|
437
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
438
|
-
def test_object_array_slice_change_tracking(self):
|
439
|
-
session, char = self._setup_object_array_char()
|
440
|
-
char.data_list[:] = [{'3': 3}]
|
441
|
-
self.assertIn(char, session.dirty)
|
442
|
-
|
443
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
444
|
-
def test_object_array_extend_change_tracking(self):
|
445
|
-
session, char = self._setup_object_array_char()
|
446
|
-
char.data_list.extend([{'3': 3}])
|
447
|
-
self.assertIn(char, session.dirty)
|
448
|
-
|
449
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
450
|
-
def test_object_array_pop_change_tracking(self):
|
451
|
-
session, char = self._setup_object_array_char()
|
452
|
-
char.data_list.pop()
|
453
|
-
self.assertIn(char, session.dirty)
|
454
|
-
|
455
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
456
|
-
def test_object_array_remove_change_tracking(self):
|
457
|
-
session, char = self._setup_object_array_char()
|
458
|
-
item = char.data_list[0]
|
459
|
-
char.data_list.remove(item)
|
460
|
-
self.assertIn(char, session.dirty)
|
@@ -1,47 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8; -*-
|
2
|
-
#
|
3
|
-
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
|
-
# license agreements. See the NOTICE file distributed with this work for
|
5
|
-
# additional information regarding copyright ownership. Crate licenses
|
6
|
-
# this file to you under the Apache License, Version 2.0 (the "License");
|
7
|
-
# you may not use this file except in compliance with the License. You may
|
8
|
-
# obtain a copy of the License at
|
9
|
-
#
|
10
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
#
|
12
|
-
# Unless required by applicable law or agreed to in writing, software
|
13
|
-
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
-
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
-
# License for the specific language governing permissions and limitations
|
16
|
-
# under the License.
|
17
|
-
#
|
18
|
-
# However, if you have executed another commercial license agreement
|
19
|
-
# with Crate these terms will supersede the license and you may use the
|
20
|
-
# software solely pursuant to the terms of the relevant commercial agreement.
|
21
|
-
|
22
|
-
from unittest import TestCase
|
23
|
-
|
24
|
-
import sqlalchemy as sa
|
25
|
-
from sqlalchemy.sql.sqltypes import TIMESTAMP
|
26
|
-
try:
|
27
|
-
from sqlalchemy.orm import declarative_base
|
28
|
-
except ImportError:
|
29
|
-
from sqlalchemy.ext.declarative import declarative_base
|
30
|
-
|
31
|
-
|
32
|
-
class SqlAlchemyFunctionTest(TestCase):
|
33
|
-
def setUp(self):
|
34
|
-
Base = declarative_base()
|
35
|
-
|
36
|
-
class Character(Base):
|
37
|
-
__tablename__ = "characters"
|
38
|
-
name = sa.Column(sa.String, primary_key=True)
|
39
|
-
timestamp = sa.Column(sa.DateTime)
|
40
|
-
|
41
|
-
self.Character = Character
|
42
|
-
|
43
|
-
def test_date_trunc_type_is_timestamp(self):
|
44
|
-
f = sa.func.date_trunc("minute", self.Character.timestamp)
|
45
|
-
self.assertEqual(len(f.base_columns), 1)
|
46
|
-
for col in f.base_columns:
|
47
|
-
self.assertIsInstance(col.type, TIMESTAMP)
|
@@ -1,85 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8; -*-
|
2
|
-
#
|
3
|
-
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
|
-
# license agreements. See the NOTICE file distributed with this work for
|
5
|
-
# additional information regarding copyright ownership. Crate licenses
|
6
|
-
# this file to you under the Apache License, Version 2.0 (the "License");
|
7
|
-
# you may not use this file except in compliance with the License. You may
|
8
|
-
# obtain a copy of the License at
|
9
|
-
#
|
10
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
#
|
12
|
-
# Unless required by applicable law or agreed to in writing, software
|
13
|
-
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
-
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
-
# License for the specific language governing permissions and limitations
|
16
|
-
# under the License.
|
17
|
-
#
|
18
|
-
# However, if you have executed another commercial license agreement
|
19
|
-
# with Crate these terms will supersede the license and you may use the
|
20
|
-
# software solely pursuant to the terms of the relevant commercial agreement.
|
21
|
-
|
22
|
-
from datetime import datetime
|
23
|
-
from unittest import TestCase
|
24
|
-
from unittest.mock import patch, MagicMock
|
25
|
-
|
26
|
-
import sqlalchemy as sa
|
27
|
-
from sqlalchemy import select, insert
|
28
|
-
from sqlalchemy.orm import Session
|
29
|
-
try:
|
30
|
-
from sqlalchemy.orm import declarative_base
|
31
|
-
except ImportError:
|
32
|
-
from sqlalchemy.ext.declarative import declarative_base
|
33
|
-
|
34
|
-
from crate.client.cursor import Cursor
|
35
|
-
|
36
|
-
|
37
|
-
fake_cursor = MagicMock(name='fake_cursor')
|
38
|
-
fake_cursor.rowcount = 1
|
39
|
-
FakeCursor = MagicMock(name='FakeCursor', spec=Cursor)
|
40
|
-
FakeCursor.return_value = fake_cursor
|
41
|
-
|
42
|
-
|
43
|
-
class SqlAlchemyInsertFromSelectTest(TestCase):
|
44
|
-
|
45
|
-
def assertSQL(self, expected_str, actual_expr):
|
46
|
-
self.assertEqual(expected_str, str(actual_expr).replace('\n', ''))
|
47
|
-
|
48
|
-
def setUp(self):
|
49
|
-
self.engine = sa.create_engine('crate://')
|
50
|
-
Base = declarative_base()
|
51
|
-
|
52
|
-
class Character(Base):
|
53
|
-
__tablename__ = 'characters'
|
54
|
-
|
55
|
-
name = sa.Column(sa.String, primary_key=True)
|
56
|
-
age = sa.Column(sa.Integer)
|
57
|
-
ts = sa.Column(sa.DateTime, onupdate=datetime.utcnow)
|
58
|
-
status = sa.Column(sa.String)
|
59
|
-
|
60
|
-
class CharacterArchive(Base):
|
61
|
-
__tablename__ = 'characters_archive'
|
62
|
-
|
63
|
-
name = sa.Column(sa.String, primary_key=True)
|
64
|
-
age = sa.Column(sa.Integer)
|
65
|
-
ts = sa.Column(sa.DateTime, onupdate=datetime.utcnow)
|
66
|
-
status = sa.Column(sa.String)
|
67
|
-
|
68
|
-
self.character = Character
|
69
|
-
self.character_archived = CharacterArchive
|
70
|
-
self.session = Session(bind=self.engine)
|
71
|
-
|
72
|
-
@patch('crate.client.connection.Cursor', FakeCursor)
|
73
|
-
def test_insert_from_select_triggered(self):
|
74
|
-
char = self.character(name='Arthur', status='Archived')
|
75
|
-
self.session.add(char)
|
76
|
-
self.session.commit()
|
77
|
-
|
78
|
-
sel = select(self.character.name, self.character.age).where(self.character.status == "Archived")
|
79
|
-
ins = insert(self.character_archived).from_select(['name', 'age'], sel)
|
80
|
-
self.session.execute(ins)
|
81
|
-
self.session.commit()
|
82
|
-
self.assertSQL(
|
83
|
-
"INSERT INTO characters_archive (name, age) SELECT characters.name, characters.age FROM characters WHERE characters.status = ?",
|
84
|
-
ins.compile(bind=self.engine)
|
85
|
-
)
|