shit show but data works

This commit is contained in:
2025-07-03 10:43:58 -04:00
parent bdb5e0fe55
commit 8e756b6553
19 changed files with 1641 additions and 636 deletions

View File

@@ -0,0 +1 @@
{}

View File

@@ -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;

View 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;
*/

View 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;

View 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": {}
}
}

View 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": {}
}
}

View 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
}
]
}

View 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]
}),
}));

View 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
View 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
View File

@@ -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"

View File

@@ -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"

View File

@@ -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,15 +136,15 @@ 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">
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">
{col === 'imageUrl' && product[col] ? (
<img src={product[col]} alt="thumb" className="h-10 w-10 object-contain border rounded" />
) : (
product[col] ?? ''
)}
{typeof product[col] === 'object' && product[col] !== null
? JSON.stringify(product[col])
: product[col] ?? ''}
</td>
))}
</tr>

View File

@@ -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,15 +508,15 @@ 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">
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">
{col === 'imageUrl' && product[col] ? (
<img src={product[col]} alt="thumb" className="h-10 w-10 object-contain border rounded" />
) : (
product[col] ?? ''
)}
{typeof product[col] === 'object' && product[col] !== null
? JSON.stringify(product[col])
: product[col] ?? ''}
</td>
))}
</tr>

View File

@@ -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,

View File

@@ -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 || ''),

View File

@@ -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
View 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(),
});

View File

@@ -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),
}
});
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),
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 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 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 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 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 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 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 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"),
]);