Spaces:
Running
Running
import { sql } from "drizzle-orm"; | |
import { pgTable, text, varchar, integer, decimal, timestamp, boolean, uuid } from "drizzle-orm/pg-core"; | |
import { relations } from "drizzle-orm"; | |
import { createInsertSchema } from "drizzle-zod"; | |
import { z } from "zod"; | |
// Users table - customers only | |
export const users = pgTable("users", { | |
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`), | |
username: varchar("username", { length: 100 }).notNull().unique(), | |
email: varchar("email", { length: 255 }).notNull().unique(), | |
password: text("password").notNull(), | |
firstName: varchar("first_name", { length: 100 }).notNull(), | |
lastName: varchar("last_name", { length: 100 }).notNull(), | |
phone: varchar("phone", { length: 20 }).notNull(), | |
street: text("street"), | |
city: varchar("city", { length: 100 }), | |
state: varchar("state", { length: 100 }), | |
pinCode: varchar("pin_code", { length: 20 }), | |
country: varchar("country", { length: 100 }), | |
// Automatic location detection fields | |
latitude: decimal("latitude", { precision: 10, scale: 8 }), | |
longitude: decimal("longitude", { precision: 11, scale: 8 }), | |
googleMapsUrl: text("google_maps_url"), | |
locationDetectedAutomatically: boolean("location_detected_automatically").default(false), | |
createdAt: timestamp("created_at").defaultNow(), | |
}); | |
// Sellers table - admin-created accounts | |
export const sellers = pgTable("sellers", { | |
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`), | |
username: varchar("username", { length: 100 }).notNull().unique(), | |
password: text("password").notNull(), | |
plainTextPassword: text("plain_text_password"), // For admin access recovery | |
createdAt: timestamp("created_at").defaultNow(), | |
}); | |
// Categories table - admin managed | |
export const categories = pgTable("categories", { | |
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`), | |
name: varchar("name", { length: 100 }).notNull().unique(), | |
icon: varchar("icon", { length: 50 }), | |
imageUrl: varchar("image_url", { length: 500 }), | |
createdAt: timestamp("created_at").defaultNow(), | |
}); | |
// Stores table - seller store information | |
export const stores = pgTable("stores", { | |
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`), | |
sellerId: uuid("seller_id").references(() => sellers.id, { onDelete: "cascade" }).notNull(), | |
name: varchar("name", { length: 200 }).notNull(), | |
description: text("description"), | |
bannerImage: text("banner_image"), | |
faceImage: text("face_image"), | |
createdAt: timestamp("created_at").defaultNow(), | |
}); | |
// Products table | |
export const products = pgTable("products", { | |
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`), | |
sellerId: uuid("seller_id").references(() => sellers.id, { onDelete: "cascade" }).notNull(), | |
categoryId: uuid("category_id").references(() => categories.id).notNull(), | |
title: varchar("title", { length: 255 }).notNull(), | |
description: text("description").notNull(), | |
price: decimal("price", { precision: 10, scale: 2 }).notNull(), | |
originalPrice: decimal("original_price", { precision: 10, scale: 2 }), | |
stock: integer("stock").default(0), | |
images: text("images").array(), | |
isActive: boolean("is_active").default(true), | |
createdAt: timestamp("created_at").defaultNow(), | |
}); | |
// Orders table | |
export const orders = pgTable("orders", { | |
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`), | |
userId: uuid("user_id").references(() => users.id).notNull(), | |
status: varchar("status", { length: 50 }).default("pending"), // pending, processing, shipped, delivered, cancelled | |
paymentStatus: varchar("payment_status", { length: 50 }).default("unpaid"), // unpaid, paid | |
subtotal: decimal("subtotal", { precision: 10, scale: 2 }).notNull(), | |
tax: decimal("tax", { precision: 10, scale: 2 }).notNull(), | |
shipping: decimal("shipping", { precision: 10, scale: 2 }).default("0.00"), | |
total: decimal("total", { precision: 10, scale: 2 }).notNull(), | |
shippingAddress: text("shipping_address").notNull(), | |
paymentMethod: varchar("payment_method", { length: 50 }).default("cod").notNull(), // cod = Cash on Delivery, upi = UPI | |
createdAt: timestamp("created_at").defaultNow(), | |
}); | |
// Order Items table | |
export const orderItems = pgTable("order_items", { | |
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`), | |
orderId: uuid("order_id").references(() => orders.id, { onDelete: "cascade" }).notNull(), | |
productId: uuid("product_id").references(() => products.id).notNull(), | |
quantity: integer("quantity").notNull(), | |
price: decimal("price", { precision: 10, scale: 2 }).notNull(), | |
}); | |
// Cart Items table | |
export const cartItems = pgTable("cart_items", { | |
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`), | |
userId: uuid("user_id").references(() => users.id, { onDelete: "cascade" }).notNull(), | |
productId: uuid("product_id").references(() => products.id, { onDelete: "cascade" }).notNull(), | |
quantity: integer("quantity").notNull().default(1), | |
createdAt: timestamp("created_at").defaultNow(), | |
}); | |
// Relations | |
export const usersRelations = relations(users, ({ many }) => ({ | |
orders: many(orders), | |
cartItems: many(cartItems), | |
})); | |
export const sellersRelations = relations(sellers, ({ one, many }) => ({ | |
store: one(stores), | |
products: many(products), | |
})); | |
export const storesRelations = relations(stores, ({ one }) => ({ | |
seller: one(sellers, { | |
fields: [stores.sellerId], | |
references: [sellers.id], | |
}), | |
})); | |
export const categoriesRelations = relations(categories, ({ many }) => ({ | |
products: many(products), | |
})); | |
export const productsRelations = relations(products, ({ one, many }) => ({ | |
seller: one(sellers, { | |
fields: [products.sellerId], | |
references: [sellers.id], | |
}), | |
category: one(categories, { | |
fields: [products.categoryId], | |
references: [categories.id], | |
}), | |
orderItems: many(orderItems), | |
cartItems: many(cartItems), | |
})); | |
export const ordersRelations = relations(orders, ({ one, many }) => ({ | |
user: one(users, { | |
fields: [orders.userId], | |
references: [users.id], | |
}), | |
orderItems: many(orderItems), | |
})); | |
export const orderItemsRelations = relations(orderItems, ({ one }) => ({ | |
order: one(orders, { | |
fields: [orderItems.orderId], | |
references: [orders.id], | |
}), | |
product: one(products, { | |
fields: [orderItems.productId], | |
references: [products.id], | |
}), | |
})); | |
export const cartItemsRelations = relations(cartItems, ({ one }) => ({ | |
user: one(users, { | |
fields: [cartItems.userId], | |
references: [users.id], | |
}), | |
product: one(products, { | |
fields: [cartItems.productId], | |
references: [products.id], | |
}), | |
})); | |
// Insert schemas | |
export const insertUserSchema = createInsertSchema(users).omit({ | |
id: true, | |
createdAt: true, | |
}).extend({ | |
// Make manual address fields optional for automatic location detection | |
street: z.string().optional(), | |
city: z.string().optional(), | |
state: z.string().optional(), | |
pinCode: z.string().optional(), | |
country: z.string().optional(), | |
// Accept both numbers (from geolocation API) and strings (for database) | |
latitude: z.union([z.number(), z.string()]).optional(), | |
longitude: z.union([z.number(), z.string()]).optional(), | |
}); | |
export const insertSellerSchema = createInsertSchema(sellers).omit({ | |
id: true, | |
createdAt: true, | |
}); | |
export const insertCategorySchema = createInsertSchema(categories).omit({ | |
id: true, | |
createdAt: true, | |
}); | |
export const insertStoreSchema = createInsertSchema(stores).omit({ | |
id: true, | |
createdAt: true, | |
}); | |
export const insertProductSchema = createInsertSchema(products).omit({ | |
id: true, | |
createdAt: true, | |
}); | |
export const insertOrderSchema = createInsertSchema(orders).omit({ | |
id: true, | |
createdAt: true, | |
}); | |
export const insertOrderItemSchema = createInsertSchema(orderItems).omit({ | |
id: true, | |
}); | |
export const insertCartItemSchema = createInsertSchema(cartItems).omit({ | |
id: true, | |
createdAt: true, | |
}); | |
// Types | |
export type User = typeof users.$inferSelect; | |
export type InsertUser = z.infer<typeof insertUserSchema>; | |
export type Seller = typeof sellers.$inferSelect; | |
export type InsertSeller = z.infer<typeof insertSellerSchema>; | |
export type Category = typeof categories.$inferSelect; | |
export type InsertCategory = z.infer<typeof insertCategorySchema>; | |
export type Store = typeof stores.$inferSelect; | |
export type InsertStore = z.infer<typeof insertStoreSchema>; | |
export type Product = typeof products.$inferSelect; | |
export type InsertProduct = z.infer<typeof insertProductSchema>; | |
export type Order = typeof orders.$inferSelect; | |
export type InsertOrder = z.infer<typeof insertOrderSchema>; | |
export type OrderItem = typeof orderItems.$inferSelect; | |
export type InsertOrderItem = z.infer<typeof insertOrderItemSchema>; | |
export type CartItem = typeof cartItems.$inferSelect; | |
export type InsertCartItem = z.infer<typeof insertCartItemSchema>; | |