mirror of
https://gitea.gofwd.group/sean/gunbuilder-next-tailwind.git
synced 2025-12-05 18:46:45 -05:00
shit show but data works
This commit is contained in:
1
.frontmatter/database/taxonomyDb.json
Normal file
1
.frontmatter/database/taxonomyDb.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -3,8 +3,13 @@ import type { Config } from "drizzle-kit";
|
||||
export default {
|
||||
schema: "./src/db/schema.ts",
|
||||
out: "./drizzle/migrations",
|
||||
driver: "pg",
|
||||
dialect: "postgresql",
|
||||
dbCredentials: {
|
||||
connectionString: process.env.DATABASE_URL!,
|
||||
host: process.env.DB_HOST!,
|
||||
port: Number(process.env.DB_PORT!),
|
||||
user: process.env.DB_USER!,
|
||||
password: process.env.DB_PASSWORD!,
|
||||
database: process.env.DB_NAME!,
|
||||
ssl: false,
|
||||
},
|
||||
} satisfies Config;
|
||||
77
drizzle/migrations/0000_luxuriant_albert_cleary.sql
Normal file
77
drizzle/migrations/0000_luxuriant_albert_cleary.sql
Normal file
@@ -0,0 +1,77 @@
|
||||
-- Current sql file was generated after introspecting the database
|
||||
-- If you want to run this migration please uncomment this code before executing migrations
|
||||
/*
|
||||
CREATE TABLE "product_category_mappings" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"feed_name" varchar(255),
|
||||
"feed_category_value" varchar(255),
|
||||
"canonical_category_id" integer,
|
||||
"confidence_score" double precision,
|
||||
"last_reviewed_by" varchar(255),
|
||||
"last_reviewed_at" timestamp
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "categories" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"name" varchar(255) NOT NULL,
|
||||
"parent_id" integer,
|
||||
"slug" varchar(255) NOT NULL,
|
||||
CONSTRAINT "categories_slug_key" UNIQUE("slug")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "products" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"name" varchar(255) NOT NULL,
|
||||
"brand" varchar(255),
|
||||
"description" text,
|
||||
"upc" varchar(32),
|
||||
"mpn" varchar(64),
|
||||
"canonical_category_id" integer,
|
||||
"created_at" timestamp DEFAULT now(),
|
||||
"updated_at" timestamp DEFAULT now()
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "offers" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"product_id" integer,
|
||||
"feed_name" varchar(255) NOT NULL,
|
||||
"feed_sku" varchar(255),
|
||||
"price" numeric(10, 2),
|
||||
"url" text,
|
||||
"in_stock" boolean,
|
||||
"vendor" varchar(255),
|
||||
"last_seen_at" timestamp DEFAULT now(),
|
||||
"raw_data" jsonb,
|
||||
CONSTRAINT "offers_product_id_feed_name_feed_sku_key" UNIQUE("product_id","feed_name","feed_sku"),
|
||||
CONSTRAINT "offers_feed_unique" UNIQUE("feed_name","feed_sku")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "offer_price_history" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"offer_id" integer,
|
||||
"price" numeric(10, 2) NOT NULL,
|
||||
"seen_at" timestamp DEFAULT now()
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "feeds" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"name" varchar(255) NOT NULL,
|
||||
"url" text,
|
||||
"last_imported_at" timestamp,
|
||||
CONSTRAINT "feeds_name_key" UNIQUE("name")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "product_attributes" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"product_id" integer,
|
||||
"name" varchar(255) NOT NULL,
|
||||
"value" varchar(255) NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "product_category_mappings" ADD CONSTRAINT "product_category_mappings_canonical_category_id_fkey" FOREIGN KEY ("canonical_category_id") REFERENCES "public"."categories"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "categories" ADD CONSTRAINT "categories_parent_id_fkey" FOREIGN KEY ("parent_id") REFERENCES "public"."categories"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "products" ADD CONSTRAINT "products_canonical_category_id_fkey" FOREIGN KEY ("canonical_category_id") REFERENCES "public"."categories"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "offers" ADD CONSTRAINT "offers_product_id_fkey" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "offer_price_history" ADD CONSTRAINT "offer_price_history_offer_id_fkey" FOREIGN KEY ("offer_id") REFERENCES "public"."offers"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "product_attributes" ADD CONSTRAINT "product_attributes_product_id_fkey" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;
|
||||
*/
|
||||
7
drizzle/migrations/0001_superb_umar.sql
Normal file
7
drizzle/migrations/0001_superb_umar.sql
Normal file
@@ -0,0 +1,7 @@
|
||||
DROP TABLE "product_category_mappings" CASCADE;--> statement-breakpoint
|
||||
DROP TABLE "categories" CASCADE;--> statement-breakpoint
|
||||
DROP TABLE "products" CASCADE;--> statement-breakpoint
|
||||
DROP TABLE "offers" CASCADE;--> statement-breakpoint
|
||||
DROP TABLE "offer_price_history" CASCADE;--> statement-breakpoint
|
||||
DROP TABLE "feeds" CASCADE;--> statement-breakpoint
|
||||
DROP TABLE "product_attributes" CASCADE;
|
||||
493
drizzle/migrations/meta/0000_snapshot.json
Normal file
493
drizzle/migrations/meta/0000_snapshot.json
Normal file
@@ -0,0 +1,493 @@
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000000",
|
||||
"prevId": "",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
"public.product_category_mappings": {
|
||||
"name": "product_category_mappings",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"feed_name": {
|
||||
"name": "feed_name",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"feed_category_value": {
|
||||
"name": "feed_category_value",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"canonical_category_id": {
|
||||
"name": "canonical_category_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"confidence_score": {
|
||||
"name": "confidence_score",
|
||||
"type": "double precision",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"last_reviewed_by": {
|
||||
"name": "last_reviewed_by",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"last_reviewed_at": {
|
||||
"name": "last_reviewed_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"product_category_mappings_canonical_category_id_fkey": {
|
||||
"name": "product_category_mappings_canonical_category_id_fkey",
|
||||
"tableFrom": "product_category_mappings",
|
||||
"tableTo": "categories",
|
||||
"schemaTo": "public",
|
||||
"columnsFrom": [
|
||||
"canonical_category_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {},
|
||||
"policies": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.categories": {
|
||||
"name": "categories",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"parent_id": {
|
||||
"name": "parent_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"categories_parent_id_fkey": {
|
||||
"name": "categories_parent_id_fkey",
|
||||
"tableFrom": "categories",
|
||||
"tableTo": "categories",
|
||||
"schemaTo": "public",
|
||||
"columnsFrom": [
|
||||
"parent_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"categories_slug_key": {
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"nullsNotDistinct": false,
|
||||
"name": "categories_slug_key"
|
||||
}
|
||||
},
|
||||
"checkConstraints": {},
|
||||
"policies": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.products": {
|
||||
"name": "products",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"brand": {
|
||||
"name": "brand",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"upc": {
|
||||
"name": "upc",
|
||||
"type": "varchar(32)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"mpn": {
|
||||
"name": "mpn",
|
||||
"type": "varchar(64)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"canonical_category_id": {
|
||||
"name": "canonical_category_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"products_canonical_category_id_fkey": {
|
||||
"name": "products_canonical_category_id_fkey",
|
||||
"tableFrom": "products",
|
||||
"tableTo": "categories",
|
||||
"schemaTo": "public",
|
||||
"columnsFrom": [
|
||||
"canonical_category_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {},
|
||||
"policies": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.offers": {
|
||||
"name": "offers",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"product_id": {
|
||||
"name": "product_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"feed_name": {
|
||||
"name": "feed_name",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"feed_sku": {
|
||||
"name": "feed_sku",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"price": {
|
||||
"name": "price",
|
||||
"type": "numeric(10, 2)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"url": {
|
||||
"name": "url",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"in_stock": {
|
||||
"name": "in_stock",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"vendor": {
|
||||
"name": "vendor",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"last_seen_at": {
|
||||
"name": "last_seen_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
},
|
||||
"raw_data": {
|
||||
"name": "raw_data",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"offers_product_id_fkey": {
|
||||
"name": "offers_product_id_fkey",
|
||||
"tableFrom": "offers",
|
||||
"tableTo": "products",
|
||||
"schemaTo": "public",
|
||||
"columnsFrom": [
|
||||
"product_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"offers_product_id_feed_name_feed_sku_key": {
|
||||
"columns": [
|
||||
"product_id",
|
||||
"feed_name",
|
||||
"feed_sku"
|
||||
],
|
||||
"nullsNotDistinct": false,
|
||||
"name": "offers_product_id_feed_name_feed_sku_key"
|
||||
},
|
||||
"offers_feed_unique": {
|
||||
"columns": [
|
||||
"feed_name",
|
||||
"feed_sku"
|
||||
],
|
||||
"nullsNotDistinct": false,
|
||||
"name": "offers_feed_unique"
|
||||
}
|
||||
},
|
||||
"checkConstraints": {},
|
||||
"policies": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.offer_price_history": {
|
||||
"name": "offer_price_history",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"offer_id": {
|
||||
"name": "offer_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"price": {
|
||||
"name": "price",
|
||||
"type": "numeric(10, 2)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"seen_at": {
|
||||
"name": "seen_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"offer_price_history_offer_id_fkey": {
|
||||
"name": "offer_price_history_offer_id_fkey",
|
||||
"tableFrom": "offer_price_history",
|
||||
"tableTo": "offers",
|
||||
"schemaTo": "public",
|
||||
"columnsFrom": [
|
||||
"offer_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {},
|
||||
"policies": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.feeds": {
|
||||
"name": "feeds",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"url": {
|
||||
"name": "url",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"last_imported_at": {
|
||||
"name": "last_imported_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"feeds_name_key": {
|
||||
"columns": [
|
||||
"name"
|
||||
],
|
||||
"nullsNotDistinct": false,
|
||||
"name": "feeds_name_key"
|
||||
}
|
||||
},
|
||||
"checkConstraints": {},
|
||||
"policies": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.product_attributes": {
|
||||
"name": "product_attributes",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"product_id": {
|
||||
"name": "product_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"value": {
|
||||
"name": "value",
|
||||
"type": "varchar(255)",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"product_attributes_product_id_fkey": {
|
||||
"name": "product_attributes_product_id_fkey",
|
||||
"tableFrom": "product_attributes",
|
||||
"tableTo": "products",
|
||||
"schemaTo": "public",
|
||||
"columnsFrom": [
|
||||
"product_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {},
|
||||
"policies": {},
|
||||
"isRLSEnabled": false
|
||||
}
|
||||
},
|
||||
"enums": {},
|
||||
"schemas": {},
|
||||
"sequences": {},
|
||||
"roles": {},
|
||||
"policies": {},
|
||||
"views": {},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
},
|
||||
"internal": {
|
||||
"tables": {}
|
||||
}
|
||||
}
|
||||
18
drizzle/migrations/meta/0001_snapshot.json
Normal file
18
drizzle/migrations/meta/0001_snapshot.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"id": "919e511e-3cff-4bd0-b4ec-20865db2d1d3",
|
||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {},
|
||||
"enums": {},
|
||||
"schemas": {},
|
||||
"sequences": {},
|
||||
"roles": {},
|
||||
"policies": {},
|
||||
"views": {},
|
||||
"_meta": {
|
||||
"columns": {},
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
||||
20
drizzle/migrations/meta/_journal.json
Normal file
20
drizzle/migrations/meta/_journal.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "7",
|
||||
"when": 1751488452074,
|
||||
"tag": "0000_luxuriant_albert_cleary",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "7",
|
||||
"when": 1751488491929,
|
||||
"tag": "0001_superb_umar",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
53
drizzle/migrations/relations.ts
Normal file
53
drizzle/migrations/relations.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { relations } from "drizzle-orm/relations";
|
||||
import { categories, productCategoryMappings, products, offers, offerPriceHistory, productAttributes } from "./schema";
|
||||
|
||||
export const productCategoryMappingsRelations = relations(productCategoryMappings, ({one}) => ({
|
||||
category: one(categories, {
|
||||
fields: [productCategoryMappings.canonicalCategoryId],
|
||||
references: [categories.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const categoriesRelations = relations(categories, ({one, many}) => ({
|
||||
productCategoryMappings: many(productCategoryMappings),
|
||||
category: one(categories, {
|
||||
fields: [categories.parentId],
|
||||
references: [categories.id],
|
||||
relationName: "categories_parentId_categories_id"
|
||||
}),
|
||||
categories: many(categories, {
|
||||
relationName: "categories_parentId_categories_id"
|
||||
}),
|
||||
products: many(products),
|
||||
}));
|
||||
|
||||
export const productsRelations = relations(products, ({one, many}) => ({
|
||||
category: one(categories, {
|
||||
fields: [products.canonicalCategoryId],
|
||||
references: [categories.id]
|
||||
}),
|
||||
offers: many(offers),
|
||||
productAttributes: many(productAttributes),
|
||||
}));
|
||||
|
||||
export const offersRelations = relations(offers, ({one, many}) => ({
|
||||
product: one(products, {
|
||||
fields: [offers.productId],
|
||||
references: [products.id]
|
||||
}),
|
||||
offerPriceHistories: many(offerPriceHistory),
|
||||
}));
|
||||
|
||||
export const offerPriceHistoryRelations = relations(offerPriceHistory, ({one}) => ({
|
||||
offer: one(offers, {
|
||||
fields: [offerPriceHistory.offerId],
|
||||
references: [offers.id]
|
||||
}),
|
||||
}));
|
||||
|
||||
export const productAttributesRelations = relations(productAttributes, ({one}) => ({
|
||||
product: one(products, {
|
||||
fields: [productAttributes.productId],
|
||||
references: [products.id]
|
||||
}),
|
||||
}));
|
||||
108
drizzle/migrations/schema.ts
Normal file
108
drizzle/migrations/schema.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { pgTable, foreignKey, serial, varchar, integer, doublePrecision, timestamp, unique, text, numeric, boolean, jsonb } from "drizzle-orm/pg-core"
|
||||
import { sql } from "drizzle-orm"
|
||||
|
||||
|
||||
|
||||
export const productCategoryMappings = pgTable("product_category_mappings", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
feedName: varchar("feed_name", { length: 255 }),
|
||||
feedCategoryValue: varchar("feed_category_value", { length: 255 }),
|
||||
canonicalCategoryId: integer("canonical_category_id"),
|
||||
confidenceScore: doublePrecision("confidence_score"),
|
||||
lastReviewedBy: varchar("last_reviewed_by", { length: 255 }),
|
||||
lastReviewedAt: timestamp("last_reviewed_at", { mode: 'string' }),
|
||||
}, (table) => [
|
||||
foreignKey({
|
||||
columns: [table.canonicalCategoryId],
|
||||
foreignColumns: [categories.id],
|
||||
name: "product_category_mappings_canonical_category_id_fkey"
|
||||
}),
|
||||
]);
|
||||
|
||||
export const categories = pgTable("categories", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
name: varchar({ length: 255 }).notNull(),
|
||||
parentId: integer("parent_id"),
|
||||
slug: varchar({ length: 255 }).notNull(),
|
||||
}, (table) => [
|
||||
foreignKey({
|
||||
columns: [table.parentId],
|
||||
foreignColumns: [table.id],
|
||||
name: "categories_parent_id_fkey"
|
||||
}),
|
||||
unique("categories_slug_key").on(table.slug),
|
||||
]);
|
||||
|
||||
export const products = pgTable("products", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
name: varchar({ length: 255 }).notNull(),
|
||||
brand: varchar({ length: 255 }),
|
||||
description: text(),
|
||||
upc: varchar({ length: 32 }),
|
||||
mpn: varchar({ length: 64 }),
|
||||
canonicalCategoryId: integer("canonical_category_id"),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow(),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow(),
|
||||
}, (table) => [
|
||||
foreignKey({
|
||||
columns: [table.canonicalCategoryId],
|
||||
foreignColumns: [categories.id],
|
||||
name: "products_canonical_category_id_fkey"
|
||||
}),
|
||||
]);
|
||||
|
||||
export const offers = pgTable("offers", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
productId: integer("product_id"),
|
||||
feedName: varchar("feed_name", { length: 255 }).notNull(),
|
||||
feedSku: varchar("feed_sku", { length: 255 }),
|
||||
price: numeric({ precision: 10, scale: 2 }),
|
||||
url: text(),
|
||||
inStock: boolean("in_stock"),
|
||||
vendor: varchar({ length: 255 }),
|
||||
lastSeenAt: timestamp("last_seen_at", { mode: 'string' }).defaultNow(),
|
||||
rawData: jsonb("raw_data"),
|
||||
}, (table) => [
|
||||
foreignKey({
|
||||
columns: [table.productId],
|
||||
foreignColumns: [products.id],
|
||||
name: "offers_product_id_fkey"
|
||||
}).onDelete("cascade"),
|
||||
unique("offers_product_id_feed_name_feed_sku_key").on(table.productId, table.feedName, table.feedSku),
|
||||
unique("offers_feed_unique").on(table.feedName, table.feedSku),
|
||||
]);
|
||||
|
||||
export const offerPriceHistory = pgTable("offer_price_history", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
offerId: integer("offer_id"),
|
||||
price: numeric({ precision: 10, scale: 2 }).notNull(),
|
||||
seenAt: timestamp("seen_at", { mode: 'string' }).defaultNow(),
|
||||
}, (table) => [
|
||||
foreignKey({
|
||||
columns: [table.offerId],
|
||||
foreignColumns: [offers.id],
|
||||
name: "offer_price_history_offer_id_fkey"
|
||||
}).onDelete("cascade"),
|
||||
]);
|
||||
|
||||
export const feeds = pgTable("feeds", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
name: varchar({ length: 255 }).notNull(),
|
||||
url: text(),
|
||||
lastImportedAt: timestamp("last_imported_at", { mode: 'string' }),
|
||||
}, (table) => [
|
||||
unique("feeds_name_key").on(table.name),
|
||||
]);
|
||||
|
||||
export const productAttributes = pgTable("product_attributes", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
productId: integer("product_id"),
|
||||
name: varchar({ length: 255 }).notNull(),
|
||||
value: varchar({ length: 255 }).notNull(),
|
||||
}, (table) => [
|
||||
foreignKey({
|
||||
columns: [table.productId],
|
||||
foreignColumns: [products.id],
|
||||
name: "product_attributes_product_id_fkey"
|
||||
}).onDelete("cascade"),
|
||||
]);
|
||||
52
frontmatter.json
Normal file
52
frontmatter.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"$schema": "https://frontmatter.codes/frontmatter.schema.json",
|
||||
"frontMatter.taxonomy.contentTypes": [
|
||||
{
|
||||
"name": "default",
|
||||
"pageBundle": false,
|
||||
"previewPath": null,
|
||||
"fields": [
|
||||
{
|
||||
"title": "Title",
|
||||
"name": "title",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"title": "Description",
|
||||
"name": "description",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"title": "Publishing date",
|
||||
"name": "date",
|
||||
"type": "datetime",
|
||||
"default": "{{now}}",
|
||||
"isPublishDate": true
|
||||
},
|
||||
{
|
||||
"title": "Content preview",
|
||||
"name": "preview",
|
||||
"type": "image"
|
||||
},
|
||||
{
|
||||
"title": "Is in draft",
|
||||
"name": "draft",
|
||||
"type": "draft"
|
||||
},
|
||||
{
|
||||
"title": "Tags",
|
||||
"name": "tags",
|
||||
"type": "tags"
|
||||
},
|
||||
{
|
||||
"title": "Categories",
|
||||
"name": "categories",
|
||||
"type": "categories"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"frontMatter.framework.id": "next",
|
||||
"frontMatter.content.publicFolder": "public",
|
||||
"frontMatter.preview.host": "http://localhost:3000"
|
||||
}
|
||||
70
package-lock.json
generated
70
package-lock.json
generated
@@ -16,7 +16,6 @@
|
||||
"bcryptjs": "^3.0.2",
|
||||
"daisyui": "^4.7.3",
|
||||
"date-fns": "^4.1.0",
|
||||
"drizzle-kit": "^0.31.4",
|
||||
"drizzle-orm": "^0.44.2",
|
||||
"lucide-react": "^0.525.0",
|
||||
"next": "^14.2.30",
|
||||
@@ -33,6 +32,7 @@
|
||||
"@types/pg": "^8.15.4",
|
||||
"@types/react": "^18.2.0",
|
||||
"@types/react-dom": "^18.2.0",
|
||||
"drizzle-kit": "^0.31.4",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "15.3.4",
|
||||
"typescript": "^5"
|
||||
@@ -159,7 +159,8 @@
|
||||
"node_modules/@drizzle-team/brocli": {
|
||||
"version": "0.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@drizzle-team/brocli/-/brocli-0.10.2.tgz",
|
||||
"integrity": "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="
|
||||
"integrity": "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@emnapi/core": {
|
||||
"version": "1.4.3",
|
||||
@@ -197,6 +198,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz",
|
||||
"integrity": "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==",
|
||||
"deprecated": "Merged into tsx: https://tsx.is",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "~0.18.20",
|
||||
"source-map-support": "^0.5.21"
|
||||
@@ -209,6 +211,7 @@
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
@@ -224,6 +227,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
@@ -239,6 +243,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
@@ -254,6 +259,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
@@ -269,6 +275,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
@@ -284,6 +291,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
@@ -299,6 +307,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
@@ -314,6 +323,7 @@
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -329,6 +339,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -344,6 +355,7 @@
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -359,6 +371,7 @@
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -374,6 +387,7 @@
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -389,6 +403,7 @@
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -404,6 +419,7 @@
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -419,6 +435,7 @@
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -434,6 +451,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -449,6 +467,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
@@ -464,6 +483,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
@@ -479,6 +499,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
@@ -494,6 +515,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
@@ -509,6 +531,7 @@
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
@@ -524,6 +547,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
@@ -536,6 +560,7 @@
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
|
||||
"integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
@@ -573,6 +598,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.6.5.tgz",
|
||||
"integrity": "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==",
|
||||
"deprecated": "Merged into tsx: https://tsx.is",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@esbuild-kit/core-utils": "^3.3.2",
|
||||
"get-tsconfig": "^4.7.0"
|
||||
@@ -585,6 +611,7 @@
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
@@ -600,6 +627,7 @@
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
@@ -615,6 +643,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
@@ -630,6 +659,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
@@ -645,6 +675,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
@@ -660,6 +691,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
@@ -675,6 +707,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
@@ -690,6 +723,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
@@ -705,6 +739,7 @@
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -720,6 +755,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -735,6 +771,7 @@
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -750,6 +787,7 @@
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -765,6 +803,7 @@
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -780,6 +819,7 @@
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -795,6 +835,7 @@
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -810,6 +851,7 @@
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -825,6 +867,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -840,6 +883,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
@@ -855,6 +899,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
@@ -870,6 +915,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
@@ -885,6 +931,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
@@ -900,6 +947,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
@@ -915,6 +963,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
@@ -930,6 +979,7 @@
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
@@ -945,6 +995,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
@@ -2652,7 +2703,8 @@
|
||||
"node_modules/buffer-from": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/busboy": {
|
||||
"version": "1.6.0",
|
||||
@@ -2985,6 +3037,7 @@
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
|
||||
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
@@ -3063,6 +3116,8 @@
|
||||
"version": "0.31.4",
|
||||
"resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.31.4.tgz",
|
||||
"integrity": "sha512-tCPWVZWZqWVx2XUsVpJRnH9Mx0ClVOf5YUHerZ5so1OKSlqww4zy1R5ksEdGRcO3tM3zj0PYN6V48TbQCL1RfA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@drizzle-team/brocli": "^0.10.2",
|
||||
"@esbuild-kit/esm-loader": "^2.5.5",
|
||||
@@ -3399,6 +3454,7 @@
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
|
||||
"integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
@@ -3438,6 +3494,7 @@
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz",
|
||||
"integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
@@ -4136,6 +4193,7 @@
|
||||
"version": "4.10.1",
|
||||
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz",
|
||||
"integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"resolve-pkg-maps": "^1.0.0"
|
||||
},
|
||||
@@ -5059,7 +5117,8 @@
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/mz": {
|
||||
"version": "2.7.0",
|
||||
@@ -6038,6 +6097,7 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
|
||||
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
||||
}
|
||||
@@ -6297,6 +6357,7 @@
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -6313,6 +6374,7 @@
|
||||
"version": "0.5.21",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"source-map": "^0.6.0"
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
"bcryptjs": "^3.0.2",
|
||||
"daisyui": "^4.7.3",
|
||||
"date-fns": "^4.1.0",
|
||||
"drizzle-kit": "^0.31.4",
|
||||
"drizzle-orm": "^0.44.2",
|
||||
"lucide-react": "^0.525.0",
|
||||
"next": "^14.2.30",
|
||||
@@ -34,6 +33,7 @@
|
||||
"@types/pg": "^8.15.4",
|
||||
"@types/react": "^18.2.0",
|
||||
"@types/react-dom": "^18.2.0",
|
||||
"drizzle-kit": "^0.31.4",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "15.3.4",
|
||||
"typescript": "^5"
|
||||
|
||||
@@ -3,14 +3,12 @@ import { useEffect, useState, useMemo } from 'react';
|
||||
import { useParams } from 'next/navigation';
|
||||
|
||||
const columns = [
|
||||
'brandName',
|
||||
'productName',
|
||||
'department',
|
||||
'category',
|
||||
'subcategory',
|
||||
'retailPrice',
|
||||
'salePrice',
|
||||
'imageUrl',
|
||||
'name',
|
||||
'brand',
|
||||
'description',
|
||||
'slug',
|
||||
'createdAt',
|
||||
'updatedAt',
|
||||
];
|
||||
|
||||
export default function PartsCategoryPage() {
|
||||
@@ -61,14 +59,14 @@ export default function PartsCategoryPage() {
|
||||
});
|
||||
}, [products, categoryParam]);
|
||||
|
||||
const brandOptions = useMemo(() => Array.from(new Set(filteredByCategory.map(p => p.brandName).filter(Boolean))).sort(), [filteredByCategory]);
|
||||
const brandOptions = useMemo(() => Array.from(new Set(filteredByCategory.map(p => p.brand).filter(Boolean))).sort(), [filteredByCategory]);
|
||||
const departmentOptions = useMemo(() => Array.from(new Set(filteredByCategory.map(p => p.department).filter(Boolean))).sort(), [filteredByCategory]);
|
||||
const subcategoryOptions = useMemo(() => Array.from(new Set(filteredByCategory.map(p => p.subcategory).filter(Boolean))).sort(), [filteredByCategory]);
|
||||
|
||||
// Further filter by sidebar filters
|
||||
const filteredProducts = useMemo(() => {
|
||||
return filteredByCategory.filter(p =>
|
||||
(!brand || p.brandName === brand) &&
|
||||
(!brand || p.brand === brand) &&
|
||||
(!department || p.department === department) &&
|
||||
(!subcategory || p.subcategory === subcategory)
|
||||
);
|
||||
@@ -138,19 +136,19 @@ export default function PartsCategoryPage() {
|
||||
) : paginatedProducts.length === 0 ? (
|
||||
<tr><td colSpan={columns.length} className="text-center py-8">No products found.</td></tr>
|
||||
) : (
|
||||
paginatedProducts.map((product, i) => (
|
||||
<tr key={product.uuid || i} className="border-b hover:bg-zinc-50">
|
||||
{columns.map(col => (
|
||||
<td key={col} className="px-2 py-1 max-w-xs truncate">
|
||||
{col === 'imageUrl' && product[col] ? (
|
||||
<img src={product[col]} alt="thumb" className="h-10 w-10 object-contain border rounded" />
|
||||
) : (
|
||||
product[col] ?? ''
|
||||
)}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
))
|
||||
paginatedProducts
|
||||
.filter(product => columns.some(col => product[col] && String(product[col]).trim() !== ''))
|
||||
.map((product, i) => (
|
||||
<tr key={product.id || i} className="border-b hover:bg-zinc-50">
|
||||
{columns.map(col => (
|
||||
<td key={col} className="px-2 py-1 max-w-xs truncate">
|
||||
{typeof product[col] === 'object' && product[col] !== null
|
||||
? JSON.stringify(product[col])
|
||||
: product[col] ?? ''}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -343,7 +343,7 @@ const useCanonicalCategories = () => {
|
||||
const [categories, setCategories] = useState<any[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
useEffect(() => {
|
||||
fetch('/api/product-categories')
|
||||
fetch('/api/categories')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
setCategories(data.data);
|
||||
@@ -390,14 +390,12 @@ function getDescendantCategoryIds(categories: any[], selectedId: string): string
|
||||
}
|
||||
|
||||
const columns = [
|
||||
'brandName',
|
||||
'productName',
|
||||
'department',
|
||||
'category',
|
||||
'subcategory',
|
||||
'retailPrice',
|
||||
'salePrice',
|
||||
'imageUrl',
|
||||
'name',
|
||||
'brand',
|
||||
'description',
|
||||
'slug',
|
||||
'createdAt',
|
||||
'updatedAt',
|
||||
];
|
||||
|
||||
export default function PartsPage() {
|
||||
@@ -413,6 +411,20 @@ export default function PartsPage() {
|
||||
const [category, setCategory] = useState('');
|
||||
const [subcategory, setSubcategory] = useState('');
|
||||
|
||||
// Category data from canonical API
|
||||
const { categories, loading: categoriesLoading } = useCanonicalCategories();
|
||||
const flatCategories = useMemo(() => flattenCategories(categories), [categories]);
|
||||
|
||||
// Updated filter options
|
||||
const categoryOptions = useMemo(
|
||||
() => flatCategories.filter(cat => cat.parentId === null).map(cat => ({ value: String(cat.id), label: cat.name })),
|
||||
[flatCategories]
|
||||
);
|
||||
const subcategoryOptions = useMemo(
|
||||
() => flatCategories.filter(cat => cat.parentId === parseInt(category)).map(cat => ({ value: String(cat.id), label: cat.name })),
|
||||
[flatCategories, category]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
@@ -431,16 +443,14 @@ export default function PartsPage() {
|
||||
// Get unique filter options from all products
|
||||
const brandOptions = useMemo(() => Array.from(new Set(products.map(p => p.brandName).filter(Boolean))).sort(), [products]);
|
||||
const departmentOptions = useMemo(() => Array.from(new Set(products.map(p => p.department).filter(Boolean))).sort(), [products]);
|
||||
const categoryOptions = useMemo(() => Array.from(new Set(products.map(p => p.category).filter(Boolean))).sort(), [products]);
|
||||
const subcategoryOptions = useMemo(() => Array.from(new Set(products.map(p => p.subcategory).filter(Boolean))).sort(), [products]);
|
||||
|
||||
// Filter products before rendering
|
||||
// Filter products before rendering (match by category/subcategory ID if available)
|
||||
const filteredProducts = useMemo(() => {
|
||||
return products.filter(p =>
|
||||
(!brand || p.brandName === brand) &&
|
||||
(!department || p.department === department) &&
|
||||
(!category || p.category === category) &&
|
||||
(!subcategory || p.subcategory === subcategory)
|
||||
(!category || String(p.categoryId) === category) &&
|
||||
(!subcategory || String(p.subcategoryId) === subcategory)
|
||||
);
|
||||
}, [products, brand, department, category, subcategory]);
|
||||
|
||||
@@ -465,25 +475,18 @@ export default function PartsPage() {
|
||||
{brandOptions.map(opt => <option key={opt} value={opt}>{opt}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-semibold mb-1">Department</label>
|
||||
<select className="border rounded px-2 py-1 min-w-[120px] w-full" value={department} onChange={e => setDepartment(e.target.value)}>
|
||||
<option value="">All</option>
|
||||
{departmentOptions.map(opt => <option key={opt} value={opt}>{opt}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-semibold mb-1">Category</label>
|
||||
<select className="border rounded px-2 py-1 min-w-[120px] w-full" value={category} onChange={e => setCategory(e.target.value)}>
|
||||
<select className="border rounded px-2 py-1 min-w-[120px] w-full" value={category} onChange={e => { setCategory(e.target.value); setSubcategory(''); }}>
|
||||
<option value="">All</option>
|
||||
{categoryOptions.map(opt => <option key={opt} value={opt}>{opt}</option>)}
|
||||
{categoryOptions.map(opt => <option key={opt.value} value={opt.value}>{opt.label}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-semibold mb-1">Subcategory</label>
|
||||
<select className="border rounded px-2 py-1 min-w-[120px] w-full" value={subcategory} onChange={e => setSubcategory(e.target.value)}>
|
||||
<option value="">All</option>
|
||||
{subcategoryOptions.map(opt => <option key={opt} value={opt}>{opt}</option>)}
|
||||
{subcategoryOptions.map(opt => <option key={opt.value} value={opt.value}>{opt.label}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -505,19 +508,19 @@ export default function PartsPage() {
|
||||
) : paginatedProducts.length === 0 ? (
|
||||
<tr><td colSpan={columns.length} className="text-center py-8">No products found.</td></tr>
|
||||
) : (
|
||||
paginatedProducts.map((product, i) => (
|
||||
<tr key={product.uuid || i} className="border-b hover:bg-zinc-50">
|
||||
{columns.map(col => (
|
||||
<td key={col} className="px-2 py-1 max-w-xs truncate">
|
||||
{col === 'imageUrl' && product[col] ? (
|
||||
<img src={product[col]} alt="thumb" className="h-10 w-10 object-contain border rounded" />
|
||||
) : (
|
||||
product[col] ?? ''
|
||||
)}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
))
|
||||
paginatedProducts
|
||||
.filter(product => columns.some(col => product[col] && String(product[col]).trim() !== ''))
|
||||
.map((product, i) => (
|
||||
<tr key={product.id || i} className="border-b hover:bg-zinc-50">
|
||||
{columns.map(col => (
|
||||
<td key={col} className="px-2 py-1 max-w-xs truncate">
|
||||
{typeof product[col] === 'object' && product[col] !== null
|
||||
? JSON.stringify(product[col])
|
||||
: product[col] ?? ''}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { db } from '@/db';
|
||||
import { bb_products } from '@/db/schema';
|
||||
import { products } from '@/db/schema';
|
||||
|
||||
function slugify(name: string): string {
|
||||
return name
|
||||
@@ -13,7 +13,7 @@ export async function GET(
|
||||
{ params }: { params: { slug: string } }
|
||||
) {
|
||||
try {
|
||||
const allProducts = await db.select().from(bb_products);
|
||||
const allProducts = await db.select().from(products);
|
||||
const mapped = allProducts.map((item: any) => ({
|
||||
id: item.uuid,
|
||||
name: item.productName,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { db } from '@/db';
|
||||
import { bb_products } from '@/db/schema';
|
||||
import { products } from '@/db/schema';
|
||||
import { NextResponse } from 'next/server';
|
||||
import { sql } from 'drizzle-orm';
|
||||
|
||||
@@ -18,11 +18,11 @@ export async function GET(req: Request) {
|
||||
const offset = (page - 1) * limit;
|
||||
|
||||
// Get total count using raw SQL
|
||||
const totalResult = await db.execute(sql`SELECT COUNT(*)::int AS count FROM bb_products`);
|
||||
const totalResult = await db.execute(sql`SELECT COUNT(*)::int AS count FROM products`);
|
||||
const total = Number(totalResult.rows?.[0]?.count || 0);
|
||||
|
||||
// Get paginated products
|
||||
const allProducts = await db.select().from(bb_products).limit(limit).offset(offset);
|
||||
const allProducts = await db.select().from(products).limit(limit).offset(offset);
|
||||
const mapped = allProducts.map((item: any) => ({
|
||||
...item,
|
||||
slug: slugify(item.productName || item.product_name || item.name || ''),
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { db } from "@/db";
|
||||
import { bb_products } from "@/db/schema";
|
||||
import { products } from "@/db/schema";
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const allProducts = await db.select().from(bb_products).limit(50);
|
||||
const allProducts = await db.select().from(products).limit(50);
|
||||
const mapped = allProducts.map((item: any) => ({
|
||||
id: item.uuid,
|
||||
name: item.productName,
|
||||
|
||||
571
src/db/schema-org.ts
Normal file
571
src/db/schema-org.ts
Normal file
@@ -0,0 +1,571 @@
|
||||
import { pgTableCreator, integer, varchar, text, numeric, timestamp, unique, check, date, boolean, uuid, bigint, real, doublePrecision, primaryKey, pgView, index, serial } from "drizzle-orm/pg-core";
|
||||
import { relations, sql } from "drizzle-orm";
|
||||
import { DATABASE_PREFIX as prefix } from "@/lib/constants";
|
||||
|
||||
export const pgTable = pgTableCreator((name) => (prefix == "" || prefix == null) ? name: `${prefix}_${name}`);
|
||||
///
|
||||
export const products = pgTable("products", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "products_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
name: varchar({ length: 255 }).notNull(),
|
||||
description: text().notNull(),
|
||||
price: numeric().notNull(),
|
||||
resellerId: integer("reseller_id").notNull(),
|
||||
categoryId: integer("category_id").notNull(),
|
||||
stockQty: integer("stock_qty").default(0),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
});
|
||||
|
||||
export const categories = pgTable("categories", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "categories_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
name: varchar({ length: 100 }).notNull(),
|
||||
parentCategoryId: integer("parent_category_id"),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
});
|
||||
|
||||
export const productFeeds = pgTable("product_feeds", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "productfeeds_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
resellerId: integer("reseller_id").notNull(),
|
||||
feedUrl: varchar("feed_url", { length: 255 }).notNull(),
|
||||
lastUpdate: timestamp("last_update", { mode: 'string' }),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
}, (table) => {
|
||||
return {
|
||||
productFeedsUuidUnique: unique("product_feeds_uuid_unique").on(table.uuid),
|
||||
}
|
||||
});
|
||||
|
||||
export const userActivityLog = pgTable("user_activity_log", {
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
id: bigint({ mode: "number" }).primaryKey().generatedAlwaysAsIdentity({ name: "user_activity_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
activity: text().notNull(),
|
||||
timestamp: timestamp({ mode: 'string' }).default(sql`CURRENT_TIMESTAMP`),
|
||||
});
|
||||
|
||||
export const brands = pgTable("brands", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "brands_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
name: varchar({ length: 100 }).notNull(),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
}, (table) => {
|
||||
return {
|
||||
brandsUuidUnique: unique("brands_uuid_unique").on(table.uuid),
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export const manufacturer = pgTable("manufacturer", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "manufacturer_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
name: varchar({ length: 100 }).notNull(),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
}, (table) => {
|
||||
return {
|
||||
manufacturerUuidUnique: unique("manufacturer_uuid_unique").on(table.uuid),
|
||||
}
|
||||
});
|
||||
|
||||
export const states = pgTable("states", {
|
||||
id: integer().primaryKey().generatedByDefaultAsIdentity({ name: "states_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
state: varchar({ length: 50 }),
|
||||
abbreviation: varchar({ length: 50 }),
|
||||
});
|
||||
|
||||
export const componentType = pgTable("component_type", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "component_type_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
name: varchar({ length: 100 }).notNull(),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
}, (table) => {
|
||||
return {
|
||||
componentTypeUuidUnique: unique("component_type_uuid_unique").on(table.uuid),
|
||||
}
|
||||
});
|
||||
|
||||
export const aeroPrecision = pgTable("aero_precision", {
|
||||
sku: text().primaryKey().notNull(),
|
||||
manufacturerId: text("manufacturer_id"),
|
||||
brandName: text("brand_name"),
|
||||
productName: text("product_name"),
|
||||
longDescription: text("long_description"),
|
||||
shortDescription: text("short_description"),
|
||||
department: text(),
|
||||
category: text(),
|
||||
subcategory: text(),
|
||||
thumbUrl: text("thumb_url"),
|
||||
imageUrl: text("image_url"),
|
||||
buyLink: text("buy_link"),
|
||||
keywords: text(),
|
||||
reviews: text(),
|
||||
retailPrice: numeric("retail_price"),
|
||||
salePrice: numeric("sale_price"),
|
||||
brandPageLink: text("brand_page_link"),
|
||||
brandLogoImage: text("brand_logo_image"),
|
||||
productPageViewTracking: text("product_page_view_tracking"),
|
||||
variantsXml: text("variants_xml"),
|
||||
mediumImageUrl: text("medium_image_url"),
|
||||
productContentWidget: text("product_content_widget"),
|
||||
googleCategorization: text("google_categorization"),
|
||||
itemBasedCommission: text("item_based_commission"),
|
||||
uuid: uuid().defaultRandom(),
|
||||
});
|
||||
|
||||
export const compartment = pgTable("compartment", {
|
||||
id: uuid().defaultRandom().primaryKey().notNull(),
|
||||
name: varchar({ length: 100 }).notNull(),
|
||||
description: varchar({ length: 300 }),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
});
|
||||
|
||||
export const builds = pgTable("builds", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "build_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
accountId: integer("account_id").notNull(),
|
||||
name: varchar({ length: 255 }).notNull(),
|
||||
description: text(),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
}, (table) => {
|
||||
return {
|
||||
buildsUuidUnique: unique("builds_uuid_unique").on(table.uuid),
|
||||
}
|
||||
});
|
||||
|
||||
export const bb_products = pgTable("bb_products", {
|
||||
uuid: uuid().defaultRandom().primaryKey().notNull(),
|
||||
upc: varchar("UPC", { length: 100 }),
|
||||
sku: varchar("SKU", { length: 50 }),
|
||||
manufacturerId: varchar("MANUFACTURER_ID", { length: 50 }),
|
||||
brandName: varchar("BRAND_NAME", { length: 50 }),
|
||||
productName: varchar("PRODUCT_NAME", { length: 255 }),
|
||||
longDescription: text("LONG_DESCRIPTION"),
|
||||
shortDescription: varchar("SHORT_DESCRIPTION", { length: 500 }),
|
||||
department: varchar("DEPARTMENT", { length: 100 }),
|
||||
category: varchar("CATEGORY", { length: 100 }),
|
||||
subcategory: varchar("SUBCATEGORY", { length: 100 }),
|
||||
thumbUrl: varchar("THUMB_URL", { length: 500 }),
|
||||
imageUrl: varchar("IMAGE_URL", { length: 500 }),
|
||||
buyLink: varchar("BUY_LINK", { length: 500 }),
|
||||
keywords: varchar("KEYWORDS", { length: 500 }),
|
||||
reviews: varchar("REVIEWS", { length: 500 }),
|
||||
retailPrice: varchar("RETAIL_PRICE", { length: 50 }),
|
||||
salePrice: varchar("SALE_PRICE", { length: 50 }),
|
||||
brandPageLink: varchar("BRAND_PAGE_LINK", { length: 500 }),
|
||||
brandLogoImage: varchar("BRAND_LOGO_IMAGE", { length: 500 }),
|
||||
productPageViewTracking: varchar("PRODUCT_PAGE_VIEW_TRACKING", { length: 500 }),
|
||||
parentGroupId: varchar("PARENT_GROUP_ID", { length: 200 }),
|
||||
fineline: varchar("FINELINE", { length: 200 }),
|
||||
superfineline: varchar("SUPERFINELINE", { length: 200 }),
|
||||
modelnumber: varchar("MODELNUMBER", { length: 100 }),
|
||||
caliber: varchar("CALIBER", { length: 200 }),
|
||||
mediumImageUrl: varchar("MEDIUM_IMAGE_URL", { length: 500 }),
|
||||
productContentWidget: varchar("PRODUCT_CONTENT_WIDGET", { length: 500 }),
|
||||
googleCategorization: varchar("GOOGLE_CATEGORIZATION", { length: 500 }),
|
||||
itemBasedCommission: varchar("ITEM_BASED_COMMISSION", { length: 500 }),
|
||||
itemBasedCommissionRate: varchar("ITEM_BASED_COMMISSION RATE", { length: 50 }),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
});
|
||||
|
||||
export const psa_old = pgTable("psa_old", {
|
||||
sku: varchar("SKU", { length: 50 }),
|
||||
manufacturerId: varchar("MANUFACTURER_ID", { length: 50 }),
|
||||
brandName: varchar("BRAND_NAME", { length: 50 }),
|
||||
productName: varchar("PRODUCT_NAME", { length: 255 }),
|
||||
longDescription: text("LONG_DESCRIPTION"),
|
||||
shortDescription: varchar("SHORT_DESCRIPTION", { length: 50 }),
|
||||
department: varchar("DEPARTMENT", { length: 50 }),
|
||||
category: varchar("CATEGORY", { length: 50 }),
|
||||
subcategory: varchar("SUBCATEGORY", { length: 50 }),
|
||||
thumbUrl: varchar("THUMB_URL", { length: 50 }),
|
||||
imageUrl: varchar("IMAGE_URL", { length: 50 }),
|
||||
buyLink: varchar("BUY_LINK", { length: 128 }),
|
||||
keywords: varchar("KEYWORDS", { length: 50 }),
|
||||
reviews: varchar("REVIEWS", { length: 50 }),
|
||||
retailPrice: real("RETAIL_PRICE"),
|
||||
salePrice: real("SALE_PRICE"),
|
||||
brandPageLink: varchar("BRAND_PAGE_LINK", { length: 50 }),
|
||||
brandLogoImage: varchar("BRAND_LOGO_IMAGE", { length: 50 }),
|
||||
productPageViewTracking: varchar("PRODUCT_PAGE_VIEW_TRACKING", { length: 256 }),
|
||||
parentGroupId: varchar("PARENT_GROUP_ID", { length: 50 }),
|
||||
fineline: varchar("FINELINE", { length: 50 }),
|
||||
superfineline: varchar("SUPERFINELINE", { length: 200 }),
|
||||
modelnumber: varchar("MODELNUMBER", { length: 50 }),
|
||||
caliber: varchar("CALIBER", { length: 200 }),
|
||||
upc: varchar("UPC", { length: 100 }),
|
||||
mediumImageUrl: varchar("MEDIUM_IMAGE_URL", { length: 50 }),
|
||||
productContentWidget: varchar("PRODUCT_CONTENT_WIDGET", { length: 256 }),
|
||||
googleCategorization: varchar("GOOGLE_CATEGORIZATION", { length: 50 }),
|
||||
itemBasedCommission: varchar("ITEM_BASED_COMMISSION", { length: 50 }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
});
|
||||
export const psa = pgTable("psa", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "psa_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
sku: varchar("SKU", { length: 50 }),
|
||||
manufacturerId: varchar("MANUFACTURER_ID", { length: 50 }),
|
||||
brandName: varchar("BRAND_NAME", { length: 50 }),
|
||||
productName: varchar("PRODUCT_NAME", { length: 255 }),
|
||||
longDescription: text("LONG_DESCRIPTION"),
|
||||
shortDescription: varchar("SHORT_DESCRIPTION", { length: 50 }),
|
||||
department: varchar("DEPARTMENT", { length: 50 }),
|
||||
category: varchar("CATEGORY", { length: 50 }),
|
||||
subcategory: varchar("SUBCATEGORY", { length: 50 }),
|
||||
thumbUrl: varchar("THUMB_URL", { length: 50 }),
|
||||
imageUrl: varchar("IMAGE_URL", { length: 50 }),
|
||||
buyLink: varchar("BUY_LINK", { length: 128 }),
|
||||
keywords: varchar("KEYWORDS", { length: 50 }),
|
||||
reviews: varchar("REVIEWS", { length: 50 }),
|
||||
retailPrice: real("RETAIL_PRICE"),
|
||||
salePrice: real("SALE_PRICE"),
|
||||
brandPageLink: varchar("BRAND_PAGE_LINK", { length: 50 }),
|
||||
brandLogoImage: varchar("BRAND_LOGO_IMAGE", { length: 50 }),
|
||||
productPageViewTracking: varchar("PRODUCT_PAGE_VIEW_TRACKING", { length: 256 }),
|
||||
parentGroupId: varchar("PARENT_GROUP_ID", { length: 50 }),
|
||||
fineline: varchar("FINELINE", { length: 50 }),
|
||||
superfineline: varchar("SUPERFINELINE", { length: 200 }),
|
||||
modelnumber: varchar("MODELNUMBER", { length: 50 }),
|
||||
caliber: varchar("CALIBER", { length: 200 }),
|
||||
upc: varchar("UPC", { length: 100 }),
|
||||
mediumImageUrl: varchar("MEDIUM_IMAGE_URL", { length: 50 }),
|
||||
productContentWidget: varchar("PRODUCT_CONTENT_WIDGET", { length: 256 }),
|
||||
googleCategorization: varchar("GOOGLE_CATEGORIZATION", { length: 50 }),
|
||||
itemBasedCommission: varchar("ITEM_BASED_COMMISSION", { length: 50 }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
});
|
||||
|
||||
export const lipseycatalog = pgTable("lipseycatalog", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "lipseycatalog_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
itemno: varchar({ length: 20 }).notNull(),
|
||||
description1: text(),
|
||||
description2: text(),
|
||||
upc: varchar({ length: 20 }),
|
||||
manufacturermodelno: varchar({ length: 30 }),
|
||||
msrp: doublePrecision(),
|
||||
model: text(),
|
||||
calibergauge: text(),
|
||||
manufacturer: text(),
|
||||
type: text(),
|
||||
action: text(),
|
||||
barrellength: text(),
|
||||
capacity: text(),
|
||||
finish: text(),
|
||||
overalllength: text(),
|
||||
receiver: text(),
|
||||
safety: text(),
|
||||
sights: text(),
|
||||
stockframegrips: text(),
|
||||
magazine: text(),
|
||||
weight: text(),
|
||||
imagename: text(),
|
||||
chamber: text(),
|
||||
drilledandtapped: text(),
|
||||
rateoftwist: text(),
|
||||
itemtype: text(),
|
||||
additionalfeature1: text(),
|
||||
additionalfeature2: text(),
|
||||
additionalfeature3: text(),
|
||||
shippingweight: text(),
|
||||
boundbookmanufacturer: text(),
|
||||
boundbookmodel: text(),
|
||||
boundbooktype: text(),
|
||||
nfathreadpattern: text(),
|
||||
nfaattachmentmethod: text(),
|
||||
nfabaffletype: text(),
|
||||
silencercanbedisassembled: text(),
|
||||
silencerconstructionmaterial: text(),
|
||||
nfadbreduction: text(),
|
||||
silenceroutsidediameter: text(),
|
||||
nfaform3Caliber: text(),
|
||||
opticmagnification: text(),
|
||||
maintubesize: text(),
|
||||
adjustableobjective: text(),
|
||||
objectivesize: text(),
|
||||
opticadjustments: text(),
|
||||
illuminatedreticle: text(),
|
||||
reticle: text(),
|
||||
exclusive: text(),
|
||||
quantity: varchar({ length: 10 }).default(sql`NULL`),
|
||||
allocated: text(),
|
||||
onsale: text(),
|
||||
price: doublePrecision(),
|
||||
currentprice: doublePrecision(),
|
||||
retailmap: doublePrecision(),
|
||||
fflrequired: text(),
|
||||
sotrequired: text(),
|
||||
exclusivetype: text(),
|
||||
scopecoverincluded: text(),
|
||||
special: text(),
|
||||
sightstype: text(),
|
||||
case: text(),
|
||||
choke: text(),
|
||||
dbreduction: text(),
|
||||
family: text(),
|
||||
finishtype: text(),
|
||||
frame: text(),
|
||||
griptype: varchar({ length: 30 }),
|
||||
handgunslidematerial: text(),
|
||||
countryoforigin: varchar({ length: 4 }),
|
||||
itemlength: text(),
|
||||
itemwidth: text(),
|
||||
itemheight: text(),
|
||||
packagelength: doublePrecision(),
|
||||
packagewidth: doublePrecision(),
|
||||
packageheight: doublePrecision(),
|
||||
itemgroup: varchar({ length: 40 }),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
});
|
||||
|
||||
export const buildsComponents = pgTable("builds_components", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "build_components_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
buildId: integer("build_id").notNull(),
|
||||
productId: integer("product_id").notNull(),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
}, (table) => {
|
||||
return {
|
||||
buildsComponentsUuidUnique: unique("builds_components_uuid_unique").on(table.uuid),
|
||||
}
|
||||
});
|
||||
|
||||
export const balResellers = pgTable("bal_resellers", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "resellers_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
name: varchar({ length: 100 }).notNull(),
|
||||
websiteUrl: varchar("website_url", { length: 255 }),
|
||||
contactEmail: varchar("contact_email", { length: 100 }),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
}, (table) => {
|
||||
return {
|
||||
balResellersUuidUnique: unique("bal_resellers_uuid_unique").on(table.uuid),
|
||||
}
|
||||
});
|
||||
|
||||
export const verificationTokens = pgTable("verificationTokens", {
|
||||
identifier: varchar("identifier").notNull(),
|
||||
token: varchar("token").notNull(),
|
||||
expires: timestamp("expires").notNull(),
|
||||
});
|
||||
|
||||
export const authenticator = pgTable("authenticator", {
|
||||
credentialId: text().notNull(),
|
||||
userId: text().notNull(),
|
||||
providerAccountId: text().notNull(),
|
||||
credentialPublicKey: text().notNull(),
|
||||
counter: integer().notNull(),
|
||||
credentialDeviceType: text().notNull(),
|
||||
credentialBackedUp: boolean().notNull(),
|
||||
transports: text(),
|
||||
}, (table) => {
|
||||
return {
|
||||
authenticatorUserIdCredentialIdPk: primaryKey({ columns: [table.credentialId, table.userId], name: "authenticator_userId_credentialID_pk"}),
|
||||
authenticatorCredentialIdUnique: unique("authenticator_credentialID_unique").on(table.credentialId),
|
||||
}
|
||||
});
|
||||
|
||||
export const accounts = pgTable("accounts", {
|
||||
id: uuid("id").primaryKey().defaultRandom(),
|
||||
uuid: uuid("uuid").defaultRandom(),
|
||||
userId: uuid("user_id").notNull(),
|
||||
type: varchar("type").notNull(),
|
||||
provider: text().notNull(),
|
||||
providerAccountId: varchar("provider_account_id").notNull(),
|
||||
refreshToken: text("refresh_token"),
|
||||
accessToken: text("access_token"),
|
||||
expiresAt: integer("expires_at"),
|
||||
tokenType: varchar("token_type"),
|
||||
idToken: text("id_token"),
|
||||
sessionState: varchar("session_state"),
|
||||
scope: text(),
|
||||
}
|
||||
);
|
||||
|
||||
/* export const vw_accounts = pgView("vw_accounts", {
|
||||
uuid: uuid().defaultRandom(),
|
||||
userId: text("user_id").notNull(),
|
||||
type: text().notNull(),
|
||||
provider: text().notNull(),
|
||||
providerAccountId: text("provider_account_id").notNull(),
|
||||
refreshToken: text("refresh_token"),
|
||||
accessToken: text("access_token"),
|
||||
expiresAt: integer("expires_at"),
|
||||
tokenType: text("token_type"),
|
||||
scope: text(),
|
||||
idToken: text("id_token"),
|
||||
sessionState: text("session_state"),
|
||||
first_name: text("first_name"),
|
||||
last_name: text("last_name"),
|
||||
|
||||
},) */
|
||||
|
||||
/* From here down is the authentication library Lusia tables */
|
||||
|
||||
export const users = pgTable("user",
|
||||
{
|
||||
id: varchar("id", { length: 21 }).primaryKey(),
|
||||
name: varchar("name"),
|
||||
username: varchar({ length: 50 }),
|
||||
discordId: varchar("discord_id", { length: 255 }).unique(),
|
||||
email: varchar("email", { length: 255 }).unique().notNull(),
|
||||
emailVerified: boolean("email_verified").default(false).notNull(),
|
||||
hashedPassword: varchar("hashed_password", { length: 255 }),
|
||||
first_name: varchar("first_name", { length: 50 }),
|
||||
last_name: varchar("last_name", { length: 50 }),
|
||||
full_name: varchar("full_name", { length: 50 }),
|
||||
profilePicture: varchar("profile_picture", { length: 255 }),
|
||||
image: text("image"),
|
||||
dateOfBirth: date("date_of_birth"),
|
||||
phoneNumber: varchar("phone_number", { length: 20 }),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).default(sql`CURRENT_TIMESTAMP`),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).default(sql`CURRENT_TIMESTAMP`),
|
||||
isAdmin: boolean("is_admin").default(false),
|
||||
lastLogin: timestamp("last_login", { mode: 'string' }),
|
||||
buildPrivacySetting: text("build_privacy_setting").default('public'),
|
||||
uuid: uuid().defaultRandom(),
|
||||
avatar: varchar("avatar", { length: 255 }),
|
||||
stripeSubscriptionId: varchar("stripe_subscription_id", { length: 191 }),
|
||||
stripePriceId: varchar("stripe_price_id", { length: 191 }),
|
||||
stripeCustomerId: varchar("stripe_customer_id", { length: 191 }),
|
||||
stripeCurrentPeriodEnd: timestamp("stripe_current_period_end"),
|
||||
}, (table) => ({
|
||||
usersUsernameKey: unique("users_username_key").on(table.username),
|
||||
usersEmailKey: unique("users_email_key").on(table.email),
|
||||
usersBuildPrivacySettingCheck: check("users_build_privacy_setting_check", sql`build_privacy_setting = ANY (ARRAY['private'::text, 'public'::text])`),
|
||||
emailIdx: index("user_email_idx").on(table.email),
|
||||
discordIdx: index("user_discord_idx").on(table.discordId),
|
||||
}),
|
||||
);
|
||||
export type User = typeof users.$inferSelect;
|
||||
export type NewUser = typeof users.$inferInsert;
|
||||
|
||||
export const session = pgTable(
|
||||
"session",
|
||||
{
|
||||
sessionToken: varchar("sessionToken", { length: 255 }).primaryKey(),
|
||||
userId: varchar("userId", { length: 21 }).notNull(),
|
||||
expires: timestamp("expires", { withTimezone: true, mode: "date" }).notNull(),
|
||||
}
|
||||
);
|
||||
|
||||
export const emailVerificationCodes = pgTable(
|
||||
"email_verification_codes",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
userId: varchar("user_id", { length: 21 }).unique().notNull(),
|
||||
email: varchar("email", { length: 255 }).notNull(),
|
||||
code: varchar("code", { length: 8 }).notNull(),
|
||||
expiresAt: timestamp("expires_at", { withTimezone: true, mode: "date" }).notNull(),
|
||||
},
|
||||
(t) => ({
|
||||
userIdx: index("verification_code_user_idx").on(t.userId),
|
||||
emailIdx: index("verification_code_email_idx").on(t.email),
|
||||
}),
|
||||
);
|
||||
|
||||
export const passwordResetTokens = pgTable(
|
||||
"password_reset_tokens",
|
||||
{
|
||||
id: varchar("id", { length: 40 }).primaryKey(),
|
||||
userId: varchar("user_id", { length: 21 }).notNull(),
|
||||
expiresAt: timestamp("expires_at", { withTimezone: true, mode: "date" }).notNull(),
|
||||
},
|
||||
(t) => ({
|
||||
userIdx: index("password_token_user_idx").on(t.userId),
|
||||
}),
|
||||
);
|
||||
|
||||
export const posts = pgTable(
|
||||
"posts",
|
||||
{
|
||||
id: varchar("id", { length: 15 }).primaryKey(),
|
||||
userId: varchar("user_id", { length: 255 }).notNull(),
|
||||
title: varchar("title", { length: 255 }).notNull(),
|
||||
excerpt: varchar("excerpt", { length: 255 }).notNull(),
|
||||
content: text("content").notNull(),
|
||||
status: varchar("status", { length: 10, enum: ["draft", "published"] })
|
||||
.default("draft")
|
||||
.notNull(),
|
||||
tags: varchar("tags", { length: 255 }),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at", { mode: "date" }).$onUpdate(() => new Date()),
|
||||
},
|
||||
(t) => ({
|
||||
userIdx: index("post_user_idx").on(t.userId),
|
||||
createdAtIdx: index("post_created_at_idx").on(t.createdAt),
|
||||
}),
|
||||
);
|
||||
|
||||
export const postRelations = relations(posts, ({ one }) => ({
|
||||
user: one(users, {
|
||||
fields: [posts.userId],
|
||||
references: [users.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export type Post = typeof posts.$inferSelect;
|
||||
export type NewPost = typeof posts.$inferInsert;
|
||||
|
||||
export const vwUserSessions = pgView("vw_user_sessions", { id: varchar({ length: 255 }),
|
||||
userId: varchar("user_id", { length: 21 }),
|
||||
uId: varchar("u_id", { length: 21 }),
|
||||
uEmail: varchar("u_email", { length: 255 }),
|
||||
expiresAt: timestamp("expires_at", { withTimezone: true, mode: 'string' }),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }),
|
||||
}).existing();
|
||||
//as(sql`SELECT s.id, s.user_id, u.id AS u_id, u.email AS u_email, s.expires_at, s.created_at, s.updated_at FROM sessions s, users u WHERE s.user_id::text = u.id::text`);
|
||||
|
||||
// Default Drizzle File
|
||||
|
||||
// import { pgTable, serial, text, integer, timestamp } from "drizzle-orm/pg-core";
|
||||
|
||||
// export const products = pgTable("products", {
|
||||
// id: serial("id").primaryKey(),
|
||||
// name: text("name").notNull(),
|
||||
// description: text("description"),
|
||||
// price: integer("price"),
|
||||
// createdAt: timestamp("created_at").defaultNow(),
|
||||
// // Add more fields as needed
|
||||
// });
|
||||
|
||||
export const affiliateCategoryMap = pgTable("affiliate_category_map", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "affiliate_category_map_id_seq", startWith: 1, increment: 1 }),
|
||||
feedname: varchar("feedname", { length: 100 }).notNull(),
|
||||
affiliatecategory: varchar("affiliatecategory", { length: 255 }).notNull(),
|
||||
buildercategoryid: integer("buildercategoryid").notNull(),
|
||||
notes: varchar("notes", { length: 255 }),
|
||||
});
|
||||
|
||||
export const product_categories = pgTable("product_categories", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "product_categories_id_seq", startWith: 1, increment: 1 }),
|
||||
name: varchar({ length: 100 }).notNull(),
|
||||
parent_category_id: integer("parent_category_id"),
|
||||
type: varchar({ length: 50 }),
|
||||
sort_order: integer("sort_order"),
|
||||
created_at: timestamp("created_at", { mode: 'string' }).defaultNow(),
|
||||
updated_at: timestamp("updated_at", { mode: 'string' }).defaultNow(),
|
||||
});
|
||||
661
src/db/schema.ts
661
src/db/schema.ts
@@ -1,571 +1,108 @@
|
||||
import { pgTableCreator, integer, varchar, text, numeric, timestamp, unique, check, date, boolean, uuid, bigint, real, doublePrecision, primaryKey, pgView, index, serial } from "drizzle-orm/pg-core";
|
||||
import { relations, sql } from "drizzle-orm";
|
||||
import { DATABASE_PREFIX as prefix } from "@/lib/constants";
|
||||
import { pgTable, foreignKey, serial, varchar, integer, doublePrecision, timestamp, unique, text, numeric, boolean, jsonb } from "drizzle-orm/pg-core"
|
||||
import { sql } from "drizzle-orm"
|
||||
|
||||
export const pgTable = pgTableCreator((name) => (prefix == "" || prefix == null) ? name: `${prefix}_${name}`);
|
||||
///
|
||||
export const products = pgTable("products", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "products_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
name: varchar({ length: 255 }).notNull(),
|
||||
description: text().notNull(),
|
||||
price: numeric().notNull(),
|
||||
resellerId: integer("reseller_id").notNull(),
|
||||
categoryId: integer("category_id").notNull(),
|
||||
stockQty: integer("stock_qty").default(0),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
});
|
||||
|
||||
|
||||
export const productCategoryMappings = pgTable("product_category_mappings", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
feedName: varchar("feed_name", { length: 255 }),
|
||||
feedCategoryValue: varchar("feed_category_value", { length: 255 }),
|
||||
canonicalCategoryId: integer("canonical_category_id"),
|
||||
confidenceScore: doublePrecision("confidence_score"),
|
||||
lastReviewedBy: varchar("last_reviewed_by", { length: 255 }),
|
||||
lastReviewedAt: timestamp("last_reviewed_at", { mode: 'string' }),
|
||||
}, (table) => [
|
||||
foreignKey({
|
||||
columns: [table.canonicalCategoryId],
|
||||
foreignColumns: [categories.id],
|
||||
name: "product_category_mappings_canonical_category_id_fkey"
|
||||
}),
|
||||
]);
|
||||
|
||||
export const categories = pgTable("categories", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "categories_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
name: varchar({ length: 100 }).notNull(),
|
||||
parentCategoryId: integer("parent_category_id"),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
});
|
||||
|
||||
export const productFeeds = pgTable("product_feeds", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "productfeeds_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
resellerId: integer("reseller_id").notNull(),
|
||||
feedUrl: varchar("feed_url", { length: 255 }).notNull(),
|
||||
lastUpdate: timestamp("last_update", { mode: 'string' }),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
}, (table) => {
|
||||
return {
|
||||
productFeedsUuidUnique: unique("product_feeds_uuid_unique").on(table.uuid),
|
||||
}
|
||||
});
|
||||
|
||||
export const userActivityLog = pgTable("user_activity_log", {
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
id: bigint({ mode: "number" }).primaryKey().generatedAlwaysAsIdentity({ name: "user_activity_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
userId: bigint("user_id", { mode: "number" }).notNull(),
|
||||
activity: text().notNull(),
|
||||
timestamp: timestamp({ mode: 'string' }).default(sql`CURRENT_TIMESTAMP`),
|
||||
});
|
||||
|
||||
export const brands = pgTable("brands", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "brands_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
name: varchar({ length: 100 }).notNull(),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
}, (table) => {
|
||||
return {
|
||||
brandsUuidUnique: unique("brands_uuid_unique").on(table.uuid),
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export const manufacturer = pgTable("manufacturer", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "manufacturer_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
name: varchar({ length: 100 }).notNull(),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
}, (table) => {
|
||||
return {
|
||||
manufacturerUuidUnique: unique("manufacturer_uuid_unique").on(table.uuid),
|
||||
}
|
||||
});
|
||||
|
||||
export const states = pgTable("states", {
|
||||
id: integer().primaryKey().generatedByDefaultAsIdentity({ name: "states_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
state: varchar({ length: 50 }),
|
||||
abbreviation: varchar({ length: 50 }),
|
||||
});
|
||||
|
||||
export const componentType = pgTable("component_type", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "component_type_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
name: varchar({ length: 100 }).notNull(),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
}, (table) => {
|
||||
return {
|
||||
componentTypeUuidUnique: unique("component_type_uuid_unique").on(table.uuid),
|
||||
}
|
||||
});
|
||||
|
||||
export const aeroPrecision = pgTable("aero_precision", {
|
||||
sku: text().primaryKey().notNull(),
|
||||
manufacturerId: text("manufacturer_id"),
|
||||
brandName: text("brand_name"),
|
||||
productName: text("product_name"),
|
||||
longDescription: text("long_description"),
|
||||
shortDescription: text("short_description"),
|
||||
department: text(),
|
||||
category: text(),
|
||||
subcategory: text(),
|
||||
thumbUrl: text("thumb_url"),
|
||||
imageUrl: text("image_url"),
|
||||
buyLink: text("buy_link"),
|
||||
keywords: text(),
|
||||
reviews: text(),
|
||||
retailPrice: numeric("retail_price"),
|
||||
salePrice: numeric("sale_price"),
|
||||
brandPageLink: text("brand_page_link"),
|
||||
brandLogoImage: text("brand_logo_image"),
|
||||
productPageViewTracking: text("product_page_view_tracking"),
|
||||
variantsXml: text("variants_xml"),
|
||||
mediumImageUrl: text("medium_image_url"),
|
||||
productContentWidget: text("product_content_widget"),
|
||||
googleCategorization: text("google_categorization"),
|
||||
itemBasedCommission: text("item_based_commission"),
|
||||
uuid: uuid().defaultRandom(),
|
||||
});
|
||||
|
||||
export const compartment = pgTable("compartment", {
|
||||
id: uuid().defaultRandom().primaryKey().notNull(),
|
||||
name: varchar({ length: 100 }).notNull(),
|
||||
description: varchar({ length: 300 }),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
});
|
||||
|
||||
export const builds = pgTable("builds", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "build_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
accountId: integer("account_id").notNull(),
|
||||
id: serial().primaryKey().notNull(),
|
||||
name: varchar({ length: 255 }).notNull(),
|
||||
parentId: integer("parent_id"),
|
||||
slug: varchar({ length: 255 }).notNull(),
|
||||
}, (table) => [
|
||||
foreignKey({
|
||||
columns: [table.parentId],
|
||||
foreignColumns: [table.id],
|
||||
name: "categories_parent_id_fkey"
|
||||
}),
|
||||
unique("categories_slug_key").on(table.slug),
|
||||
]);
|
||||
|
||||
export const products = pgTable("products", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
name: varchar({ length: 255 }).notNull(),
|
||||
brand: varchar({ length: 255 }),
|
||||
description: text(),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
}, (table) => {
|
||||
return {
|
||||
buildsUuidUnique: unique("builds_uuid_unique").on(table.uuid),
|
||||
}
|
||||
});
|
||||
upc: varchar({ length: 32 }),
|
||||
mpn: varchar({ length: 64 }),
|
||||
canonicalCategoryId: integer("canonical_category_id"),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow(),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow(),
|
||||
}, (table) => [
|
||||
foreignKey({
|
||||
columns: [table.canonicalCategoryId],
|
||||
foreignColumns: [categories.id],
|
||||
name: "products_canonical_category_id_fkey"
|
||||
}),
|
||||
]);
|
||||
|
||||
export const bb_products = pgTable("bb_products", {
|
||||
uuid: uuid().defaultRandom().primaryKey().notNull(),
|
||||
upc: varchar("UPC", { length: 100 }),
|
||||
sku: varchar("SKU", { length: 50 }),
|
||||
manufacturerId: varchar("MANUFACTURER_ID", { length: 50 }),
|
||||
brandName: varchar("BRAND_NAME", { length: 50 }),
|
||||
productName: varchar("PRODUCT_NAME", { length: 255 }),
|
||||
longDescription: text("LONG_DESCRIPTION"),
|
||||
shortDescription: varchar("SHORT_DESCRIPTION", { length: 500 }),
|
||||
department: varchar("DEPARTMENT", { length: 100 }),
|
||||
category: varchar("CATEGORY", { length: 100 }),
|
||||
subcategory: varchar("SUBCATEGORY", { length: 100 }),
|
||||
thumbUrl: varchar("THUMB_URL", { length: 500 }),
|
||||
imageUrl: varchar("IMAGE_URL", { length: 500 }),
|
||||
buyLink: varchar("BUY_LINK", { length: 500 }),
|
||||
keywords: varchar("KEYWORDS", { length: 500 }),
|
||||
reviews: varchar("REVIEWS", { length: 500 }),
|
||||
retailPrice: varchar("RETAIL_PRICE", { length: 50 }),
|
||||
salePrice: varchar("SALE_PRICE", { length: 50 }),
|
||||
brandPageLink: varchar("BRAND_PAGE_LINK", { length: 500 }),
|
||||
brandLogoImage: varchar("BRAND_LOGO_IMAGE", { length: 500 }),
|
||||
productPageViewTracking: varchar("PRODUCT_PAGE_VIEW_TRACKING", { length: 500 }),
|
||||
parentGroupId: varchar("PARENT_GROUP_ID", { length: 200 }),
|
||||
fineline: varchar("FINELINE", { length: 200 }),
|
||||
superfineline: varchar("SUPERFINELINE", { length: 200 }),
|
||||
modelnumber: varchar("MODELNUMBER", { length: 100 }),
|
||||
caliber: varchar("CALIBER", { length: 200 }),
|
||||
mediumImageUrl: varchar("MEDIUM_IMAGE_URL", { length: 500 }),
|
||||
productContentWidget: varchar("PRODUCT_CONTENT_WIDGET", { length: 500 }),
|
||||
googleCategorization: varchar("GOOGLE_CATEGORIZATION", { length: 500 }),
|
||||
itemBasedCommission: varchar("ITEM_BASED_COMMISSION", { length: 500 }),
|
||||
itemBasedCommissionRate: varchar("ITEM_BASED_COMMISSION RATE", { length: 50 }),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
});
|
||||
export const offers = pgTable("offers", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
productId: integer("product_id"),
|
||||
feedName: varchar("feed_name", { length: 255 }).notNull(),
|
||||
feedSku: varchar("feed_sku", { length: 255 }),
|
||||
price: numeric({ precision: 10, scale: 2 }),
|
||||
url: text(),
|
||||
inStock: boolean("in_stock"),
|
||||
vendor: varchar({ length: 255 }),
|
||||
lastSeenAt: timestamp("last_seen_at", { mode: 'string' }).defaultNow(),
|
||||
rawData: jsonb("raw_data"),
|
||||
}, (table) => [
|
||||
foreignKey({
|
||||
columns: [table.productId],
|
||||
foreignColumns: [products.id],
|
||||
name: "offers_product_id_fkey"
|
||||
}).onDelete("cascade"),
|
||||
unique("offers_product_id_feed_name_feed_sku_key").on(table.productId, table.feedName, table.feedSku),
|
||||
unique("offers_feed_unique").on(table.feedName, table.feedSku),
|
||||
]);
|
||||
|
||||
export const psa_old = pgTable("psa_old", {
|
||||
sku: varchar("SKU", { length: 50 }),
|
||||
manufacturerId: varchar("MANUFACTURER_ID", { length: 50 }),
|
||||
brandName: varchar("BRAND_NAME", { length: 50 }),
|
||||
productName: varchar("PRODUCT_NAME", { length: 255 }),
|
||||
longDescription: text("LONG_DESCRIPTION"),
|
||||
shortDescription: varchar("SHORT_DESCRIPTION", { length: 50 }),
|
||||
department: varchar("DEPARTMENT", { length: 50 }),
|
||||
category: varchar("CATEGORY", { length: 50 }),
|
||||
subcategory: varchar("SUBCATEGORY", { length: 50 }),
|
||||
thumbUrl: varchar("THUMB_URL", { length: 50 }),
|
||||
imageUrl: varchar("IMAGE_URL", { length: 50 }),
|
||||
buyLink: varchar("BUY_LINK", { length: 128 }),
|
||||
keywords: varchar("KEYWORDS", { length: 50 }),
|
||||
reviews: varchar("REVIEWS", { length: 50 }),
|
||||
retailPrice: real("RETAIL_PRICE"),
|
||||
salePrice: real("SALE_PRICE"),
|
||||
brandPageLink: varchar("BRAND_PAGE_LINK", { length: 50 }),
|
||||
brandLogoImage: varchar("BRAND_LOGO_IMAGE", { length: 50 }),
|
||||
productPageViewTracking: varchar("PRODUCT_PAGE_VIEW_TRACKING", { length: 256 }),
|
||||
parentGroupId: varchar("PARENT_GROUP_ID", { length: 50 }),
|
||||
fineline: varchar("FINELINE", { length: 50 }),
|
||||
superfineline: varchar("SUPERFINELINE", { length: 200 }),
|
||||
modelnumber: varchar("MODELNUMBER", { length: 50 }),
|
||||
caliber: varchar("CALIBER", { length: 200 }),
|
||||
upc: varchar("UPC", { length: 100 }),
|
||||
mediumImageUrl: varchar("MEDIUM_IMAGE_URL", { length: 50 }),
|
||||
productContentWidget: varchar("PRODUCT_CONTENT_WIDGET", { length: 256 }),
|
||||
googleCategorization: varchar("GOOGLE_CATEGORIZATION", { length: 50 }),
|
||||
itemBasedCommission: varchar("ITEM_BASED_COMMISSION", { length: 50 }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
});
|
||||
export const psa = pgTable("psa", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "psa_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
sku: varchar("SKU", { length: 50 }),
|
||||
manufacturerId: varchar("MANUFACTURER_ID", { length: 50 }),
|
||||
brandName: varchar("BRAND_NAME", { length: 50 }),
|
||||
productName: varchar("PRODUCT_NAME", { length: 255 }),
|
||||
longDescription: text("LONG_DESCRIPTION"),
|
||||
shortDescription: varchar("SHORT_DESCRIPTION", { length: 50 }),
|
||||
department: varchar("DEPARTMENT", { length: 50 }),
|
||||
category: varchar("CATEGORY", { length: 50 }),
|
||||
subcategory: varchar("SUBCATEGORY", { length: 50 }),
|
||||
thumbUrl: varchar("THUMB_URL", { length: 50 }),
|
||||
imageUrl: varchar("IMAGE_URL", { length: 50 }),
|
||||
buyLink: varchar("BUY_LINK", { length: 128 }),
|
||||
keywords: varchar("KEYWORDS", { length: 50 }),
|
||||
reviews: varchar("REVIEWS", { length: 50 }),
|
||||
retailPrice: real("RETAIL_PRICE"),
|
||||
salePrice: real("SALE_PRICE"),
|
||||
brandPageLink: varchar("BRAND_PAGE_LINK", { length: 50 }),
|
||||
brandLogoImage: varchar("BRAND_LOGO_IMAGE", { length: 50 }),
|
||||
productPageViewTracking: varchar("PRODUCT_PAGE_VIEW_TRACKING", { length: 256 }),
|
||||
parentGroupId: varchar("PARENT_GROUP_ID", { length: 50 }),
|
||||
fineline: varchar("FINELINE", { length: 50 }),
|
||||
superfineline: varchar("SUPERFINELINE", { length: 200 }),
|
||||
modelnumber: varchar("MODELNUMBER", { length: 50 }),
|
||||
caliber: varchar("CALIBER", { length: 200 }),
|
||||
upc: varchar("UPC", { length: 100 }),
|
||||
mediumImageUrl: varchar("MEDIUM_IMAGE_URL", { length: 50 }),
|
||||
productContentWidget: varchar("PRODUCT_CONTENT_WIDGET", { length: 256 }),
|
||||
googleCategorization: varchar("GOOGLE_CATEGORIZATION", { length: 50 }),
|
||||
itemBasedCommission: varchar("ITEM_BASED_COMMISSION", { length: 50 }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
});
|
||||
export const offerPriceHistory = pgTable("offer_price_history", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
offerId: integer("offer_id"),
|
||||
price: numeric({ precision: 10, scale: 2 }).notNull(),
|
||||
seenAt: timestamp("seen_at", { mode: 'string' }).defaultNow(),
|
||||
}, (table) => [
|
||||
foreignKey({
|
||||
columns: [table.offerId],
|
||||
foreignColumns: [offers.id],
|
||||
name: "offer_price_history_offer_id_fkey"
|
||||
}).onDelete("cascade"),
|
||||
]);
|
||||
|
||||
export const lipseycatalog = pgTable("lipseycatalog", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "lipseycatalog_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
itemno: varchar({ length: 20 }).notNull(),
|
||||
description1: text(),
|
||||
description2: text(),
|
||||
upc: varchar({ length: 20 }),
|
||||
manufacturermodelno: varchar({ length: 30 }),
|
||||
msrp: doublePrecision(),
|
||||
model: text(),
|
||||
calibergauge: text(),
|
||||
manufacturer: text(),
|
||||
type: text(),
|
||||
action: text(),
|
||||
barrellength: text(),
|
||||
capacity: text(),
|
||||
finish: text(),
|
||||
overalllength: text(),
|
||||
receiver: text(),
|
||||
safety: text(),
|
||||
sights: text(),
|
||||
stockframegrips: text(),
|
||||
magazine: text(),
|
||||
weight: text(),
|
||||
imagename: text(),
|
||||
chamber: text(),
|
||||
drilledandtapped: text(),
|
||||
rateoftwist: text(),
|
||||
itemtype: text(),
|
||||
additionalfeature1: text(),
|
||||
additionalfeature2: text(),
|
||||
additionalfeature3: text(),
|
||||
shippingweight: text(),
|
||||
boundbookmanufacturer: text(),
|
||||
boundbookmodel: text(),
|
||||
boundbooktype: text(),
|
||||
nfathreadpattern: text(),
|
||||
nfaattachmentmethod: text(),
|
||||
nfabaffletype: text(),
|
||||
silencercanbedisassembled: text(),
|
||||
silencerconstructionmaterial: text(),
|
||||
nfadbreduction: text(),
|
||||
silenceroutsidediameter: text(),
|
||||
nfaform3Caliber: text(),
|
||||
opticmagnification: text(),
|
||||
maintubesize: text(),
|
||||
adjustableobjective: text(),
|
||||
objectivesize: text(),
|
||||
opticadjustments: text(),
|
||||
illuminatedreticle: text(),
|
||||
reticle: text(),
|
||||
exclusive: text(),
|
||||
quantity: varchar({ length: 10 }).default(sql`NULL`),
|
||||
allocated: text(),
|
||||
onsale: text(),
|
||||
price: doublePrecision(),
|
||||
currentprice: doublePrecision(),
|
||||
retailmap: doublePrecision(),
|
||||
fflrequired: text(),
|
||||
sotrequired: text(),
|
||||
exclusivetype: text(),
|
||||
scopecoverincluded: text(),
|
||||
special: text(),
|
||||
sightstype: text(),
|
||||
case: text(),
|
||||
choke: text(),
|
||||
dbreduction: text(),
|
||||
family: text(),
|
||||
finishtype: text(),
|
||||
frame: text(),
|
||||
griptype: varchar({ length: 30 }),
|
||||
handgunslidematerial: text(),
|
||||
countryoforigin: varchar({ length: 4 }),
|
||||
itemlength: text(),
|
||||
itemwidth: text(),
|
||||
itemheight: text(),
|
||||
packagelength: doublePrecision(),
|
||||
packagewidth: doublePrecision(),
|
||||
packageheight: doublePrecision(),
|
||||
itemgroup: varchar({ length: 40 }),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
});
|
||||
export const feeds = pgTable("feeds", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
name: varchar({ length: 255 }).notNull(),
|
||||
url: text(),
|
||||
lastImportedAt: timestamp("last_imported_at", { mode: 'string' }),
|
||||
}, (table) => [
|
||||
unique("feeds_name_key").on(table.name),
|
||||
]);
|
||||
|
||||
export const buildsComponents = pgTable("builds_components", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "build_components_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
buildId: integer("build_id").notNull(),
|
||||
productId: integer("product_id").notNull(),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
}, (table) => {
|
||||
return {
|
||||
buildsComponentsUuidUnique: unique("builds_components_uuid_unique").on(table.uuid),
|
||||
}
|
||||
});
|
||||
|
||||
export const balResellers = pgTable("bal_resellers", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "resellers_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
|
||||
name: varchar({ length: 100 }).notNull(),
|
||||
websiteUrl: varchar("website_url", { length: 255 }),
|
||||
contactEmail: varchar("contact_email", { length: 100 }),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
|
||||
deletedAt: timestamp("deleted_at", { mode: 'string' }),
|
||||
uuid: uuid().defaultRandom(),
|
||||
}, (table) => {
|
||||
return {
|
||||
balResellersUuidUnique: unique("bal_resellers_uuid_unique").on(table.uuid),
|
||||
}
|
||||
});
|
||||
|
||||
export const verificationTokens = pgTable("verificationTokens", {
|
||||
identifier: varchar("identifier").notNull(),
|
||||
token: varchar("token").notNull(),
|
||||
expires: timestamp("expires").notNull(),
|
||||
});
|
||||
|
||||
export const authenticator = pgTable("authenticator", {
|
||||
credentialId: text().notNull(),
|
||||
userId: text().notNull(),
|
||||
providerAccountId: text().notNull(),
|
||||
credentialPublicKey: text().notNull(),
|
||||
counter: integer().notNull(),
|
||||
credentialDeviceType: text().notNull(),
|
||||
credentialBackedUp: boolean().notNull(),
|
||||
transports: text(),
|
||||
}, (table) => {
|
||||
return {
|
||||
authenticatorUserIdCredentialIdPk: primaryKey({ columns: [table.credentialId, table.userId], name: "authenticator_userId_credentialID_pk"}),
|
||||
authenticatorCredentialIdUnique: unique("authenticator_credentialID_unique").on(table.credentialId),
|
||||
}
|
||||
});
|
||||
|
||||
export const accounts = pgTable("accounts", {
|
||||
id: uuid("id").primaryKey().defaultRandom(),
|
||||
uuid: uuid("uuid").defaultRandom(),
|
||||
userId: uuid("user_id").notNull(),
|
||||
type: varchar("type").notNull(),
|
||||
provider: text().notNull(),
|
||||
providerAccountId: varchar("provider_account_id").notNull(),
|
||||
refreshToken: text("refresh_token"),
|
||||
accessToken: text("access_token"),
|
||||
expiresAt: integer("expires_at"),
|
||||
tokenType: varchar("token_type"),
|
||||
idToken: text("id_token"),
|
||||
sessionState: varchar("session_state"),
|
||||
scope: text(),
|
||||
}
|
||||
);
|
||||
|
||||
/* export const vw_accounts = pgView("vw_accounts", {
|
||||
uuid: uuid().defaultRandom(),
|
||||
userId: text("user_id").notNull(),
|
||||
type: text().notNull(),
|
||||
provider: text().notNull(),
|
||||
providerAccountId: text("provider_account_id").notNull(),
|
||||
refreshToken: text("refresh_token"),
|
||||
accessToken: text("access_token"),
|
||||
expiresAt: integer("expires_at"),
|
||||
tokenType: text("token_type"),
|
||||
scope: text(),
|
||||
idToken: text("id_token"),
|
||||
sessionState: text("session_state"),
|
||||
first_name: text("first_name"),
|
||||
last_name: text("last_name"),
|
||||
|
||||
},) */
|
||||
|
||||
/* From here down is the authentication library Lusia tables */
|
||||
|
||||
export const users = pgTable("user",
|
||||
{
|
||||
id: varchar("id", { length: 21 }).primaryKey(),
|
||||
name: varchar("name"),
|
||||
username: varchar({ length: 50 }),
|
||||
discordId: varchar("discord_id", { length: 255 }).unique(),
|
||||
email: varchar("email", { length: 255 }).unique().notNull(),
|
||||
emailVerified: boolean("email_verified").default(false).notNull(),
|
||||
hashedPassword: varchar("hashed_password", { length: 255 }),
|
||||
first_name: varchar("first_name", { length: 50 }),
|
||||
last_name: varchar("last_name", { length: 50 }),
|
||||
full_name: varchar("full_name", { length: 50 }),
|
||||
profilePicture: varchar("profile_picture", { length: 255 }),
|
||||
image: text("image"),
|
||||
dateOfBirth: date("date_of_birth"),
|
||||
phoneNumber: varchar("phone_number", { length: 20 }),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }).default(sql`CURRENT_TIMESTAMP`),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }).default(sql`CURRENT_TIMESTAMP`),
|
||||
isAdmin: boolean("is_admin").default(false),
|
||||
lastLogin: timestamp("last_login", { mode: 'string' }),
|
||||
buildPrivacySetting: text("build_privacy_setting").default('public'),
|
||||
uuid: uuid().defaultRandom(),
|
||||
avatar: varchar("avatar", { length: 255 }),
|
||||
stripeSubscriptionId: varchar("stripe_subscription_id", { length: 191 }),
|
||||
stripePriceId: varchar("stripe_price_id", { length: 191 }),
|
||||
stripeCustomerId: varchar("stripe_customer_id", { length: 191 }),
|
||||
stripeCurrentPeriodEnd: timestamp("stripe_current_period_end"),
|
||||
}, (table) => ({
|
||||
usersUsernameKey: unique("users_username_key").on(table.username),
|
||||
usersEmailKey: unique("users_email_key").on(table.email),
|
||||
usersBuildPrivacySettingCheck: check("users_build_privacy_setting_check", sql`build_privacy_setting = ANY (ARRAY['private'::text, 'public'::text])`),
|
||||
emailIdx: index("user_email_idx").on(table.email),
|
||||
discordIdx: index("user_discord_idx").on(table.discordId),
|
||||
}),
|
||||
);
|
||||
export type User = typeof users.$inferSelect;
|
||||
export type NewUser = typeof users.$inferInsert;
|
||||
|
||||
export const session = pgTable(
|
||||
"session",
|
||||
{
|
||||
sessionToken: varchar("sessionToken", { length: 255 }).primaryKey(),
|
||||
userId: varchar("userId", { length: 21 }).notNull(),
|
||||
expires: timestamp("expires", { withTimezone: true, mode: "date" }).notNull(),
|
||||
}
|
||||
);
|
||||
|
||||
export const emailVerificationCodes = pgTable(
|
||||
"email_verification_codes",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
userId: varchar("user_id", { length: 21 }).unique().notNull(),
|
||||
email: varchar("email", { length: 255 }).notNull(),
|
||||
code: varchar("code", { length: 8 }).notNull(),
|
||||
expiresAt: timestamp("expires_at", { withTimezone: true, mode: "date" }).notNull(),
|
||||
},
|
||||
(t) => ({
|
||||
userIdx: index("verification_code_user_idx").on(t.userId),
|
||||
emailIdx: index("verification_code_email_idx").on(t.email),
|
||||
}),
|
||||
);
|
||||
|
||||
export const passwordResetTokens = pgTable(
|
||||
"password_reset_tokens",
|
||||
{
|
||||
id: varchar("id", { length: 40 }).primaryKey(),
|
||||
userId: varchar("user_id", { length: 21 }).notNull(),
|
||||
expiresAt: timestamp("expires_at", { withTimezone: true, mode: "date" }).notNull(),
|
||||
},
|
||||
(t) => ({
|
||||
userIdx: index("password_token_user_idx").on(t.userId),
|
||||
}),
|
||||
);
|
||||
|
||||
export const posts = pgTable(
|
||||
"posts",
|
||||
{
|
||||
id: varchar("id", { length: 15 }).primaryKey(),
|
||||
userId: varchar("user_id", { length: 255 }).notNull(),
|
||||
title: varchar("title", { length: 255 }).notNull(),
|
||||
excerpt: varchar("excerpt", { length: 255 }).notNull(),
|
||||
content: text("content").notNull(),
|
||||
status: varchar("status", { length: 10, enum: ["draft", "published"] })
|
||||
.default("draft")
|
||||
.notNull(),
|
||||
tags: varchar("tags", { length: 255 }),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at", { mode: "date" }).$onUpdate(() => new Date()),
|
||||
},
|
||||
(t) => ({
|
||||
userIdx: index("post_user_idx").on(t.userId),
|
||||
createdAtIdx: index("post_created_at_idx").on(t.createdAt),
|
||||
}),
|
||||
);
|
||||
|
||||
export const postRelations = relations(posts, ({ one }) => ({
|
||||
user: one(users, {
|
||||
fields: [posts.userId],
|
||||
references: [users.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export type Post = typeof posts.$inferSelect;
|
||||
export type NewPost = typeof posts.$inferInsert;
|
||||
|
||||
export const vwUserSessions = pgView("vw_user_sessions", { id: varchar({ length: 255 }),
|
||||
userId: varchar("user_id", { length: 21 }),
|
||||
uId: varchar("u_id", { length: 21 }),
|
||||
uEmail: varchar("u_email", { length: 255 }),
|
||||
expiresAt: timestamp("expires_at", { withTimezone: true, mode: 'string' }),
|
||||
createdAt: timestamp("created_at", { mode: 'string' }),
|
||||
updatedAt: timestamp("updated_at", { mode: 'string' }),
|
||||
}).existing();
|
||||
//as(sql`SELECT s.id, s.user_id, u.id AS u_id, u.email AS u_email, s.expires_at, s.created_at, s.updated_at FROM sessions s, users u WHERE s.user_id::text = u.id::text`);
|
||||
|
||||
// Default Drizzle File
|
||||
|
||||
// import { pgTable, serial, text, integer, timestamp } from "drizzle-orm/pg-core";
|
||||
|
||||
// export const products = pgTable("products", {
|
||||
// id: serial("id").primaryKey(),
|
||||
// name: text("name").notNull(),
|
||||
// description: text("description"),
|
||||
// price: integer("price"),
|
||||
// createdAt: timestamp("created_at").defaultNow(),
|
||||
// // Add more fields as needed
|
||||
// });
|
||||
|
||||
export const affiliateCategoryMap = pgTable("affiliate_category_map", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "affiliate_category_map_id_seq", startWith: 1, increment: 1 }),
|
||||
feedname: varchar("feedname", { length: 100 }).notNull(),
|
||||
affiliatecategory: varchar("affiliatecategory", { length: 255 }).notNull(),
|
||||
buildercategoryid: integer("buildercategoryid").notNull(),
|
||||
notes: varchar("notes", { length: 255 }),
|
||||
});
|
||||
|
||||
export const product_categories = pgTable("product_categories", {
|
||||
id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "product_categories_id_seq", startWith: 1, increment: 1 }),
|
||||
name: varchar({ length: 100 }).notNull(),
|
||||
parent_category_id: integer("parent_category_id"),
|
||||
type: varchar({ length: 50 }),
|
||||
sort_order: integer("sort_order"),
|
||||
created_at: timestamp("created_at", { mode: 'string' }).defaultNow(),
|
||||
updated_at: timestamp("updated_at", { mode: 'string' }).defaultNow(),
|
||||
});
|
||||
export const productAttributes = pgTable("product_attributes", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
productId: integer("product_id"),
|
||||
name: varchar({ length: 255 }).notNull(),
|
||||
value: varchar({ length: 255 }).notNull(),
|
||||
}, (table) => [
|
||||
foreignKey({
|
||||
columns: [table.productId],
|
||||
foreignColumns: [products.id],
|
||||
name: "product_attributes_product_id_fkey"
|
||||
}).onDelete("cascade"),
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user