388 lines
11 KiB
Elixir
388 lines
11 KiB
Elixir
# Script for populating the database with sample data. You can run it as:
|
|
#
|
|
# mix run priv/repo/seeds.exs
|
|
#
|
|
# This seeds file creates:
|
|
# - Sample categories (with hierarchical subcategories)
|
|
# - Storage locations (with auto-assigned AprilTag IDs)
|
|
# - Sample electronic components with proper storage assignments
|
|
# - Generates all AprilTag SVG files for immediate use
|
|
#
|
|
# Inside the script, you can read and write to any of your
|
|
# repositories directly:
|
|
#
|
|
# ComponentsElixir.Repo.insert!(%ComponentsElixir.SomeSchema{})
|
|
#
|
|
# We recommend using the bang functions (`insert!`, `update!`
|
|
# and so on) as they will fail if something goes wrong.
|
|
|
|
alias ComponentsElixir.{Repo, Inventory, AprilTag}
|
|
alias ComponentsElixir.Inventory.{Category, Component, StorageLocation}
|
|
|
|
# Clear existing data
|
|
Repo.delete_all(Component)
|
|
Repo.delete_all(Category)
|
|
Repo.delete_all(StorageLocation)
|
|
|
|
# Create categories
|
|
{:ok, resistors} =
|
|
Inventory.create_category(%{name: "Resistors", description: "Various types of resistors"})
|
|
|
|
{:ok, capacitors} =
|
|
Inventory.create_category(%{
|
|
name: "Capacitors",
|
|
description: "Electrolytic, ceramic, and film capacitors"
|
|
})
|
|
|
|
{:ok, semiconductors} =
|
|
Inventory.create_category(%{name: "Semiconductors", description: "ICs, transistors, diodes"})
|
|
|
|
{:ok, connectors} =
|
|
Inventory.create_category(%{name: "Connectors", description: "Headers, terminals, plugs"})
|
|
|
|
# Create subcategories
|
|
{:ok, _through_hole_resistors} =
|
|
Inventory.create_category(%{
|
|
name: "Through-hole",
|
|
description: "Traditional leaded resistors",
|
|
parent_id: resistors.id
|
|
})
|
|
|
|
{:ok, _smd_resistors} =
|
|
Inventory.create_category(%{
|
|
name: "SMD/SMT",
|
|
description: "Surface mount resistors",
|
|
parent_id: resistors.id
|
|
})
|
|
|
|
{:ok, _ceramic_caps} =
|
|
Inventory.create_category(%{
|
|
name: "Ceramic",
|
|
description: "Ceramic disc and multilayer capacitors",
|
|
parent_id: capacitors.id
|
|
})
|
|
|
|
{:ok, _electrolytic_caps} =
|
|
Inventory.create_category(%{
|
|
name: "Electrolytic",
|
|
description: "Polarized electrolytic capacitors",
|
|
parent_id: capacitors.id
|
|
})
|
|
|
|
# Create a DEEP category hierarchy to test fallback path (7+ levels)
|
|
{:ok, deep_cat_1} =
|
|
Inventory.create_category(%{
|
|
name: "Level 1",
|
|
description: "Deep hierarchy test",
|
|
parent_id: resistors.id
|
|
})
|
|
|
|
{:ok, deep_cat_2} =
|
|
Inventory.create_category(%{
|
|
name: "Level 2",
|
|
description: "Deep hierarchy test",
|
|
parent_id: deep_cat_1.id
|
|
})
|
|
|
|
{:ok, deep_cat_3} =
|
|
Inventory.create_category(%{
|
|
name: "Level 3",
|
|
description: "Deep hierarchy test",
|
|
parent_id: deep_cat_2.id
|
|
})
|
|
|
|
{:ok, deep_cat_4} =
|
|
Inventory.create_category(%{
|
|
name: "Level 4",
|
|
description: "Deep hierarchy test",
|
|
parent_id: deep_cat_3.id
|
|
})
|
|
|
|
{:ok, deep_cat_5} =
|
|
Inventory.create_category(%{
|
|
name: "Level 5",
|
|
description: "Deep hierarchy test",
|
|
parent_id: deep_cat_4.id
|
|
})
|
|
|
|
{:ok, deep_cat_6} =
|
|
Inventory.create_category(%{
|
|
name: "Level 6",
|
|
description: "Deep hierarchy test",
|
|
parent_id: deep_cat_5.id
|
|
})
|
|
|
|
{:ok, deep_cat_7} =
|
|
Inventory.create_category(%{
|
|
name: "Level 7",
|
|
description: "Deep hierarchy test - triggers fallback",
|
|
parent_id: deep_cat_6.id
|
|
})
|
|
|
|
# Create storage locations
|
|
{:ok, shelf_a} =
|
|
Inventory.create_storage_location(%{name: "Shelf A", description: "Main electronics shelf"})
|
|
|
|
{:ok, _shelf_b} =
|
|
Inventory.create_storage_location(%{name: "Shelf B", description: "Components overflow shelf"})
|
|
|
|
# Create drawers on Shelf A
|
|
{:ok, drawer_a1} =
|
|
Inventory.create_storage_location(%{
|
|
name: "Drawer 1",
|
|
description: "Resistors and capacitors",
|
|
parent_id: shelf_a.id
|
|
})
|
|
|
|
{:ok, drawer_a2} =
|
|
Inventory.create_storage_location(%{
|
|
name: "Drawer 2",
|
|
description: "Semiconductors and ICs",
|
|
parent_id: shelf_a.id
|
|
})
|
|
|
|
# Create boxes in Drawer A1
|
|
{:ok, box_a1_1} =
|
|
Inventory.create_storage_location(%{
|
|
name: "Box 1",
|
|
description: "Through-hole resistors",
|
|
parent_id: drawer_a1.id
|
|
})
|
|
|
|
{:ok, _box_a1_2} =
|
|
Inventory.create_storage_location(%{
|
|
name: "Box 2",
|
|
description: "SMD resistors",
|
|
parent_id: drawer_a1.id
|
|
})
|
|
|
|
{:ok, box_a1_3} =
|
|
Inventory.create_storage_location(%{
|
|
name: "Box 3",
|
|
description: "Ceramic capacitors",
|
|
parent_id: drawer_a1.id
|
|
})
|
|
|
|
# Create boxes in Drawer A2
|
|
{:ok, box_a2_1} =
|
|
Inventory.create_storage_location(%{
|
|
name: "Box 1",
|
|
description: "Microcontrollers",
|
|
parent_id: drawer_a2.id
|
|
})
|
|
|
|
{:ok, _box_a2_2} =
|
|
Inventory.create_storage_location(%{
|
|
name: "Box 2",
|
|
description: "Transistors and diodes",
|
|
parent_id: drawer_a2.id
|
|
})
|
|
|
|
# Create a DEEP storage location hierarchy to test fallback path (7+ levels)
|
|
{:ok, deep_loc_1} =
|
|
Inventory.create_storage_location(%{
|
|
name: "Deep Level 1",
|
|
description: "Deep hierarchy test",
|
|
parent_id: box_a1_3.id
|
|
})
|
|
|
|
{:ok, deep_loc_2} =
|
|
Inventory.create_storage_location(%{
|
|
name: "Deep Level 2",
|
|
description: "Deep hierarchy test",
|
|
parent_id: deep_loc_1.id
|
|
})
|
|
|
|
{:ok, deep_loc_3} =
|
|
Inventory.create_storage_location(%{
|
|
name: "Deep Level 3",
|
|
description: "Deep hierarchy test",
|
|
parent_id: deep_loc_2.id
|
|
})
|
|
|
|
{:ok, deep_loc_4} =
|
|
Inventory.create_storage_location(%{
|
|
name: "Deep Level 4",
|
|
description: "Deep hierarchy test",
|
|
parent_id: deep_loc_3.id
|
|
})
|
|
|
|
{:ok, deep_loc_5} =
|
|
Inventory.create_storage_location(%{
|
|
name: "Deep Level 5",
|
|
description: "Deep hierarchy test",
|
|
parent_id: deep_loc_4.id
|
|
})
|
|
|
|
{:ok, deep_loc_6} =
|
|
Inventory.create_storage_location(%{
|
|
name: "Deep Level 6",
|
|
description: "Deep hierarchy test",
|
|
parent_id: deep_loc_5.id
|
|
})
|
|
|
|
{:ok, deep_loc_7} =
|
|
Inventory.create_storage_location(%{
|
|
name: "Deep Level 7",
|
|
description: "Deep hierarchy test - triggers fallback",
|
|
parent_id: deep_loc_6.id
|
|
})
|
|
|
|
# Create sample components
|
|
sample_components = [
|
|
%{
|
|
name: "1kΩ Resistor (1/4W)",
|
|
description: "Carbon film resistor, 5% tolerance",
|
|
keywords: "resistor carbon film 1k ohm",
|
|
storage_location_id: box_a1_1.id,
|
|
count: 150,
|
|
category_id: resistors.id
|
|
},
|
|
%{
|
|
name: "10kΩ Resistor (1/4W)",
|
|
description: "Carbon film resistor, 5% tolerance",
|
|
keywords: "resistor carbon film 10k ohm",
|
|
storage_location_id: box_a1_1.id,
|
|
count: 200,
|
|
category_id: resistors.id
|
|
},
|
|
%{
|
|
name: "100μF Electrolytic Capacitor",
|
|
description: "25V electrolytic capacitor, radial leads",
|
|
keywords: "capacitor electrolytic 100uf microfarad",
|
|
storage_location_id: box_a1_3.id,
|
|
count: 50,
|
|
category_id: capacitors.id
|
|
},
|
|
%{
|
|
name: "0.1μF Ceramic Capacitor",
|
|
description: "50V ceramic disc capacitor",
|
|
keywords: "capacitor ceramic 100nf nanofarad disc",
|
|
storage_location_id: box_a1_3.id,
|
|
count: 300,
|
|
category_id: capacitors.id
|
|
},
|
|
%{
|
|
name: "ATmega328P-PU",
|
|
description: "8-bit AVR microcontroller, DIP-28 package",
|
|
keywords: "microcontroller avr atmega328 arduino",
|
|
storage_location_id: box_a2_1.id,
|
|
count: 10,
|
|
datasheet_url:
|
|
"https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf",
|
|
category_id: semiconductors.id
|
|
},
|
|
%{
|
|
name: "LM358 Op-Amp",
|
|
description: "Dual operational amplifier, DIP-8 package",
|
|
keywords: "opamp operational amplifier lm358 dual",
|
|
storage_location_id: box_a2_1.id,
|
|
count: 25,
|
|
category_id: semiconductors.id
|
|
},
|
|
%{
|
|
name: "2N2222 NPN Transistor",
|
|
description: "General purpose NPN transistor, TO-92 package",
|
|
keywords: "transistor npn 2n2222 to92",
|
|
storage_location_id: box_a2_1.id,
|
|
count: 40,
|
|
category_id: semiconductors.id
|
|
},
|
|
%{
|
|
name: "2.54mm Pin Headers",
|
|
description: "Male pin headers, 40 pins, break-away",
|
|
keywords: "header pins male 2.54mm breakaway",
|
|
storage_location_id: drawer_a2.id,
|
|
count: 20,
|
|
category_id: connectors.id
|
|
},
|
|
%{
|
|
name: "JST-XH 2-pin Connector",
|
|
description: "2-pin JST-XH connector with housing",
|
|
keywords: "jst xh connector 2pin housing",
|
|
storage_location_id: drawer_a2.id,
|
|
count: 30,
|
|
category_id: connectors.id
|
|
},
|
|
%{
|
|
name: "470Ω Resistor (1/4W)",
|
|
description: "Carbon film resistor, 5% tolerance, commonly used for LEDs",
|
|
keywords: "resistor carbon film 470 ohm led current limiting",
|
|
storage_location_id: box_a1_1.id,
|
|
count: 100,
|
|
category_id: resistors.id
|
|
},
|
|
# Test components for deep hierarchies to ensure fallback path is exercised
|
|
%{
|
|
name: "Deep Category Test Component",
|
|
description: "Component in 7-level deep category hierarchy",
|
|
keywords: "test deep hierarchy category fallback",
|
|
storage_location_id: box_a1_1.id,
|
|
count: 1,
|
|
category_id: deep_cat_7.id
|
|
},
|
|
%{
|
|
name: "Deep Storage Test Component",
|
|
description: "Component in 7-level deep storage location hierarchy",
|
|
keywords: "test deep hierarchy storage fallback",
|
|
storage_location_id: deep_loc_7.id,
|
|
count: 1,
|
|
category_id: resistors.id
|
|
}
|
|
]
|
|
|
|
Enum.each(sample_components, fn component_attrs ->
|
|
{:ok, _component} = Inventory.create_component(component_attrs)
|
|
end)
|
|
|
|
IO.puts("Seeded database with categories, storage locations, and sample components!")
|
|
IO.puts("Categories: #{length(Inventory.list_categories())}")
|
|
IO.puts("Storage Locations: #{length(Inventory.list_storage_locations())}")
|
|
IO.puts("Components: #{length(Inventory.list_components())}")
|
|
IO.puts("")
|
|
IO.puts("Sample AprilTag information:")
|
|
|
|
# Print AprilTag information for sample storage locations
|
|
sample_locations = [
|
|
Inventory.get_storage_location!(shelf_a.id),
|
|
Inventory.get_storage_location!(drawer_a1.id),
|
|
Inventory.get_storage_location!(box_a1_1.id),
|
|
Inventory.get_storage_location!(box_a2_1.id)
|
|
]
|
|
|
|
Enum.each(sample_locations, fn location ->
|
|
if location.apriltag_id do
|
|
apriltag_url = AprilTag.get_apriltag_url(location)
|
|
location_path = StorageLocation.full_path(location)
|
|
IO.puts("#{location_path}: AprilTag ID #{location.apriltag_id}")
|
|
IO.puts(" Download URL: #{apriltag_url}")
|
|
else
|
|
location_path = StorageLocation.full_path(location)
|
|
IO.puts("#{location_path}: No AprilTag assigned")
|
|
end
|
|
end)
|
|
|
|
# Generate all AprilTag SVGs for immediate use
|
|
IO.puts("Generating AprilTag SVG files...")
|
|
result = AprilTag.generate_all_apriltag_svgs()
|
|
IO.puts("Generated #{result.success}/#{result.total} AprilTag SVG files")
|
|
|
|
IO.puts("")
|
|
IO.puts("🎉 Database seeded successfully!")
|
|
IO.puts("📊 Summary:")
|
|
IO.puts(" Categories: #{length(Inventory.list_categories())}")
|
|
|
|
IO.puts(
|
|
" Storage Locations: #{length(Inventory.list_storage_locations())} (with auto-assigned AprilTags)"
|
|
)
|
|
|
|
IO.puts(" Components: #{length(Inventory.list_components())}")
|
|
IO.puts("")
|
|
IO.puts("🏷️ AprilTag System:")
|
|
IO.puts(" - Each storage location has an auto-assigned AprilTag ID (0-586)")
|
|
IO.puts(" - SVG files available at /apriltags/tag36h11_id_XXX.svg")
|
|
IO.puts(" - Download AprilTags from storage location management page")
|
|
IO.puts("")
|
|
IO.puts("🔐 Login with password: changeme (or set AUTH_PASSWORD environment variable)")
|
|
IO.puts("🌐 Visit http://localhost:4000 to start using the system!")
|