ammocpr/priv/repo/seeds.exs
Graham McIntire bbe5bde145
Initial implementation of ammo price tracker
Phoenix 1.8 app that scrapes ammunition retailers (Lucky Gunner,
SGAmmo) for price data and displays historical price trends.

- Data model: retailers, calibers, products, price snapshots
- Scraper infrastructure with Req, Floki, realistic browser headers
- Oban-scheduled scrape jobs (every 4h with randomized delays)
- LiveView pages: homepage with category cards, caliber detail with
  price table, Chart.js price history, and price stats banner
- 18 seeded calibers across handgun/rifle/rimfire/shotgun categories
- 77 tests
2026-03-11 15:58:12 -05:00

85 lines
2.9 KiB
Elixir

alias Ammoprices.Catalog.Caliber
alias Ammoprices.Catalog.Retailer
alias Ammoprices.Repo
# Retailers
retailers = [
%{
name: "Lucky Gunner",
slug: "lucky-gunner",
base_url: "https://www.luckygunner.com"
},
%{
name: "SGAmmo",
slug: "sgammo",
base_url: "https://www.sgammo.com"
}
]
for attrs <- retailers do
%Retailer{}
|> Retailer.changeset(attrs)
|> Repo.insert!(on_conflict: :nothing, conflict_target: :slug)
end
# Calibers by category
calibers = [
# Handgun
%{name: "9mm Luger", slug: "9mm-luger", category: "handgun", aliases: ["9mm", "9x19", "9mm parabellum", "9mm nato"]},
%{name: ".45 ACP", slug: "45-acp", category: "handgun", aliases: [".45 acp", "45 acp", ".45 auto", "45 auto"]},
%{name: ".380 ACP", slug: "380-acp", category: "handgun", aliases: [".380", "380 acp", ".380 auto", "380 auto"]},
%{name: ".40 S&W", slug: "40-sw", category: "handgun", aliases: [".40 s&w", "40 s&w", ".40 cal", "40 cal"]},
%{
name: ".38 Special",
slug: "38-special",
category: "handgun",
aliases: [".38 spl", "38 special", ".38 spc", "38 spl"]
},
%{name: ".357 Magnum", slug: "357-magnum", category: "handgun", aliases: [".357 mag", "357 mag", "357 magnum"]},
%{name: "10mm Auto", slug: "10mm-auto", category: "handgun", aliases: ["10mm", "10mm auto"]},
# Rifle
%{
name: "5.56x45 / .223 Rem",
slug: "556-223",
category: "rifle",
aliases: ["5.56", "5.56x45", ".223", ".223 rem", "223 remington", "5.56 nato"]
},
%{
name: ".308 Win / 7.62x51",
slug: "308-win",
category: "rifle",
aliases: [".308", ".308 win", "308 winchester", "7.62x51", "7.62 nato"]
},
%{name: "7.62x39", slug: "762x39", category: "rifle", aliases: ["7.62x39", "7.62x39mm"]},
%{
name: ".30-06 Springfield",
slug: "30-06",
category: "rifle",
aliases: [".30-06", "30-06", "30-06 springfield", ".30-06 sprg"]
},
%{
name: ".300 Blackout",
slug: "300-blackout",
category: "rifle",
aliases: [".300 blk", "300 blackout", ".300 aac blackout", "300 blk"]
},
%{name: "6.5 Creedmoor", slug: "65-creedmoor", category: "rifle", aliases: ["6.5 creedmoor", "6.5cm", "6.5 cm"]},
# Rimfire
%{name: ".22 LR", slug: "22-lr", category: "rimfire", aliases: [".22 lr", "22 lr", ".22 long rifle", "22 long rifle"]},
%{name: ".22 WMR", slug: "22-wmr", category: "rimfire", aliases: [".22 wmr", "22 wmr", ".22 magnum", "22 mag"]},
%{name: ".17 HMR", slug: "17-hmr", category: "rimfire", aliases: [".17 hmr", "17 hmr", ".17 hornady magnum"]},
# Shotgun
%{name: "12 Gauge", slug: "12-gauge", category: "shotgun", aliases: ["12 gauge", "12 ga", "12ga"]},
%{name: "20 Gauge", slug: "20-gauge", category: "shotgun", aliases: ["20 gauge", "20 ga", "20ga"]}
]
for attrs <- calibers do
%Caliber{}
|> Caliber.changeset(attrs)
|> Repo.insert!(on_conflict: :nothing, conflict_target: :slug)
end
IO.puts("Seeded #{length(retailers)} retailers and #{length(calibers)} calibers")