From 8e40b1fd7e6e501bd5e73e39d4dbfd4739cf339a Mon Sep 17 00:00:00 2001
From: Gregoo <versatile.mailbox@gmail.com>
Date: Mon, 3 Feb 2025 22:20:43 +0100
Subject: [PATCH] Simplify BrickRecord based lists to deduplicate code

---
 bricktracker/minifigure_list.py |  74 +++++++++----------
 bricktracker/part_list.py       | 114 ++++++++++++-----------------
 bricktracker/set_list.py        | 122 ++++++++++----------------------
 3 files changed, 117 insertions(+), 193 deletions(-)

diff --git a/bricktracker/minifigure_list.py b/bricktracker/minifigure_list.py
index 24a4d2e1..fa735629 100644
--- a/bricktracker/minifigure_list.py
+++ b/bricktracker/minifigure_list.py
@@ -38,13 +38,7 @@ class BrickMinifigureList(BrickRecordList[BrickMinifigure]):
 
     # Load all minifigures
     def all(self, /) -> Self:
-        for record in self.select(
-            override_query=self.all_query,
-            order=self.order
-        ):
-            minifigure = BrickMinifigure(record=record)
-
-            self.records.append(minifigure)
+        self.list(override_query=self.all_query)
 
         return self
 
@@ -55,13 +49,7 @@ class BrickMinifigureList(BrickRecordList[BrickMinifigure]):
         self.fields.color = color
 
         # Load the minifigures from the database
-        for record in self.select(
-            override_query=self.damaged_part_query,
-            order=self.order
-        ):
-            minifigure = BrickMinifigure(record=record)
-
-            self.records.append(minifigure)
+        self.list(override_query=self.damaged_part_query)
 
         return self
 
@@ -73,27 +61,45 @@ class BrickMinifigureList(BrickRecordList[BrickMinifigure]):
         else:
             order = '"bricktracker_minifigures"."rowid" DESC'
 
-        for record in self.select(
-            override_query=self.last_query,
-            order=order,
-            limit=limit
-        ):
-            minifigure = BrickMinifigure(record=record)
-
-            self.records.append(minifigure)
+        self.list(override_query=self.last_query, order=order, limit=limit)
 
         return self
 
+    # Base minifigure list
+    def list(
+        self,
+        /,
+        *,
+        override_query: str | None = None,
+        order: str | None = None,
+        limit: int | None = None,
+        **context: Any,
+    ) -> None:
+        if order is None:
+            order = self.order
+
+        if hasattr(self, 'brickset'):
+            brickset = self.brickset
+        else:
+            brickset = None
+
+        # Load the sets from the database
+        for record in super().select(
+            override_query=override_query,
+            order=order,
+            limit=limit,
+        ):
+            minifigure = BrickMinifigure(brickset=brickset, record=record)
+
+            self.records.append(minifigure)
+
     # Load minifigures from a brickset
     def from_set(self, brickset: 'BrickSet', /) -> Self:
         # Save the brickset
         self.brickset = brickset
 
         # Load the minifigures from the database
-        for record in self.select(order=self.order):
-            minifigure = BrickMinifigure(brickset=self.brickset, record=record)
-
-            self.records.append(minifigure)
+        self.list()
 
         return self
 
@@ -104,13 +110,7 @@ class BrickMinifigureList(BrickRecordList[BrickMinifigure]):
         self.fields.color = color
 
         # Load the minifigures from the database
-        for record in self.select(
-            override_query=self.missing_part_query,
-            order=self.order
-        ):
-            minifigure = BrickMinifigure(record=record)
-
-            self.records.append(minifigure)
+        self.list(override_query=self.missing_part_query)
 
         return self
 
@@ -121,13 +121,7 @@ class BrickMinifigureList(BrickRecordList[BrickMinifigure]):
         self.fields.color = color
 
         # Load the minifigures from the database
-        for record in self.select(
-            override_query=self.using_part_query,
-            order=self.order
-        ):
-            minifigure = BrickMinifigure(record=record)
-
-            self.records.append(minifigure)
+        self.list(override_query=self.using_part_query)
 
         return self
 
diff --git a/bricktracker/part_list.py b/bricktracker/part_list.py
index eb3f58d5..a12ef89e 100644
--- a/bricktracker/part_list.py
+++ b/bricktracker/part_list.py
@@ -42,16 +42,50 @@ class BrickPartList(BrickRecordList[BrickPart]):
 
     # Load all parts
     def all(self, /) -> Self:
-        for record in self.select(
-            override_query=self.all_query,
-            order=self.order
-        ):
-            part = BrickPart(record=record)
-
-            self.records.append(part)
+        self.list(override_query=self.all_query)
 
         return self
 
+    # Base part list
+    def list(
+        self,
+        /,
+        *,
+        override_query: str | None = None,
+        order: str | None = None,
+        limit: int | None = None,
+        **context: Any,
+    ) -> None:
+        if order is None:
+            order = self.order
+
+        if hasattr(self, 'brickset'):
+            brickset = self.brickset
+        else:
+            brickset = None
+
+        if hasattr(self, 'minifigure'):
+            minifigure = self.minifigure
+        else:
+            minifigure = None
+
+        # Load the sets from the database
+        for record in super().select(
+            override_query=override_query,
+            order=order,
+            limit=limit,
+        ):
+            part = BrickPart(
+                brickset=brickset,
+                minifigure=minifigure,
+                record=record,
+            )
+
+            if current_app.config['SKIP_SPARE_PARTS'] and part.fields.spare:
+                continue
+
+            self.records.append(part)
+
     # List specific parts from a brickset or minifigure
     def list_specific(
         self,
@@ -65,17 +99,7 @@ class BrickPartList(BrickRecordList[BrickPart]):
         self.minifigure = minifigure
 
         # Load the parts from the database
-        for record in self.select(order=self.order):
-            part = BrickPart(
-                brickset=self.brickset,
-                minifigure=minifigure,
-                record=record,
-            )
-
-            if current_app.config['SKIP_SPARE_PARTS'] and part.fields.spare:
-                continue
-
-            self.records.append(part)
+        self.list()
 
         return self
 
@@ -89,19 +113,7 @@ class BrickPartList(BrickRecordList[BrickPart]):
         self.minifigure = minifigure
 
         # Load the parts from the database
-        for record in self.select(
-            override_query=self.minifigure_query,
-            order=self.order
-        ):
-            part = BrickPart(
-                minifigure=minifigure,
-                record=record,
-            )
-
-            if current_app.config['SKIP_SPARE_PARTS'] and part.fields.spare:
-                continue
-
-            self.records.append(part)
+        self.list(override_query=self.minifigure_query)
 
         return self
 
@@ -121,33 +133,13 @@ class BrickPartList(BrickRecordList[BrickPart]):
         self.fields.color = brickpart.fields.color
 
         # Load the parts from the database
-        for record in self.select(
-            override_query=self.print_query,
-            order=self.order
-        ):
-            part = BrickPart(
-                record=record,
-            )
-
-            if (
-                current_app.config['SKIP_SPARE_PARTS'] and
-                part.fields.spare
-            ):
-                continue
-
-            self.records.append(part)
+        self.list(override_query=self.print_query)
 
         return self
 
     # Load problematic parts
     def problem(self, /) -> Self:
-        for record in self.select(
-            override_query=self.problem_query,
-            order=self.order
-        ):
-            part = BrickPart(record=record)
-
-            self.records.append(part)
+        self.list(override_query=self.problem_query)
 
         return self
 
@@ -178,21 +170,7 @@ class BrickPartList(BrickRecordList[BrickPart]):
         self.fields.color = brickpart.fields.color
 
         # Load the parts from the database
-        for record in self.select(
-            override_query=self.different_color_query,
-            order=self.order
-        ):
-            part = BrickPart(
-                record=record,
-            )
-
-            if (
-                current_app.config['SKIP_SPARE_PARTS'] and
-                part.fields.spare
-            ):
-                continue
-
-            self.records.append(part)
+        self.list(override_query=self.different_color_query)
 
         return self
 
diff --git a/bricktracker/set_list.py b/bricktracker/set_list.py
index ffc436d2..b12f9717 100644
--- a/bricktracker/set_list.py
+++ b/bricktracker/set_list.py
@@ -1,4 +1,4 @@
-from typing import Self
+from typing import Any, Self
 
 from flask import current_app
 
@@ -36,23 +36,8 @@ class BrickSetList(BrickRecordList[BrickSet]):
 
     # All the sets
     def all(self, /) -> Self:
-        themes = set()
-
         # Load the sets from the database
-        for record in self.select(
-            order=self.order,
-            owners=BrickSetOwnerList.as_columns(),
-            statuses=BrickSetStatusList.as_columns(),
-            tags=BrickSetTagList.as_columns(),
-        ):
-            brickset = BrickSet(record=record)
-
-            self.records.append(brickset)
-            themes.add(brickset.theme.name)
-
-        # Convert the set into a list and sort it
-        self.themes = list(themes)
-        self.themes.sort()
+        self.list(do_theme=True)
 
         return self
 
@@ -62,13 +47,7 @@ class BrickSetList(BrickRecordList[BrickSet]):
         self.fields.figure = figure
 
         # Load the sets from the database
-        for record in self.select(
-            override_query=self.damaged_minifigure_query,
-            order=self.order
-        ):
-            brickset = BrickSet(record=record)
-
-            self.records.append(brickset)
+        self.list(override_query=self.damaged_minifigure_query)
 
         return self
 
@@ -79,25 +58,7 @@ class BrickSetList(BrickRecordList[BrickSet]):
         self.fields.color = color
 
         # Load the sets from the database
-        for record in self.select(
-            override_query=self.damaged_part_query,
-            order=self.order
-        ):
-            brickset = BrickSet(record=record)
-
-            self.records.append(brickset)
-
-        return self
-
-    # A generic list of the different sets
-    def generic(self, /) -> Self:
-        for record in self.select(
-            override_query=self.generic_query,
-            order=self.order
-        ):
-            brickset = BrickSet(record=record)
-
-            self.records.append(brickset)
+        self.list(override_query=self.damaged_part_query)
 
         return self
 
@@ -109,7 +70,29 @@ class BrickSetList(BrickRecordList[BrickSet]):
         else:
             order = '"bricktracker_sets"."rowid" DESC'
 
-        for record in self.select(
+        self.list(order=order, limit=limit)
+
+        return self
+
+    # Base set list
+    def list(
+        self,
+        /,
+        *,
+        override_query: str | None = None,
+        order: str | None = None,
+        limit: int | None = None,
+        do_theme: bool = False,
+        **context: Any,
+    ) -> None:
+        themes = set()
+
+        if order is None:
+            order = self.order
+
+        # Load the sets from the database
+        for record in super().select(
+            override_query=override_query,
             order=order,
             limit=limit,
             owners=BrickSetOwnerList.as_columns(),
@@ -119,8 +102,13 @@ class BrickSetList(BrickRecordList[BrickSet]):
             brickset = BrickSet(record=record)
 
             self.records.append(brickset)
+            if do_theme:
+                themes.add(brickset.theme.name)
 
-        return self
+        # Convert the set into a list and sort it
+        if do_theme:
+            self.themes = list(themes)
+            self.themes.sort()
 
     # Sets missing a minifigure part
     def missing_minifigure(self, figure: str, /) -> Self:
@@ -128,16 +116,7 @@ class BrickSetList(BrickRecordList[BrickSet]):
         self.fields.figure = figure
 
         # Load the sets from the database
-        for record in self.select(
-            override_query=self.missing_minifigure_query,
-            order=self.order,
-            owners=BrickSetOwnerList.as_columns(),
-            statuses=BrickSetStatusList.as_columns(),
-            tags=BrickSetTagList.as_columns(),
-        ):
-            brickset = BrickSet(record=record)
-
-            self.records.append(brickset)
+        self.list(override_query=self.missing_minifigure_query)
 
         return self
 
@@ -148,16 +127,7 @@ class BrickSetList(BrickRecordList[BrickSet]):
         self.fields.color = color
 
         # Load the sets from the database
-        for record in self.select(
-            override_query=self.missing_part_query,
-            order=self.order,
-            owners=BrickSetOwnerList.as_columns(),
-            statuses=BrickSetStatusList.as_columns(),
-            tags=BrickSetTagList.as_columns(),
-        ):
-            brickset = BrickSet(record=record)
-
-            self.records.append(brickset)
+        self.list(override_query=self.missing_part_query)
 
         return self
 
@@ -167,16 +137,7 @@ class BrickSetList(BrickRecordList[BrickSet]):
         self.fields.figure = figure
 
         # Load the sets from the database
-        for record in self.select(
-            override_query=self.using_minifigure_query,
-            order=self.order,
-            owners=BrickSetOwnerList.as_columns(),
-            statuses=BrickSetStatusList.as_columns(),
-            tags=BrickSetTagList.as_columns(),
-        ):
-            brickset = BrickSet(record=record)
-
-            self.records.append(brickset)
+        self.list(override_query=self.using_minifigure_query)
 
         return self
 
@@ -187,15 +148,6 @@ class BrickSetList(BrickRecordList[BrickSet]):
         self.fields.color = color
 
         # Load the sets from the database
-        for record in self.select(
-            override_query=self.using_part_query,
-            order=self.order,
-            owners=BrickSetOwnerList.as_columns(),
-            statuses=BrickSetStatusList.as_columns(),
-            tags=BrickSetTagList.as_columns(),
-        ):
-            brickset = BrickSet(record=record)
-
-            self.records.append(brickset)
+        self.list(override_query=self.using_part_query)
 
         return self