relations-sqlite3 0.6.8__tar.gz → 0.6.10__tar.gz
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.
- {relations_sqlite3-0.6.8 → relations_sqlite3-0.6.10}/PKG-INFO +2 -2
- {relations_sqlite3-0.6.8 → relations_sqlite3-0.6.10}/lib/relations_sqlite3.egg-info/PKG-INFO +2 -2
- {relations_sqlite3-0.6.8 → relations_sqlite3-0.6.10}/lib/relations_sqlite3.egg-info/requires.txt +1 -1
- {relations_sqlite3-0.6.8 → relations_sqlite3-0.6.10}/lib/relations_sqlite3.py +44 -6
- {relations_sqlite3-0.6.8 → relations_sqlite3-0.6.10}/setup.py +9 -2
- {relations_sqlite3-0.6.8 → relations_sqlite3-0.6.10}/test/test_relations_sqlite3.py +213 -0
- {relations_sqlite3-0.6.8 → relations_sqlite3-0.6.10}/LICENSE.txt +0 -0
- {relations_sqlite3-0.6.8 → relations_sqlite3-0.6.10}/README.md +0 -0
- {relations_sqlite3-0.6.8 → relations_sqlite3-0.6.10}/lib/relations_sqlite3.egg-info/SOURCES.txt +0 -0
- {relations_sqlite3-0.6.8 → relations_sqlite3-0.6.10}/lib/relations_sqlite3.egg-info/dependency_links.txt +0 -0
- {relations_sqlite3-0.6.8 → relations_sqlite3-0.6.10}/lib/relations_sqlite3.egg-info/top_level.txt +0 -0
- {relations_sqlite3-0.6.8 → relations_sqlite3-0.6.10}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: relations-sqlite3
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.10
|
|
4
4
|
Summary: DB Modeling for SQLite using the sqlite3 library
|
|
5
5
|
Home-page: https://github.com/relations-dil/python-relations-sqlite3
|
|
6
6
|
Author: Gaffer Fitch
|
|
@@ -9,7 +9,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
11
|
License-File: LICENSE.txt
|
|
12
|
-
Requires-Dist: relations-dil>=0.6.
|
|
12
|
+
Requires-Dist: relations-dil>=0.6.16
|
|
13
13
|
Requires-Dist: relations-sqlite>=0.6.3
|
|
14
14
|
|
|
15
15
|
# relations-sqlite3
|
{relations_sqlite3-0.6.8 → relations_sqlite3-0.6.10}/lib/relations_sqlite3.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: relations-sqlite3
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.10
|
|
4
4
|
Summary: DB Modeling for SQLite using the sqlite3 library
|
|
5
5
|
Home-page: https://github.com/relations-dil/python-relations-sqlite3
|
|
6
6
|
Author: Gaffer Fitch
|
|
@@ -9,7 +9,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
11
|
License-File: LICENSE.txt
|
|
12
|
-
Requires-Dist: relations-dil>=0.6.
|
|
12
|
+
Requires-Dist: relations-dil>=0.6.16
|
|
13
13
|
Requires-Dist: relations-sqlite>=0.6.3
|
|
14
14
|
|
|
15
15
|
# relations-sqlite3
|
{relations_sqlite3-0.6.8 → relations_sqlite3-0.6.10}/lib/relations_sqlite3.egg-info/requires.txt
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
relations-dil>=0.6.
|
|
1
|
+
relations-dil>=0.6.16
|
|
2
2
|
relations-sqlite>=0.6.3
|
|
@@ -29,7 +29,9 @@ class Source(relations_sql.SOURCE, relations.Source): # pylint: disable=too-many
|
|
|
29
29
|
OP = relations_sqlite.OP
|
|
30
30
|
|
|
31
31
|
AS = relations_sqlite.AS
|
|
32
|
+
OPTIONS = relations_sqlite.OPTIONS
|
|
32
33
|
FIELDS = relations_sqlite.FIELDS
|
|
34
|
+
COLUMN_NAME = relations_sqlite.COLUMN_NAME
|
|
33
35
|
TABLE = relations_sqlite.TABLE
|
|
34
36
|
TABLE_NAME = relations_sqlite.TABLE_NAME
|
|
35
37
|
|
|
@@ -193,14 +195,30 @@ class Source(relations_sql.SOURCE, relations.Source): # pylint: disable=too-many
|
|
|
193
195
|
|
|
194
196
|
return model
|
|
195
197
|
|
|
196
|
-
def
|
|
198
|
+
def retrieve_record(self, record, query):
|
|
197
199
|
"""
|
|
198
|
-
Adds where
|
|
200
|
+
Adds where clauses to query for all the fields in the record
|
|
201
|
+
"""
|
|
202
|
+
|
|
203
|
+
for field in record._order:
|
|
204
|
+
self.retrieve_field(field, query, record)
|
|
205
|
+
|
|
206
|
+
def retrieve_field(self, field, query, record=None):
|
|
207
|
+
"""
|
|
208
|
+
Adds where caluse to query, an injected field is looked up in the field it's stored in
|
|
199
209
|
"""
|
|
200
210
|
|
|
201
211
|
for operator, value in (field.criteria or {}).items():
|
|
202
|
-
|
|
203
|
-
|
|
212
|
+
|
|
213
|
+
if field.inject:
|
|
214
|
+
stored, path = field.inject.split("__", 1)
|
|
215
|
+
stored = record._names[stored]
|
|
216
|
+
name = f"{stored.store}__{path}__{operator}"
|
|
217
|
+
extracted = path in (stored.extract or {})
|
|
218
|
+
else:
|
|
219
|
+
name = f"{field.store}__{operator}"
|
|
220
|
+
extracted = operator.rsplit("__", 1)[0] in (field.extract or {})
|
|
221
|
+
|
|
204
222
|
query.WHERE(self.OP(name, value, EXTRACTED=extracted))
|
|
205
223
|
|
|
206
224
|
def like(self, model, query):
|
|
@@ -250,7 +268,17 @@ class Source(relations_sql.SOURCE, relations.Source): # pylint: disable=too-many
|
|
|
250
268
|
"""
|
|
251
269
|
|
|
252
270
|
for field in (model._sort or model._order or []):
|
|
253
|
-
|
|
271
|
+
|
|
272
|
+
name = field[1:]
|
|
273
|
+
field_name, path = (name.split("__", 1) + [None])[:2]
|
|
274
|
+
|
|
275
|
+
# an injected field is sorted by its path in the field it's stored in
|
|
276
|
+
|
|
277
|
+
if model._fields._names[field_name].inject:
|
|
278
|
+
stored, injected = model._fields._names[field_name].inject.split("__", 1)
|
|
279
|
+
name = f"{model._fields._names[stored].store}__{injected}" + (f"__{path}" if path else "")
|
|
280
|
+
|
|
281
|
+
query.ORDER_BY(**{name: (self.ASC if field[0] == "+" else self.DESC)})
|
|
254
282
|
|
|
255
283
|
model._sort = None
|
|
256
284
|
|
|
@@ -278,6 +306,11 @@ class Source(relations_sql.SOURCE, relations.Source): # pylint: disable=too-many
|
|
|
278
306
|
self.retrieve_record(model._record, query)
|
|
279
307
|
self.like(model, query)
|
|
280
308
|
|
|
309
|
+
# a sibling-attribute flat join repeats a model tied to several matching siblings, so
|
|
310
|
+
# count the distinct model id instead of the joined rows
|
|
311
|
+
if getattr(model, "_distinct", False):
|
|
312
|
+
query.FIELDS = self.FIELDS(self.AS("total", self.SQL(f"COUNT(DISTINCT {model.STORE}.{model._id})")))
|
|
313
|
+
|
|
281
314
|
return query
|
|
282
315
|
|
|
283
316
|
def retrieve_query(self, model):
|
|
@@ -287,7 +320,12 @@ class Source(relations_sql.SOURCE, relations.Source): # pylint: disable=too-many
|
|
|
287
320
|
|
|
288
321
|
query = self.count_query(model)
|
|
289
322
|
|
|
290
|
-
|
|
323
|
+
# honor the flat-join DISTINCT marker: dedupe the model rows the join multiplied
|
|
324
|
+
if getattr(model, "_distinct", False):
|
|
325
|
+
query.OPTIONS = self.OPTIONS("DISTINCT")
|
|
326
|
+
query.FIELDS = self.FIELDS(self.COLUMN_NAME("*", table=model.STORE))
|
|
327
|
+
else:
|
|
328
|
+
query.FIELDS = self.FIELDS("*")
|
|
291
329
|
|
|
292
330
|
self.sort(model, query)
|
|
293
331
|
self.limit(model, query)
|
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
|
|
3
|
+
import os
|
|
3
4
|
from setuptools import setup
|
|
4
5
|
|
|
5
6
|
with open("README.md", "r") as readme_file:
|
|
6
7
|
long_description = readme_file.read()
|
|
7
8
|
|
|
9
|
+
version = os.environ.get("BUILD_VERSION")
|
|
10
|
+
|
|
11
|
+
if version is None:
|
|
12
|
+
with open("VERSION", "r") as version_file:
|
|
13
|
+
version = version_file.read().strip()
|
|
14
|
+
|
|
8
15
|
setup(
|
|
9
16
|
name="relations-sqlite3",
|
|
10
|
-
version=
|
|
17
|
+
version=version,
|
|
11
18
|
package_dir = {'': 'lib'},
|
|
12
19
|
py_modules = [
|
|
13
20
|
'relations_sqlite3'
|
|
14
21
|
],
|
|
15
22
|
install_requires=[
|
|
16
|
-
'relations-dil>=0.6.
|
|
23
|
+
'relations-dil>=0.6.16',
|
|
17
24
|
'relations-sqlite>=0.6.3'
|
|
18
25
|
],
|
|
19
26
|
url="https://github.com/relations-dil/python-relations-sqlite3",
|
|
@@ -101,6 +101,17 @@ class SisBro(SourceModel):
|
|
|
101
101
|
|
|
102
102
|
relations.ManyToMany(Sis, Bro, SisBro)
|
|
103
103
|
|
|
104
|
+
class Owner(SourceModel):
|
|
105
|
+
id = int
|
|
106
|
+
name = str
|
|
107
|
+
|
|
108
|
+
class Pet(SourceModel):
|
|
109
|
+
id = int
|
|
110
|
+
name = str
|
|
111
|
+
what = dict
|
|
112
|
+
|
|
113
|
+
relations.OneToMany(Owner, Pet, child_inject="what")
|
|
114
|
+
|
|
104
115
|
def dict_factory(cursor, row):
|
|
105
116
|
d = {}
|
|
106
117
|
for idx, col in enumerate(cursor.description):
|
|
@@ -218,6 +229,16 @@ CREATE UNIQUE INDEX `test_source`.`simple_name` ON `simple` (`name`);
|
|
|
218
229
|
|
|
219
230
|
self.source.execute(self.source.define(Simple.thy().define()))
|
|
220
231
|
|
|
232
|
+
# an injected key isn't a column, it's stored in the dict field
|
|
233
|
+
|
|
234
|
+
self.source.execute(Owner.define())
|
|
235
|
+
self.source.execute(Pet.define())
|
|
236
|
+
|
|
237
|
+
cursor = self.source.connection.cursor()
|
|
238
|
+
cursor.execute("PRAGMA test_source.table_info(pet)")
|
|
239
|
+
self.assertEqual([column["name"] for column in cursor.fetchall()], ["id", "name", "what"])
|
|
240
|
+
cursor.close()
|
|
241
|
+
|
|
221
242
|
def test_create_query(self):
|
|
222
243
|
|
|
223
244
|
query = Simple("sure").query()
|
|
@@ -323,6 +344,27 @@ CREATE UNIQUE INDEX `test_source`.`simple_name` ON `simple` (`name`);
|
|
|
323
344
|
|
|
324
345
|
cursor.close()
|
|
325
346
|
|
|
347
|
+
# an injected key is stored in the dict field, whether there's a parent or not
|
|
348
|
+
|
|
349
|
+
self.source.execute(Owner.define())
|
|
350
|
+
self.source.execute(Pet.define())
|
|
351
|
+
|
|
352
|
+
owner = Owner("pat")
|
|
353
|
+
owner.pet.add("rex")
|
|
354
|
+
owner.create()
|
|
355
|
+
|
|
356
|
+
stray = Pet("stray").create()
|
|
357
|
+
|
|
358
|
+
cursor = self.source.connection.cursor()
|
|
359
|
+
cursor.execute("SELECT * FROM test_source.pet ORDER BY name")
|
|
360
|
+
rows = [self.source.values_retrieve(stray, row) for row in cursor.fetchall()]
|
|
361
|
+
cursor.close()
|
|
362
|
+
|
|
363
|
+
self.assertEqual(rows, [
|
|
364
|
+
{"id": 1, "name": "rex", "what": {"relations": {"owner": {"id": owner.id}}}},
|
|
365
|
+
{"id": 2, "name": "stray", "what": {}}
|
|
366
|
+
])
|
|
367
|
+
|
|
326
368
|
def test_retrieve_field(self):
|
|
327
369
|
|
|
328
370
|
field = relations.Field(int, name="id")
|
|
@@ -361,6 +403,37 @@ CREATE UNIQUE INDEX `test_source`.`simple_name` ON `simple` (`name`);
|
|
|
361
403
|
self.assertEqual(query.sql, """SELECT WHERE `things__for__0____1`=?""")
|
|
362
404
|
self.assertEqual(query.args, ['yes'])
|
|
363
405
|
|
|
406
|
+
# an injected key is looked up by its path in the field it's stored in
|
|
407
|
+
|
|
408
|
+
record = copy.deepcopy(Pet.thy()._fields)
|
|
409
|
+
field = record._names["owner_id"]
|
|
410
|
+
field.filter(1)
|
|
411
|
+
query = self.source.SELECT()
|
|
412
|
+
self.source.retrieve_field(field, query, record)
|
|
413
|
+
query.generate()
|
|
414
|
+
self.assertEqual(query.sql, """SELECT WHERE json_extract(`what`,?)=?""")
|
|
415
|
+
self.assertEqual(query.args, ['$.relations.owner.id', 1])
|
|
416
|
+
|
|
417
|
+
record = copy.deepcopy(Pet.thy()._fields)
|
|
418
|
+
field = record._names["owner_id"]
|
|
419
|
+
field.filter([1, 2], "in")
|
|
420
|
+
query = self.source.SELECT()
|
|
421
|
+
self.source.retrieve_field(field, query, record)
|
|
422
|
+
query.generate()
|
|
423
|
+
self.assertEqual(query.sql, """SELECT WHERE json_extract(`what`,?) IN (?,?)""")
|
|
424
|
+
self.assertEqual(query.args, ['$.relations.owner.id', 1, 2])
|
|
425
|
+
|
|
426
|
+
def test_retrieve_record(self):
|
|
427
|
+
|
|
428
|
+
record = copy.deepcopy(Pet.thy()._fields)
|
|
429
|
+
record._names["name"].filter("rex")
|
|
430
|
+
record._names["owner_id"].filter(1)
|
|
431
|
+
query = self.source.SELECT()
|
|
432
|
+
self.source.retrieve_record(record, query)
|
|
433
|
+
query.generate()
|
|
434
|
+
self.assertEqual(query.sql, """SELECT WHERE `name`=? AND json_extract(`what`,?)=?""")
|
|
435
|
+
self.assertEqual(query.args, ["rex", "$.relations.owner.id", 1])
|
|
436
|
+
|
|
364
437
|
def test_like(self):
|
|
365
438
|
|
|
366
439
|
self.source.execute(Unit.define())
|
|
@@ -448,6 +521,16 @@ CREATE UNIQUE INDEX `test_source`.`simple_name` ON `simple` (`name`);
|
|
|
448
521
|
self.assertEqual(query.args, [])
|
|
449
522
|
self.assertIsNone(unit._sort)
|
|
450
523
|
|
|
524
|
+
# an injected key sorts by its path in the field it's stored in
|
|
525
|
+
|
|
526
|
+
pet = Pet.many()
|
|
527
|
+
pet._sort = ['-owner_id']
|
|
528
|
+
query = self.source.SELECT()
|
|
529
|
+
self.source.sort(pet, query)
|
|
530
|
+
query.generate()
|
|
531
|
+
self.assertEqual(query.sql, """SELECT ORDER BY json_extract(`what`,?) DESC""")
|
|
532
|
+
self.assertEqual(query.args, ['$.relations.owner.id'])
|
|
533
|
+
|
|
451
534
|
def test_limit(self):
|
|
452
535
|
|
|
453
536
|
unit = Unit.one()
|
|
@@ -638,6 +721,19 @@ LIMIT ?""")
|
|
|
638
721
|
self.assertEqual(Sis.many(bro_id=[tom.id]).count(), 1)
|
|
639
722
|
self.assertEqual(Sis.many(bro_id=[999]).count(), 0)
|
|
640
723
|
|
|
724
|
+
# an injected key counts like any other
|
|
725
|
+
|
|
726
|
+
self.source.execute(Owner.define())
|
|
727
|
+
self.source.execute(Pet.define())
|
|
728
|
+
|
|
729
|
+
pat = Owner("pat").create()
|
|
730
|
+
|
|
731
|
+
Pet([{"name": "rex", "owner_id": pat.id}, {"name": "stray"}]).create()
|
|
732
|
+
|
|
733
|
+
self.assertEqual(Pet.many().count(), 2)
|
|
734
|
+
self.assertEqual(Pet.many(owner_id=pat.id).count(), 1)
|
|
735
|
+
self.assertEqual(Pet.many(owner_id=99).count(), 0)
|
|
736
|
+
|
|
641
737
|
def test_values_retrieve(self):
|
|
642
738
|
|
|
643
739
|
model = unittest.mock.MagicMock()
|
|
@@ -867,6 +963,37 @@ LIMIT ?""")
|
|
|
867
963
|
|
|
868
964
|
self.assertEqual(len(Sis.many(bro_id=[999])), 0)
|
|
869
965
|
|
|
966
|
+
# an injected key retrieves, filters and relates like a column
|
|
967
|
+
|
|
968
|
+
self.source.execute(Owner.define())
|
|
969
|
+
self.source.execute(Pet.define())
|
|
970
|
+
|
|
971
|
+
pat = Owner("pat").create()
|
|
972
|
+
sam = Owner("sam").create()
|
|
973
|
+
|
|
974
|
+
Pet([
|
|
975
|
+
{"name": "rex", "owner_id": pat.id},
|
|
976
|
+
{"name": "fido", "owner_id": sam.id},
|
|
977
|
+
{"name": "spot", "owner_id": pat.id},
|
|
978
|
+
{"name": "stray"}
|
|
979
|
+
]).create()
|
|
980
|
+
|
|
981
|
+
self.assertEqual(Pet.many(owner_id=pat.id).name, ["rex", "spot"])
|
|
982
|
+
self.assertEqual(Pet.many(owner_id__in=[pat.id, sam.id]).name, ["fido", "rex", "spot"])
|
|
983
|
+
self.assertEqual(Pet.many(owner_id__null=True).name, ["stray"])
|
|
984
|
+
self.assertEqual(Pet.many(owner_id=99).name, [])
|
|
985
|
+
|
|
986
|
+
self.assertEqual(Pet.one(name="rex").owner.name, "pat")
|
|
987
|
+
self.assertIsNone(Pet.one(name="stray").owner)
|
|
988
|
+
|
|
989
|
+
self.assertEqual(Owner.one(pat.id).pet.name, ["rex", "spot"])
|
|
990
|
+
self.assertEqual(Owner.one(name="pat").pet.name, ["rex", "spot"])
|
|
991
|
+
|
|
992
|
+
self.assertEqual(Pet.many(owner__name="pat").name, ["rex", "spot"])
|
|
993
|
+
self.assertEqual(Owner.many(pet__name="fido").name, ["sam"])
|
|
994
|
+
|
|
995
|
+
self.assertEqual(Pet.many(like="re").name, ["rex"])
|
|
996
|
+
|
|
870
997
|
def test_retrieve_ties_query(self):
|
|
871
998
|
|
|
872
999
|
self.source.execute(Sis.define())
|
|
@@ -917,6 +1044,52 @@ LIMIT ?""")
|
|
|
917
1044
|
self.assertEqual(Bro.many(sis_id__all=[jane.id, joan.id]).name, ["Bob"])
|
|
918
1045
|
self.assertEqual(Bro.many(sis_id__any=[joan.id]).name, ["Bob"])
|
|
919
1046
|
|
|
1047
|
+
def test_retrieve_ties_attr(self):
|
|
1048
|
+
|
|
1049
|
+
self.source.execute(Sis.define())
|
|
1050
|
+
self.source.execute(Bro.define())
|
|
1051
|
+
self.source.execute(SisBro.define())
|
|
1052
|
+
|
|
1053
|
+
# M2M attribute filtering: a flat join through the tie table filters on the sibling's
|
|
1054
|
+
# own field. Existence semantics, with the sibling's normal field operators.
|
|
1055
|
+
|
|
1056
|
+
tom = Bro("Tom").create()
|
|
1057
|
+
dick = Bro("Dick").create()
|
|
1058
|
+
harry = Bro("Harry").create()
|
|
1059
|
+
|
|
1060
|
+
Sis("Mary", bro_id=[tom.id, dick.id]).create() # tied to Tom, Dick
|
|
1061
|
+
Sis("Sue", bro_id=[tom.id]).create() # tied to Tom
|
|
1062
|
+
Sis("Ann", bro_id=[dick.id, harry.id]).create() # tied to Dick, Harry
|
|
1063
|
+
|
|
1064
|
+
# tied to a brother with that name
|
|
1065
|
+
self.assertEqual(sorted(Sis.many(bro__name="Tom").name), ["Mary", "Sue"])
|
|
1066
|
+
self.assertEqual(Sis.many(bro__name="Harry").name, ["Ann"])
|
|
1067
|
+
self.assertEqual(len(Sis.many(bro__name="Ghost")), 0)
|
|
1068
|
+
|
|
1069
|
+
# field operators land on the sibling: like
|
|
1070
|
+
self.assertEqual(Sis.many(bro__name__like="arr").name, ["Ann"])
|
|
1071
|
+
|
|
1072
|
+
# DISTINCT: Mary is tied to BOTH Tom and Dick, so an "in" join would match her twice;
|
|
1073
|
+
# she must appear once (retrieve) and count once
|
|
1074
|
+
self.assertEqual(sorted(Sis.many(bro__name__in=["Tom", "Dick"]).name), ["Ann", "Mary", "Sue"])
|
|
1075
|
+
self.assertEqual(Sis.many(bro__name__in=["Tom", "Dick"]).count(), 3)
|
|
1076
|
+
|
|
1077
|
+
# negation is field-level: a tied non-Tom exists (Mary stays via Dick)
|
|
1078
|
+
self.assertEqual(sorted(Sis.many(bro__name__not_in=["Tom"]).name), ["Ann", "Mary"])
|
|
1079
|
+
|
|
1080
|
+
# criteria on the same relation filter the SAME tied brother
|
|
1081
|
+
self.assertEqual(Sis.many(bro__name="Dick", bro__id=harry.id).name, [])
|
|
1082
|
+
self.assertEqual(sorted(Sis.many(bro__name="Dick", bro__id=dick.id).name), ["Ann", "Mary"])
|
|
1083
|
+
|
|
1084
|
+
# symmetric: brothers filtered by a tied sister's name
|
|
1085
|
+
jane = Sis("Jane").create()
|
|
1086
|
+
joan = Sis("Joan").create()
|
|
1087
|
+
Bro("Bab", sis_id=[jane.id, joan.id]).create() # tied to Jane, Joan
|
|
1088
|
+
Bro("Bil", sis_id=[jane.id]).create() # tied to Jane
|
|
1089
|
+
|
|
1090
|
+
self.assertEqual(sorted(Bro.many(sis__name="Jane").name), ["Bab", "Bil"])
|
|
1091
|
+
self.assertEqual(Bro.many(sis__name__in=["Joan"]).name, ["Bab"])
|
|
1092
|
+
|
|
920
1093
|
def test_titles(self):
|
|
921
1094
|
|
|
922
1095
|
self.source.execute(Unit.define())
|
|
@@ -1102,6 +1275,34 @@ LIMIT ?""")
|
|
|
1102
1275
|
self.assertEqual(Bro.one(name="Dick").sis.id, [dot.id])
|
|
1103
1276
|
self.assertEqual(Sis.one(name="Nikki").bro.id, [tom.id])
|
|
1104
1277
|
|
|
1278
|
+
# an injected key updates like a column, but not in mass
|
|
1279
|
+
|
|
1280
|
+
self.source.execute(Owner.define())
|
|
1281
|
+
self.source.execute(Pet.define())
|
|
1282
|
+
|
|
1283
|
+
pat = Owner("pat").create()
|
|
1284
|
+
sam = Owner("sam").create()
|
|
1285
|
+
|
|
1286
|
+
Pet([{"name": "rex", "owner_id": pat.id}, {"name": "fido", "owner_id": sam.id}]).create()
|
|
1287
|
+
|
|
1288
|
+
pet = Pet.one(name="rex").retrieve()
|
|
1289
|
+
pet.owner_id = sam.id
|
|
1290
|
+
|
|
1291
|
+
self.assertEqual(pet.update(), 1)
|
|
1292
|
+
self.assertEqual(Pet.one(name="rex").owner_id, sam.id)
|
|
1293
|
+
self.assertEqual(Pet.many(owner_id=sam.id).name, ["fido", "rex"])
|
|
1294
|
+
|
|
1295
|
+
pet.owner_id = None
|
|
1296
|
+
|
|
1297
|
+
self.assertEqual(pet.update(), 1)
|
|
1298
|
+
self.assertIsNone(Pet.one(name="rex").owner_id)
|
|
1299
|
+
self.assertEqual(Pet.many(owner_id__null=True).name, ["rex"])
|
|
1300
|
+
|
|
1301
|
+
self.assertEqual(Pet.one(name="rex").set(owner_id=pat.id).update(), 1)
|
|
1302
|
+
self.assertEqual(Pet.one(name="rex").owner_id, pat.id)
|
|
1303
|
+
|
|
1304
|
+
self.assertRaisesRegex(relations.FieldError, "no mass update with inject", Pet.many(name="rex").set(owner_id=sam.id).update)
|
|
1305
|
+
|
|
1105
1306
|
def test_delete_query(self):
|
|
1106
1307
|
|
|
1107
1308
|
self.source.execute(Unit.define())
|
|
@@ -1182,6 +1383,18 @@ LIMIT ?""")
|
|
|
1182
1383
|
self.assertEqual(Sis.one(name="Dot").bro.id, [tom.id])
|
|
1183
1384
|
self.assertEqual(SisBro.many().count(), 1)
|
|
1184
1385
|
|
|
1386
|
+
# an injected key deletes like any other
|
|
1387
|
+
|
|
1388
|
+
self.source.execute(Owner.define())
|
|
1389
|
+
self.source.execute(Pet.define())
|
|
1390
|
+
|
|
1391
|
+
pat = Owner("pat").create()
|
|
1392
|
+
|
|
1393
|
+
Pet([{"name": "rex", "owner_id": pat.id}, {"name": "spot", "owner_id": pat.id}, {"name": "stray"}]).create()
|
|
1394
|
+
|
|
1395
|
+
self.assertEqual(Pet.many(owner_id=pat.id).delete(), 2)
|
|
1396
|
+
self.assertEqual(Pet.many().name, ["stray"])
|
|
1397
|
+
|
|
1185
1398
|
def test_definition(self):
|
|
1186
1399
|
|
|
1187
1400
|
with open("ddl/general.json", 'w') as ddl_file:
|
|
File without changes
|
|
File without changes
|
{relations_sqlite3-0.6.8 → relations_sqlite3-0.6.10}/lib/relations_sqlite3.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{relations_sqlite3-0.6.8 → relations_sqlite3-0.6.10}/lib/relations_sqlite3.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|