relations-sqlite3 0.6.8__tar.gz → 0.6.9__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: relations-sqlite3
3
- Version: 0.6.8
3
+ Version: 0.6.9
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: relations-sqlite3
3
- Version: 0.6.8
3
+ Version: 0.6.9
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
@@ -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
 
@@ -278,6 +280,11 @@ class Source(relations_sql.SOURCE, relations.Source): # pylint: disable=too-many
278
280
  self.retrieve_record(model._record, query)
279
281
  self.like(model, query)
280
282
 
283
+ # a sibling-attribute flat join repeats a model tied to several matching siblings, so
284
+ # count the distinct model id instead of the joined rows
285
+ if getattr(model, "_distinct", False):
286
+ query.FIELDS = self.FIELDS(self.AS("total", self.SQL(f"COUNT(DISTINCT {model.STORE}.{model._id})")))
287
+
281
288
  return query
282
289
 
283
290
  def retrieve_query(self, model):
@@ -287,7 +294,12 @@ class Source(relations_sql.SOURCE, relations.Source): # pylint: disable=too-many
287
294
 
288
295
  query = self.count_query(model)
289
296
 
290
- query.FIELDS = self.FIELDS("*")
297
+ # honor the flat-join DISTINCT marker: dedupe the model rows the join multiplied
298
+ if getattr(model, "_distinct", False):
299
+ query.OPTIONS = self.OPTIONS("DISTINCT")
300
+ query.FIELDS = self.FIELDS(self.COLUMN_NAME("*", table=model.STORE))
301
+ else:
302
+ query.FIELDS = self.FIELDS("*")
291
303
 
292
304
  self.sort(model, query)
293
305
  self.limit(model, query)
@@ -7,7 +7,7 @@ with open("README.md", "r") as readme_file:
7
7
 
8
8
  setup(
9
9
  name="relations-sqlite3",
10
- version="0.6.8",
10
+ version="0.6.9",
11
11
  package_dir = {'': 'lib'},
12
12
  py_modules = [
13
13
  'relations_sqlite3'
@@ -917,6 +917,52 @@ LIMIT ?""")
917
917
  self.assertEqual(Bro.many(sis_id__all=[jane.id, joan.id]).name, ["Bob"])
918
918
  self.assertEqual(Bro.many(sis_id__any=[joan.id]).name, ["Bob"])
919
919
 
920
+ def test_retrieve_ties_attr(self):
921
+
922
+ self.source.execute(Sis.define())
923
+ self.source.execute(Bro.define())
924
+ self.source.execute(SisBro.define())
925
+
926
+ # M2M attribute filtering: a flat join through the tie table filters on the sibling's
927
+ # own field. Existence semantics, with the sibling's normal field operators.
928
+
929
+ tom = Bro("Tom").create()
930
+ dick = Bro("Dick").create()
931
+ harry = Bro("Harry").create()
932
+
933
+ Sis("Mary", bro_id=[tom.id, dick.id]).create() # tied to Tom, Dick
934
+ Sis("Sue", bro_id=[tom.id]).create() # tied to Tom
935
+ Sis("Ann", bro_id=[dick.id, harry.id]).create() # tied to Dick, Harry
936
+
937
+ # tied to a brother with that name
938
+ self.assertEqual(sorted(Sis.many(bro__name="Tom").name), ["Mary", "Sue"])
939
+ self.assertEqual(Sis.many(bro__name="Harry").name, ["Ann"])
940
+ self.assertEqual(len(Sis.many(bro__name="Ghost")), 0)
941
+
942
+ # field operators land on the sibling: like
943
+ self.assertEqual(Sis.many(bro__name__like="arr").name, ["Ann"])
944
+
945
+ # DISTINCT: Mary is tied to BOTH Tom and Dick, so an "in" join would match her twice;
946
+ # she must appear once (retrieve) and count once
947
+ self.assertEqual(sorted(Sis.many(bro__name__in=["Tom", "Dick"]).name), ["Ann", "Mary", "Sue"])
948
+ self.assertEqual(Sis.many(bro__name__in=["Tom", "Dick"]).count(), 3)
949
+
950
+ # negation is field-level: a tied non-Tom exists (Mary stays via Dick)
951
+ self.assertEqual(sorted(Sis.many(bro__name__not_in=["Tom"]).name), ["Ann", "Mary"])
952
+
953
+ # criteria on the same relation filter the SAME tied brother
954
+ self.assertEqual(Sis.many(bro__name="Dick", bro__id=harry.id).name, [])
955
+ self.assertEqual(sorted(Sis.many(bro__name="Dick", bro__id=dick.id).name), ["Ann", "Mary"])
956
+
957
+ # symmetric: brothers filtered by a tied sister's name
958
+ jane = Sis("Jane").create()
959
+ joan = Sis("Joan").create()
960
+ Bro("Bab", sis_id=[jane.id, joan.id]).create() # tied to Jane, Joan
961
+ Bro("Bil", sis_id=[jane.id]).create() # tied to Jane
962
+
963
+ self.assertEqual(sorted(Bro.many(sis__name="Jane").name), ["Bab", "Bil"])
964
+ self.assertEqual(Bro.many(sis__name__in=["Joan"]).name, ["Bab"])
965
+
920
966
  def test_titles(self):
921
967
 
922
968
  self.source.execute(Unit.define())