feat(parts): add SQL queries for individual parts and lot management

This commit is contained in:
2026-01-18 20:25:47 +01:00
parent 58ff39fbc3
commit c947d29d67
43 changed files with 785 additions and 0 deletions
@@ -0,0 +1,17 @@
-- A bit unsafe as it does not use a prepared statement but it
-- should not be possible to inject anything through the {{ id }} context
BEGIN TRANSACTION;
-- Delete metadata from consolidated tables
DELETE FROM "bricktracker_set_owners"
WHERE "id" IS NOT DISTINCT FROM '{{ id }}';
DELETE FROM "bricktracker_set_tags"
WHERE "id" IS NOT DISTINCT FROM '{{ id }}';
-- Delete the individual part itself
DELETE FROM "bricktracker_individual_parts"
WHERE "id" IS NOT DISTINCT FROM '{{ id }}';
COMMIT;
@@ -0,0 +1,30 @@
-- Insert a new individual part
INSERT INTO "bricktracker_individual_parts" (
"id",
"part",
"color",
"quantity",
"missing",
"damaged",
"checked",
"description",
"lot_id",
"storage",
"purchase_location",
"purchase_date",
"purchase_price"
) VALUES (
:id,
:part,
:color,
:quantity,
:missing,
:damaged,
:checked,
:description,
:lot_id,
:storage,
:purchase_location,
:purchase_date,
:purchase_price
)
@@ -0,0 +1,30 @@
-- Insert an individual part that belongs to a lot
INSERT INTO "bricktracker_individual_parts" (
"id",
"part",
"color",
"quantity",
"missing",
"damaged",
"checked",
"description",
"storage",
"purchase_location",
"purchase_date",
"purchase_price",
"lot_id"
) VALUES (
:id,
:part,
:color,
:quantity,
0,
0,
0,
NULL,
NULL,
NULL,
NULL,
NULL,
:lot_id
)
@@ -0,0 +1,42 @@
-- List all individual parts
SELECT
"bricktracker_individual_parts"."id",
"bricktracker_individual_parts"."part",
"bricktracker_individual_parts"."color",
"bricktracker_individual_parts"."quantity",
"bricktracker_individual_parts"."missing",
"bricktracker_individual_parts"."damaged",
"bricktracker_individual_parts"."checked",
"bricktracker_individual_parts"."description",
"bricktracker_individual_parts"."lot_id",
"bricktracker_individual_parts"."storage",
"bricktracker_individual_parts"."purchase_location",
"bricktracker_individual_parts"."purchase_date",
"bricktracker_individual_parts"."purchase_price",
"rebrickable_parts"."name" AS "part_name",
"rebrickable_parts"."color_name",
"rebrickable_parts"."color_rgb",
"rebrickable_parts"."color_transparent",
"rebrickable_parts"."category",
"rebrickable_parts"."image",
"rebrickable_parts"."image_id",
"rebrickable_parts"."url" AS "part_url",
"rebrickable_parts"."bricklink_part_num",
"rebrickable_parts"."bricklink_color_id",
"rebrickable_parts"."bricklink_color_name"
FROM "bricktracker_individual_parts"
INNER JOIN "rebrickable_parts"
ON "bricktracker_individual_parts"."part" = "rebrickable_parts"."part"
AND "bricktracker_individual_parts"."color" = "rebrickable_parts"."color_id"
{% if order %}
ORDER BY {{ order }}
{% endif %}
{% if limit %}
LIMIT {{ limit }}
{% endif %}
{% if offset %}
OFFSET {{ offset }}
{% endif %}
@@ -0,0 +1,31 @@
SELECT
"bricktracker_individual_parts"."id",
"bricktracker_individual_parts"."part",
"bricktracker_individual_parts"."color",
"bricktracker_individual_parts"."quantity",
"bricktracker_individual_parts"."missing",
"bricktracker_individual_parts"."damaged",
"bricktracker_individual_parts"."checked",
"bricktracker_individual_parts"."description",
"bricktracker_individual_parts"."storage",
"bricktracker_individual_parts"."purchase_location",
"bricktracker_individual_parts"."purchase_date",
"bricktracker_individual_parts"."purchase_price",
"rebrickable_parts"."name",
"rebrickable_parts"."color_name",
"rebrickable_parts"."color_rgb",
"rebrickable_parts"."color_transparent",
"rebrickable_parts"."image",
"rebrickable_parts"."url",
"bricktracker_metadata_storages"."name" AS "storage_name",
"bricktracker_metadata_purchase_locations"."name" AS "purchase_location_name"
FROM "bricktracker_individual_parts"
INNER JOIN "rebrickable_parts"
ON "bricktracker_individual_parts"."part" = "rebrickable_parts"."part"
AND "bricktracker_individual_parts"."color" = "rebrickable_parts"."color_id"
LEFT JOIN "bricktracker_metadata_storages"
ON "bricktracker_individual_parts"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
LEFT JOIN "bricktracker_metadata_purchase_locations"
ON "bricktracker_individual_parts"."purchase_location" IS NOT DISTINCT FROM "bricktracker_metadata_purchase_locations"."id"
WHERE "bricktracker_individual_parts"."color" = :color
ORDER BY "bricktracker_individual_parts"."part"
@@ -0,0 +1,31 @@
SELECT
"bricktracker_individual_parts"."id",
"bricktracker_individual_parts"."part",
"bricktracker_individual_parts"."color",
"bricktracker_individual_parts"."quantity",
"bricktracker_individual_parts"."missing",
"bricktracker_individual_parts"."damaged",
"bricktracker_individual_parts"."checked",
"bricktracker_individual_parts"."description",
"bricktracker_individual_parts"."storage",
"bricktracker_individual_parts"."purchase_location",
"bricktracker_individual_parts"."purchase_date",
"bricktracker_individual_parts"."purchase_price",
"rebrickable_parts"."name",
"rebrickable_parts"."color_name",
"rebrickable_parts"."color_rgb",
"rebrickable_parts"."color_transparent",
"rebrickable_parts"."image",
"rebrickable_parts"."url",
"bricktracker_metadata_storages"."name" AS "storage_name",
"bricktracker_metadata_purchase_locations"."name" AS "purchase_location_name"
FROM "bricktracker_individual_parts"
INNER JOIN "rebrickable_parts"
ON "bricktracker_individual_parts"."part" = "rebrickable_parts"."part"
AND "bricktracker_individual_parts"."color" = "rebrickable_parts"."color_id"
LEFT JOIN "bricktracker_metadata_storages"
ON "bricktracker_individual_parts"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
LEFT JOIN "bricktracker_metadata_purchase_locations"
ON "bricktracker_individual_parts"."purchase_location" IS NOT DISTINCT FROM "bricktracker_metadata_purchase_locations"."id"
WHERE "bricktracker_individual_parts"."part" = :part
ORDER BY "bricktracker_individual_parts"."color"
@@ -0,0 +1,34 @@
SELECT
"bricktracker_individual_parts"."id",
"bricktracker_individual_parts"."part",
"bricktracker_individual_parts"."color",
"bricktracker_individual_parts"."quantity",
"bricktracker_individual_parts"."missing",
"bricktracker_individual_parts"."damaged",
"bricktracker_individual_parts"."checked",
"bricktracker_individual_parts"."description",
"bricktracker_individual_parts"."lot_id",
"bricktracker_individual_parts"."storage",
"bricktracker_individual_parts"."purchase_location",
"bricktracker_individual_parts"."purchase_date",
"bricktracker_individual_parts"."purchase_price",
"rebrickable_parts"."name",
"rebrickable_parts"."color_name",
"rebrickable_parts"."color_rgb",
"rebrickable_parts"."color_transparent",
"rebrickable_parts"."image",
"rebrickable_parts"."url",
"bricktracker_metadata_storages"."name" AS "storage_name",
"bricktracker_metadata_purchase_locations"."name" AS "purchase_location_name"
FROM "bricktracker_individual_parts"
INNER JOIN "rebrickable_parts"
ON "bricktracker_individual_parts"."part" = "rebrickable_parts"."part"
AND "bricktracker_individual_parts"."color" = "rebrickable_parts"."color_id"
LEFT JOIN "bricktracker_metadata_storages"
ON "bricktracker_individual_parts"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
LEFT JOIN "bricktracker_metadata_purchase_locations"
ON "bricktracker_individual_parts"."purchase_location" IS NOT DISTINCT FROM "bricktracker_metadata_purchase_locations"."id"
WHERE "bricktracker_individual_parts"."part" = :part
AND "bricktracker_individual_parts"."color" = :color
AND "bricktracker_individual_parts"."lot_id" IS NULL
ORDER BY "bricktracker_individual_parts"."id"
@@ -0,0 +1,31 @@
SELECT
"bricktracker_individual_parts"."id",
"bricktracker_individual_parts"."part",
"bricktracker_individual_parts"."color",
"bricktracker_individual_parts"."quantity",
"bricktracker_individual_parts"."missing",
"bricktracker_individual_parts"."damaged",
"bricktracker_individual_parts"."checked",
"bricktracker_individual_parts"."description",
"bricktracker_individual_parts"."storage",
"bricktracker_individual_parts"."purchase_location",
"bricktracker_individual_parts"."purchase_date",
"bricktracker_individual_parts"."purchase_price",
"rebrickable_parts"."name",
"rebrickable_parts"."color_name",
"rebrickable_parts"."color_rgb",
"rebrickable_parts"."color_transparent",
"rebrickable_parts"."image",
"rebrickable_parts"."url",
"bricktracker_metadata_storages"."name" AS "storage_name",
"bricktracker_metadata_purchase_locations"."name" AS "purchase_location_name"
FROM "bricktracker_individual_parts"
INNER JOIN "rebrickable_parts"
ON "bricktracker_individual_parts"."part" = "rebrickable_parts"."part"
AND "bricktracker_individual_parts"."color" = "rebrickable_parts"."color_id"
LEFT JOIN "bricktracker_metadata_storages"
ON "bricktracker_individual_parts"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
LEFT JOIN "bricktracker_metadata_purchase_locations"
ON "bricktracker_individual_parts"."purchase_location" IS NOT DISTINCT FROM "bricktracker_metadata_purchase_locations"."id"
WHERE "bricktracker_individual_parts"."storage" = :storage
ORDER BY "bricktracker_individual_parts"."part", "bricktracker_individual_parts"."color"
@@ -0,0 +1,32 @@
SELECT
"bricktracker_individual_parts"."id",
"bricktracker_individual_parts"."part",
"bricktracker_individual_parts"."color",
"bricktracker_individual_parts"."quantity",
"bricktracker_individual_parts"."missing",
"bricktracker_individual_parts"."damaged",
"bricktracker_individual_parts"."checked",
"bricktracker_individual_parts"."description",
"bricktracker_individual_parts"."storage",
"bricktracker_individual_parts"."purchase_location",
"bricktracker_individual_parts"."purchase_date",
"bricktracker_individual_parts"."purchase_price",
"rebrickable_parts"."name",
"rebrickable_parts"."color_name",
"rebrickable_parts"."color_rgb",
"rebrickable_parts"."color_transparent",
"rebrickable_parts"."image",
"rebrickable_parts"."url",
"bricktracker_metadata_storages"."name" AS "storage_name",
"bricktracker_metadata_purchase_locations"."name" AS "purchase_location_name"
FROM "bricktracker_individual_parts"
INNER JOIN "rebrickable_parts"
ON "bricktracker_individual_parts"."part" = "rebrickable_parts"."part"
AND "bricktracker_individual_parts"."color" = "rebrickable_parts"."color_id"
LEFT JOIN "bricktracker_metadata_storages"
ON "bricktracker_individual_parts"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
LEFT JOIN "bricktracker_metadata_purchase_locations"
ON "bricktracker_individual_parts"."purchase_location" IS NOT DISTINCT FROM "bricktracker_metadata_purchase_locations"."id"
WHERE "bricktracker_individual_parts"."missing" > 0
OR "bricktracker_individual_parts"."damaged" > 0
ORDER BY "bricktracker_individual_parts"."part", "bricktracker_individual_parts"."color"
@@ -0,0 +1,32 @@
SELECT
"bricktracker_individual_parts"."id",
"bricktracker_individual_parts"."part",
"bricktracker_individual_parts"."color",
"bricktracker_individual_parts"."quantity",
"bricktracker_individual_parts"."missing",
"bricktracker_individual_parts"."damaged",
"bricktracker_individual_parts"."checked",
"bricktracker_individual_parts"."description",
"bricktracker_individual_parts"."storage",
"bricktracker_individual_parts"."purchase_location",
"bricktracker_individual_parts"."purchase_date",
"bricktracker_individual_parts"."purchase_price",
"rebrickable_parts"."name",
"rebrickable_parts"."color_name",
"rebrickable_parts"."color_rgb",
"rebrickable_parts"."color_transparent",
"rebrickable_parts"."image",
"rebrickable_parts"."url",
"bricktracker_metadata_storages"."name" AS "storage_name",
"bricktracker_metadata_purchase_locations"."name" AS "purchase_location_name"
FROM "bricktracker_individual_parts"
INNER JOIN "rebrickable_parts"
ON "bricktracker_individual_parts"."part" = "rebrickable_parts"."part"
AND "bricktracker_individual_parts"."color" = "rebrickable_parts"."color_id"
LEFT JOIN "bricktracker_metadata_storages"
ON "bricktracker_individual_parts"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
LEFT JOIN "bricktracker_metadata_purchase_locations"
ON "bricktracker_individual_parts"."purchase_location" IS NOT DISTINCT FROM "bricktracker_metadata_purchase_locations"."id"
WHERE "bricktracker_individual_parts"."purchase_location" IS NOT DISTINCT FROM :purchase_location
AND "bricktracker_individual_parts"."lot_id" IS NULL
ORDER BY "bricktracker_individual_parts"."part", "bricktracker_individual_parts"."color"
@@ -0,0 +1,31 @@
SELECT
"bricktracker_individual_parts"."id",
"bricktracker_individual_parts"."part",
"bricktracker_individual_parts"."color",
"bricktracker_individual_parts"."quantity",
"bricktracker_individual_parts"."missing",
"bricktracker_individual_parts"."damaged",
"bricktracker_individual_parts"."checked",
"bricktracker_individual_parts"."description",
"bricktracker_individual_parts"."storage",
"bricktracker_individual_parts"."purchase_location",
"bricktracker_individual_parts"."purchase_date",
"bricktracker_individual_parts"."purchase_price",
"rebrickable_parts"."name",
"rebrickable_parts"."color_name",
"rebrickable_parts"."color_rgb",
"rebrickable_parts"."color_transparent",
"rebrickable_parts"."image",
"rebrickable_parts"."url",
"bricktracker_metadata_storages"."name" AS "storage_name",
"bricktracker_metadata_purchase_locations"."name" AS "purchase_location_name"
FROM "bricktracker_individual_parts"
INNER JOIN "rebrickable_parts"
ON "bricktracker_individual_parts"."part" = "rebrickable_parts"."part"
AND "bricktracker_individual_parts"."color" = "rebrickable_parts"."color_id"
LEFT JOIN "bricktracker_metadata_storages"
ON "bricktracker_individual_parts"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
LEFT JOIN "bricktracker_metadata_purchase_locations"
ON "bricktracker_individual_parts"."purchase_location" IS NOT DISTINCT FROM "bricktracker_metadata_purchase_locations"."id"
WHERE "bricktracker_individual_parts"."storage" IS NOT DISTINCT FROM :storage
ORDER BY "bricktracker_individual_parts"."part", "bricktracker_individual_parts"."color"
@@ -0,0 +1,31 @@
SELECT
"bricktracker_individual_parts"."id",
"bricktracker_individual_parts"."part",
"bricktracker_individual_parts"."color",
"bricktracker_individual_parts"."quantity",
"bricktracker_individual_parts"."missing",
"bricktracker_individual_parts"."damaged",
"bricktracker_individual_parts"."checked",
"bricktracker_individual_parts"."description",
"bricktracker_individual_parts"."storage",
"bricktracker_individual_parts"."purchase_location",
"bricktracker_individual_parts"."purchase_date",
"bricktracker_individual_parts"."purchase_price",
"rebrickable_parts"."name",
"rebrickable_parts"."color_name",
"rebrickable_parts"."color_rgb",
"rebrickable_parts"."color_transparent",
"rebrickable_parts"."image",
"rebrickable_parts"."url",
"bricktracker_metadata_storages"."name" AS "storage_name",
"bricktracker_metadata_purchase_locations"."name" AS "purchase_location_name"
FROM "bricktracker_individual_parts"
INNER JOIN "rebrickable_parts"
ON "bricktracker_individual_parts"."part" = "rebrickable_parts"."part"
AND "bricktracker_individual_parts"."color" = "rebrickable_parts"."color_id"
LEFT JOIN "bricktracker_metadata_storages"
ON "bricktracker_individual_parts"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
LEFT JOIN "bricktracker_metadata_purchase_locations"
ON "bricktracker_individual_parts"."purchase_location" IS NOT DISTINCT FROM "bricktracker_metadata_purchase_locations"."id"
WHERE "bricktracker_individual_parts"."storage" IS NULL
ORDER BY "bricktracker_individual_parts"."part", "bricktracker_individual_parts"."color"
@@ -0,0 +1,44 @@
-- Select a specific individual part by UUID
SELECT
"bricktracker_individual_parts"."id",
"bricktracker_individual_parts"."part",
"bricktracker_individual_parts"."color",
"bricktracker_individual_parts"."quantity",
"bricktracker_individual_parts"."missing",
"bricktracker_individual_parts"."damaged",
"bricktracker_individual_parts"."checked",
"bricktracker_individual_parts"."description",
"bricktracker_individual_parts"."lot_id",
"bricktracker_individual_parts"."storage",
"bricktracker_individual_parts"."purchase_location",
"bricktracker_individual_parts"."purchase_date",
"bricktracker_individual_parts"."purchase_price",
"rebrickable_parts"."name" AS "part_name",
"rebrickable_parts"."color_name",
"rebrickable_parts"."color_rgb",
"rebrickable_parts"."color_transparent",
"rebrickable_parts"."category",
"rebrickable_parts"."image",
"rebrickable_parts"."image_id",
"rebrickable_parts"."url",
"rebrickable_parts"."bricklink_part_num",
"rebrickable_parts"."bricklink_color_id",
"rebrickable_parts"."bricklink_color_name"
{% if owners %},{{ owners }}{% endif %}
{% if statuses %},{{ statuses }}{% endif %}
{% if tags %},{{ tags }}{% endif %}
FROM "bricktracker_individual_parts"
INNER JOIN "rebrickable_parts"
ON "bricktracker_individual_parts"."part" = "rebrickable_parts"."part"
AND "bricktracker_individual_parts"."color" = "rebrickable_parts"."color_id"
LEFT JOIN "bricktracker_set_owners"
ON "bricktracker_individual_parts"."id" IS NOT DISTINCT FROM "bricktracker_set_owners"."id"
LEFT JOIN "bricktracker_set_statuses"
ON "bricktracker_individual_parts"."id" IS NOT DISTINCT FROM "bricktracker_set_statuses"."id"
LEFT JOIN "bricktracker_set_tags"
ON "bricktracker_individual_parts"."id" IS NOT DISTINCT FROM "bricktracker_set_tags"."id"
WHERE "bricktracker_individual_parts"."id" = :id;
@@ -0,0 +1,3 @@
UPDATE "bricktracker_individual_parts"
SET "checked" = :checked
WHERE "id" = :id
@@ -0,0 +1,3 @@
UPDATE "bricktracker_individual_parts"
SET "damaged" = :damaged
WHERE "id" = :id
@@ -0,0 +1,4 @@
-- Update description for an individual part
UPDATE "bricktracker_individual_parts"
SET "description" = :description
WHERE "id" = :id;
@@ -0,0 +1,4 @@
-- Update a specific field in bricktracker_individual_parts
UPDATE "bricktracker_individual_parts"
SET "{{ field }}" = :value
WHERE "id" = :id
@@ -0,0 +1,3 @@
UPDATE "bricktracker_individual_parts"
SET "missing" = :missing
WHERE "id" = :id
@@ -0,0 +1,4 @@
-- Update quantity for an individual part
UPDATE "bricktracker_individual_parts"
SET "quantity" = :quantity
WHERE "id" = :id;
@@ -0,0 +1,9 @@
UPDATE "bricktracker_individual_parts"
SET
"quantity" = :quantity,
"description" = :description,
"storage" = :storage,
"purchase_location" = :purchase_location,
"purchase_date" = :purchase_date,
"purchase_price" = :purchase_price
WHERE "id" = :id
@@ -0,0 +1,22 @@
-- A bit unsafe as it does not use a prepared statement but it
-- should not be possible to inject anything through the {{ id }} context
BEGIN TRANSACTION;
-- Delete all individual parts associated with this lot
DELETE FROM "bricktracker_individual_parts"
WHERE "lot_id" IS NOT DISTINCT FROM '{{ id }}';
-- Delete lot owners (using consolidated metadata table)
DELETE FROM "bricktracker_set_owners"
WHERE "id" IS NOT DISTINCT FROM '{{ id }}';
-- Delete lot tags (using consolidated metadata table)
DELETE FROM "bricktracker_set_tags"
WHERE "id" IS NOT DISTINCT FROM '{{ id }}';
-- Delete the lot itself
DELETE FROM "bricktracker_individual_part_lots"
WHERE "id" IS NOT DISTINCT FROM '{{ id }}';
COMMIT;
@@ -0,0 +1,19 @@
INSERT INTO "bricktracker_individual_part_lots" (
"id",
"name",
"description",
"created_date",
"storage",
"purchase_location",
"purchase_date",
"purchase_price"
) VALUES (
:id,
:name,
:description,
:created_date,
:storage,
:purchase_location,
:purchase_date,
:purchase_price
)
@@ -0,0 +1,21 @@
SELECT
"bricktracker_individual_part_lots"."id",
"bricktracker_individual_part_lots"."name",
"bricktracker_individual_part_lots"."description",
"bricktracker_individual_part_lots"."created_date",
"bricktracker_individual_part_lots"."storage",
"bricktracker_individual_part_lots"."purchase_location",
"bricktracker_individual_part_lots"."purchase_date",
"bricktracker_individual_part_lots"."purchase_price",
"bricktracker_metadata_storages"."name" AS "storage_name",
"bricktracker_metadata_purchase_locations"."name" AS "purchase_location_name",
COUNT("bricktracker_individual_parts"."id") AS "part_count"
FROM "bricktracker_individual_part_lots"
LEFT JOIN "bricktracker_metadata_storages"
ON "bricktracker_individual_part_lots"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
LEFT JOIN "bricktracker_metadata_purchase_locations"
ON "bricktracker_individual_part_lots"."purchase_location" IS NOT DISTINCT FROM "bricktracker_metadata_purchase_locations"."id"
LEFT JOIN "bricktracker_individual_parts"
ON "bricktracker_individual_part_lots"."id" = "bricktracker_individual_parts"."lot_id"
GROUP BY "bricktracker_individual_part_lots"."id"
ORDER BY "bricktracker_individual_part_lots"."created_date" DESC
@@ -0,0 +1,23 @@
SELECT DISTINCT
"bricktracker_individual_part_lots"."id",
"bricktracker_individual_part_lots"."name",
"bricktracker_individual_part_lots"."description",
"bricktracker_individual_part_lots"."created_date",
"bricktracker_individual_part_lots"."storage",
"bricktracker_individual_part_lots"."purchase_location",
"bricktracker_individual_part_lots"."purchase_date",
"bricktracker_individual_part_lots"."purchase_price",
"bricktracker_metadata_storages"."name" AS "storage_name",
"bricktracker_metadata_purchase_locations"."name" AS "purchase_location_name",
COUNT("bricktracker_individual_parts"."id") AS "part_count"
FROM "bricktracker_individual_part_lots"
INNER JOIN "bricktracker_individual_parts"
ON "bricktracker_individual_part_lots"."id" = "bricktracker_individual_parts"."lot_id"
LEFT JOIN "bricktracker_metadata_storages"
ON "bricktracker_individual_part_lots"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
LEFT JOIN "bricktracker_metadata_purchase_locations"
ON "bricktracker_individual_part_lots"."purchase_location" IS NOT DISTINCT FROM "bricktracker_metadata_purchase_locations"."id"
WHERE "bricktracker_individual_parts"."part" = :part
AND "bricktracker_individual_parts"."color" = :color
GROUP BY "bricktracker_individual_part_lots"."id"
ORDER BY "bricktracker_individual_part_lots"."created_date" DESC
@@ -0,0 +1,22 @@
SELECT
"bricktracker_individual_part_lots"."id",
"bricktracker_individual_part_lots"."name",
"bricktracker_individual_part_lots"."description",
"bricktracker_individual_part_lots"."created_date",
"bricktracker_individual_part_lots"."storage",
"bricktracker_individual_part_lots"."purchase_location",
"bricktracker_individual_part_lots"."purchase_date",
"bricktracker_individual_part_lots"."purchase_price",
"bricktracker_metadata_storages"."name" AS "storage_name",
"bricktracker_metadata_purchase_locations"."name" AS "purchase_location_name",
COUNT("bricktracker_individual_parts"."id") AS "part_count"
FROM "bricktracker_individual_part_lots"
LEFT JOIN "bricktracker_metadata_storages"
ON "bricktracker_individual_part_lots"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
LEFT JOIN "bricktracker_metadata_purchase_locations"
ON "bricktracker_individual_part_lots"."purchase_location" IS NOT DISTINCT FROM "bricktracker_metadata_purchase_locations"."id"
LEFT JOIN "bricktracker_individual_parts"
ON "bricktracker_individual_part_lots"."id" = "bricktracker_individual_parts"."lot_id"
WHERE "bricktracker_individual_part_lots"."storage" = :storage
GROUP BY "bricktracker_individual_part_lots"."id"
ORDER BY "bricktracker_individual_part_lots"."created_date" DESC
@@ -0,0 +1,26 @@
SELECT
"bricktracker_individual_parts"."id",
"bricktracker_individual_parts"."part",
"bricktracker_individual_parts"."color",
"bricktracker_individual_parts"."quantity",
"bricktracker_individual_parts"."missing",
"bricktracker_individual_parts"."damaged",
"bricktracker_individual_parts"."checked",
"bricktracker_individual_parts"."description",
"bricktracker_individual_parts"."storage",
"bricktracker_individual_parts"."purchase_location",
"bricktracker_individual_parts"."purchase_date",
"bricktracker_individual_parts"."purchase_price",
"bricktracker_individual_parts"."lot_id",
"rebrickable_parts"."name",
"rebrickable_parts"."color_name",
"rebrickable_parts"."color_rgb",
"rebrickable_parts"."color_transparent",
"rebrickable_parts"."image",
"rebrickable_parts"."url"
FROM "bricktracker_individual_parts"
INNER JOIN "rebrickable_parts"
ON "bricktracker_individual_parts"."part" = "rebrickable_parts"."part"
AND "bricktracker_individual_parts"."color" = "rebrickable_parts"."color_id"
WHERE "bricktracker_individual_parts"."lot_id" = :lot_id
ORDER BY "rebrickable_parts"."name" ASC, "bricktracker_individual_parts"."color" ASC
@@ -0,0 +1,23 @@
SELECT
"bricktracker_individual_part_lots"."id",
"bricktracker_individual_part_lots"."name",
"bricktracker_individual_part_lots"."description",
"bricktracker_individual_part_lots"."created_date",
"bricktracker_individual_part_lots"."storage",
"bricktracker_individual_part_lots"."purchase_location",
"bricktracker_individual_part_lots"."purchase_date",
"bricktracker_individual_part_lots"."purchase_price",
"bricktracker_metadata_storages"."name" AS "storage_name",
"bricktracker_metadata_purchase_locations"."name" AS "purchase_location_name",
COUNT("bricktracker_individual_parts"."id") AS "part_count"
FROM "bricktracker_individual_part_lots"
LEFT JOIN "bricktracker_metadata_storages"
ON "bricktracker_individual_part_lots"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
LEFT JOIN "bricktracker_metadata_purchase_locations"
ON "bricktracker_individual_part_lots"."purchase_location" IS NOT DISTINCT FROM "bricktracker_metadata_purchase_locations"."id"
INNER JOIN "bricktracker_individual_parts"
ON "bricktracker_individual_part_lots"."id" = "bricktracker_individual_parts"."lot_id"
WHERE "bricktracker_individual_parts"."missing" > 0
OR "bricktracker_individual_parts"."damaged" > 0
GROUP BY "bricktracker_individual_part_lots"."id"
ORDER BY "bricktracker_individual_part_lots"."created_date" DESC
@@ -0,0 +1,22 @@
SELECT
"bricktracker_individual_part_lots"."id",
"bricktracker_individual_part_lots"."name",
"bricktracker_individual_part_lots"."description",
"bricktracker_individual_part_lots"."created_date",
"bricktracker_individual_part_lots"."storage",
"bricktracker_individual_part_lots"."purchase_location",
"bricktracker_individual_part_lots"."purchase_date",
"bricktracker_individual_part_lots"."purchase_price",
"bricktracker_metadata_storages"."name" AS "storage_name",
"bricktracker_metadata_purchase_locations"."name" AS "purchase_location_name",
COUNT("bricktracker_individual_parts"."id") AS "part_count"
FROM "bricktracker_individual_part_lots"
LEFT JOIN "bricktracker_metadata_storages"
ON "bricktracker_individual_part_lots"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
LEFT JOIN "bricktracker_metadata_purchase_locations"
ON "bricktracker_individual_part_lots"."purchase_location" IS NOT DISTINCT FROM "bricktracker_metadata_purchase_locations"."id"
LEFT JOIN "bricktracker_individual_parts"
ON "bricktracker_individual_part_lots"."id" = "bricktracker_individual_parts"."lot_id"
WHERE "bricktracker_individual_part_lots"."purchase_location" IS NOT DISTINCT FROM :purchase_location
GROUP BY "bricktracker_individual_part_lots"."id"
ORDER BY "bricktracker_individual_part_lots"."created_date" DESC
@@ -0,0 +1,22 @@
SELECT
"bricktracker_individual_part_lots"."id",
"bricktracker_individual_part_lots"."name",
"bricktracker_individual_part_lots"."description",
"bricktracker_individual_part_lots"."created_date",
"bricktracker_individual_part_lots"."storage",
"bricktracker_individual_part_lots"."purchase_location",
"bricktracker_individual_part_lots"."purchase_date",
"bricktracker_individual_part_lots"."purchase_price",
"bricktracker_metadata_storages"."name" AS "storage_name",
"bricktracker_metadata_purchase_locations"."name" AS "purchase_location_name",
COUNT("bricktracker_individual_parts"."id") AS "part_count"
FROM "bricktracker_individual_part_lots"
LEFT JOIN "bricktracker_metadata_storages"
ON "bricktracker_individual_part_lots"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
LEFT JOIN "bricktracker_metadata_purchase_locations"
ON "bricktracker_individual_part_lots"."purchase_location" IS NOT DISTINCT FROM "bricktracker_metadata_purchase_locations"."id"
LEFT JOIN "bricktracker_individual_parts"
ON "bricktracker_individual_part_lots"."id" = "bricktracker_individual_parts"."lot_id"
WHERE "bricktracker_individual_part_lots"."storage" IS NOT DISTINCT FROM :storage
GROUP BY "bricktracker_individual_part_lots"."id"
ORDER BY "bricktracker_individual_part_lots"."created_date" DESC
@@ -0,0 +1,22 @@
SELECT
"bricktracker_individual_part_lots"."id",
"bricktracker_individual_part_lots"."name",
"bricktracker_individual_part_lots"."description",
"bricktracker_individual_part_lots"."created_date",
"bricktracker_individual_part_lots"."storage",
"bricktracker_individual_part_lots"."purchase_location",
"bricktracker_individual_part_lots"."purchase_date",
"bricktracker_individual_part_lots"."purchase_price",
"bricktracker_metadata_storages"."name" AS "storage_name",
"bricktracker_metadata_purchase_locations"."name" AS "purchase_location_name",
COUNT("bricktracker_individual_parts"."id") AS "part_count"
FROM "bricktracker_individual_part_lots"
LEFT JOIN "bricktracker_metadata_storages"
ON "bricktracker_individual_part_lots"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
LEFT JOIN "bricktracker_metadata_purchase_locations"
ON "bricktracker_individual_part_lots"."purchase_location" IS NOT DISTINCT FROM "bricktracker_metadata_purchase_locations"."id"
LEFT JOIN "bricktracker_individual_parts"
ON "bricktracker_individual_part_lots"."id" = "bricktracker_individual_parts"."lot_id"
WHERE "bricktracker_individual_part_lots"."storage" IS NULL
GROUP BY "bricktracker_individual_part_lots"."id"
ORDER BY "bricktracker_individual_part_lots"."created_date" DESC
@@ -0,0 +1,28 @@
SELECT
"bricktracker_individual_part_lots"."id",
"bricktracker_individual_part_lots"."name",
"bricktracker_individual_part_lots"."description",
"bricktracker_individual_part_lots"."created_date",
"bricktracker_individual_part_lots"."storage",
"bricktracker_individual_part_lots"."purchase_location",
"bricktracker_individual_part_lots"."purchase_date",
"bricktracker_individual_part_lots"."purchase_price",
"bricktracker_metadata_storages"."name" AS "storage_name",
"bricktracker_metadata_purchase_locations"."name" AS "purchase_location_name"
{% if owners %},{{ owners }}{% endif %}
{% if tags %},{{ tags }}{% endif %}
FROM "bricktracker_individual_part_lots"
LEFT JOIN "bricktracker_metadata_storages"
ON "bricktracker_individual_part_lots"."storage" IS NOT DISTINCT FROM "bricktracker_metadata_storages"."id"
LEFT JOIN "bricktracker_metadata_purchase_locations"
ON "bricktracker_individual_part_lots"."purchase_location" IS NOT DISTINCT FROM "bricktracker_metadata_purchase_locations"."id"
LEFT JOIN "bricktracker_set_owners"
ON "bricktracker_individual_part_lots"."id" IS NOT DISTINCT FROM "bricktracker_set_owners"."id"
-- Note: Part lots don't have statuses, only owners and tags
LEFT JOIN "bricktracker_set_tags"
ON "bricktracker_individual_part_lots"."id" IS NOT DISTINCT FROM "bricktracker_set_tags"."id"
WHERE "bricktracker_individual_part_lots"."id" = :id
@@ -0,0 +1,4 @@
-- Update individual part lot description
UPDATE "bricktracker_individual_part_lots"
SET "description" = :description
WHERE "id" = :id
@@ -0,0 +1,4 @@
-- Update individual part lot name
UPDATE "bricktracker_individual_part_lots"
SET "name" = :name
WHERE "id" = :id
@@ -0,0 +1,4 @@
-- Update individual part lot purchase date
UPDATE "bricktracker_individual_part_lots"
SET "purchase_date" = :purchase_date
WHERE "id" = :id
@@ -0,0 +1,4 @@
-- Update individual part lot purchase location
UPDATE "bricktracker_individual_part_lots"
SET "purchase_location" = :purchase_location
WHERE "id" = :id
@@ -0,0 +1,4 @@
-- Update individual part lot purchase price
UPDATE "bricktracker_individual_part_lots"
SET "purchase_price" = :purchase_price
WHERE "id" = :id
@@ -0,0 +1,4 @@
-- Update individual part lot storage
UPDATE "bricktracker_individual_part_lots"
SET "storage" = :storage
WHERE "id" = :id
@@ -0,0 +1,8 @@
-- Insert or replace color information
INSERT OR REPLACE INTO "rebrickable_colors" (
"color_id", "name", "rgb", "is_trans",
"bricklink_color_id", "bricklink_color_name"
) VALUES (
:color_id, :name, :rgb, :is_trans,
:bricklink_color_id, :bricklink_color_name
)
@@ -0,0 +1,5 @@
-- Select color information by color_id
SELECT "color_id", "name", "rgb", "is_trans",
"bricklink_color_id", "bricklink_color_name"
FROM "rebrickable_colors"
WHERE "color_id" = :color_id
@@ -0,0 +1,3 @@
-- Check if a part/color combination exists in rebrickable_parts
SELECT COUNT(*) FROM "rebrickable_parts"
WHERE "part" = :part AND "color_id" = :color_id
@@ -0,0 +1,26 @@
-- Insert a part/color combination into rebrickable_parts
INSERT OR IGNORE INTO "rebrickable_parts" (
"part",
"name",
"color_id",
"color_name",
"color_rgb",
"color_transparent",
"image",
"image_id",
"url",
"bricklink_color_id",
"bricklink_color_name"
) VALUES (
:part,
:name,
:color_id,
:color_name,
:color_rgb,
:color_transparent,
:image,
:image_id,
:url,
:bricklink_color_id,
:bricklink_color_name
)
@@ -0,0 +1,20 @@
-- Insert or update part into rebrickable_parts using pre-loaded color data
INSERT INTO "rebrickable_parts" (
"part", "color_id", "color_name", "color_rgb", "color_transparent",
"bricklink_color_id", "bricklink_color_name",
"name", "image", "image_id", "url"
) VALUES (
:part, :color_id, :color_name, :color_rgb, :color_transparent,
:bricklink_color_id, :bricklink_color_name,
:name, :image, :image_id, :url
)
ON CONFLICT("part", "color_id") DO UPDATE SET
"color_name" = COALESCE(excluded."color_name", "rebrickable_parts"."color_name"),
"color_rgb" = COALESCE(excluded."color_rgb", "rebrickable_parts"."color_rgb"),
"color_transparent" = COALESCE(excluded."color_transparent", "rebrickable_parts"."color_transparent"),
"bricklink_color_id" = COALESCE(excluded."bricklink_color_id", "rebrickable_parts"."bricklink_color_id"),
"bricklink_color_name" = COALESCE(excluded."bricklink_color_name", "rebrickable_parts"."bricklink_color_name"),
"name" = COALESCE(excluded."name", "rebrickable_parts"."name"),
"image" = COALESCE(excluded."image", "rebrickable_parts"."image"),
"image_id" = COALESCE(excluded."image_id", "rebrickable_parts"."image_id"),
"url" = COALESCE(excluded."url", "rebrickable_parts"."url")
@@ -0,0 +1,3 @@
-- Get image URL for a part/color combination
SELECT "image" FROM "rebrickable_parts"
WHERE "part" = :part AND "color_id" = :color_id