This commit is contained in:
shafi54 2026-03-24 18:48:31 +05:30
parent 23be301cc0
commit 17e2644759
130 changed files with 3277 additions and 2266 deletions

View file

@ -1,7 +1,10 @@
ENV_MODE=PROD ENV_MODE=PROD
DATABASE_URL=postgresql://postgres:meatfarmer_master_password@57.128.212.174:7447/meatfarmer #technocracy # DATABASE_URL=postgresql://postgres:meatfarmer_master_password@57.128.212.174:7447/meatfarmer #technocracy
# DATABASE_URL=postgres://postgres:meatfarmer_master_password@5.223.55.14:7447/meatfarmer #hetzner # DATABASE_URL=postgres://postgres:meatfarmer_master_password@5.223.55.14:7447/meatfarmer #hetzner
SQLITE_DB_PATH='./sqlite.db'
DB_DIALECT='sqlite'
PHONE_PE_BASE_URL=https://api-preprod.phonepe.com/ PHONE_PE_BASE_URL=https://api-preprod.phonepe.com/
PHONE_PE_CLIENT_ID=TEST-M23F2IGP34ZAR_25090 PHONE_PE_CLIENT_ID=TEST-M23F2IGP34ZAR_25090
PHONE_PE_CLIENT_VERSION=1 PHONE_PE_CLIENT_VERSION=1
PHONE_PE_CLIENT_SECRET=MTU1MmIzOTgtM2Q0Mi00N2M5LTkyMWUtNzBiMjdmYzVmZWUy PHONE_PE_CLIENT_SECRET=MTU1MmIzOTgtM2Q0Mi00N2M5LTkyMWUtNzBiMjdmYzVmZWUy

View file

@ -1,11 +1,6 @@
import 'dotenv/config'; import postgresConfig from '../db-helper-postgres/drizzle.config'
import { defineConfig } from 'drizzle-kit'; import sqliteConfig from '../db-helper-sqlite/drizzle.config'
export default defineConfig({ export default process.env.DB_DIALECT === 'sqlite'
out: './drizzle', ? sqliteConfig
schema: './src/db/schema.ts', : postgresConfig
dialect: 'postgresql',
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});

View file

@ -157,7 +157,6 @@ app.onError((err, c) => {
return c.json({ message }, status) return c.json({ message }, status)
}) })
<<<<<<< HEAD
// Start server // Start server
serve({ serve({
fetch: app.fetch, fetch: app.fetch,
@ -166,8 +165,3 @@ serve({
}) })
console.log('🚀 Server running on http://localhost:4000') console.log('🚀 Server running on http://localhost:4000')
=======
app.listen(4000, '::', () => {
console.log("Server is running on http://localhost:4000/api/mobile/");
});
>>>>>>> main

View file

@ -4,16 +4,16 @@
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"migrate": "drizzle-kit generate --config drizzle.config.postgres.ts", "migrate": "drizzle-kit generate --config ../db-helper-postgres/drizzle.config.ts",
"migrate:pg": "drizzle-kit generate --config drizzle.config.postgres.ts", "migrate:pg": "drizzle-kit generate --config ../db-helper-postgres/drizzle.config.ts",
"migrate:sqlite": "drizzle-kit generate --config drizzle.config.sqlite.ts", "migrate:sqlite": "drizzle-kit generate --config ../db-helper-sqlite/drizzle.config.ts",
"generate:pg": "bunx drizzle-kit generate --config drizzle.config.postgres.ts", "generate:pg": "bunx drizzle-kit generate --config ../db-helper-postgres/drizzle.config.ts",
"generate:sqlite": "bunx drizzle-kit generate --config drizzle.config.sqlite.ts", "generate:sqlite": "bunx drizzle-kit generate --config ../db-helper-sqlite/drizzle.config.ts",
"build": "rimraf ./dist && tsc --project tsconfig.json && tsc-alias -p tsconfig.json", "build": "rimraf ./dist && tsc --project tsconfig.json && tsc-alias -p tsconfig.json",
"build2": "rimraf ./dist && tsc", "build2": "rimraf ./dist && tsc",
"db:push": "drizzle-kit push --config drizzle.config.postgres.ts", "db:push": "drizzle-kit push --config ../db-helper-postgres/drizzle.config.ts",
"db:push:pg": "drizzle-kit push --config drizzle.config.postgres.ts", "db:push:pg": "drizzle-kit push --config ../db-helper-postgres/drizzle.config.ts",
"db:push:sqlite": "drizzle-kit push --config drizzle.config.sqlite.ts", "db:push:sqlite": "drizzle-kit push --config ../db-helper-sqlite/drizzle.config.ts",
"db:seed": "tsx src/db/seed.ts", "db:seed": "tsx src/db/seed.ts",
"dev:express": "bun --watch index-express.ts", "dev:express": "bun --watch index-express.ts",
"dev:hono": "bun --watch index.ts", "dev:hono": "bun --watch index.ts",
@ -46,7 +46,6 @@
"jose": "^5.10.0", "jose": "^5.10.0",
"node-cron": "^4.2.1", "node-cron": "^4.2.1",
"pg": "^8.16.3", "pg": "^8.16.3",
"razorpay": "^2.9.6",
"redis": "^5.9.0", "redis": "^5.9.0",
"zod": "^4.1.12" "zod": "^4.1.12"
}, },

BIN
apps/backend/sqlite.db Normal file

Binary file not shown.

View file

@ -1,85 +1,19 @@
import { eq, gt, and, sql, inArray } from "drizzle-orm"; import { Context } from 'hono'
import { Context } from "hono";
import { db } from "@/src/db/db_index"
import { productInfo, units, productSlots, deliverySlotInfo, productTags } from "@/src/db/schema"
import { scaffoldAssetUrl } from "@/src/lib/s3-client"
/** import { getProductsSummaryData } from '@/src/db/common-product'
* Get next delivery date for a product import { scaffoldAssetUrl } from '@/src/lib/s3-client'
*/
const getNextDeliveryDate = async (productId: number): Promise<Date | null> => {
const result = await db
.select({ deliveryTime: deliverySlotInfo.deliveryTime })
.from(productSlots)
.innerJoin(deliverySlotInfo, eq(productSlots.slotId, deliverySlotInfo.id))
.where(
and(
eq(productSlots.productId, productId),
eq(deliverySlotInfo.isActive, true),
gt(deliverySlotInfo.deliveryTime, sql`NOW()`)
)
)
.orderBy(deliverySlotInfo.deliveryTime)
.limit(1);
return result[0]?.deliveryTime || null;
};
/** /**
* Get all products summary for dropdown * Get all products summary for dropdown
*/ */
export const getAllProductsSummary = async (c: Context) => { export const getAllProductsSummary = async (c: Context) => {
try { try {
const tagId = c.req.query('tagId'); const tagId = c.req.query('tagId')
const tagIdNum = tagId ? parseInt(tagId) : null; const tagIdNum = tagId ? parseInt(tagId) : null
let productIds: number[] | null = null; const productsWithUnits = await getProductsSummaryData(tagIdNum)
// If tagId is provided, get products that have this tag const formattedProducts = productsWithUnits.map((product) => ({
if (tagIdNum) {
const taggedProducts = await db
.select({ productId: productTags.productId })
.from(productTags)
.where(eq(productTags.tagId, tagIdNum));
productIds = taggedProducts.map(tp => tp.productId);
}
let whereCondition = undefined;
// Filter by product IDs if tag filtering is applied
if (productIds && productIds.length > 0) {
whereCondition = inArray(productInfo.id, productIds);
} else if (tagIdNum) {
// If tagId was provided but no products found, return empty array
return c.json({
products: [],
count: 0,
});
}
const productsWithUnits = await db
.select({
id: productInfo.id,
name: productInfo.name,
shortDescription: productInfo.shortDescription,
price: productInfo.price,
marketPrice: productInfo.marketPrice,
images: productInfo.images,
isOutOfStock: productInfo.isOutOfStock,
unitShortNotation: units.shortNotation,
productQuantity: productInfo.productQuantity,
})
.from(productInfo)
.innerJoin(units, eq(productInfo.unitId, units.id))
.where(whereCondition);
// Generate signed URLs for product images
const formattedProducts = await Promise.all(
productsWithUnits.map(async (product) => {
const nextDeliveryDate = await getNextDeliveryDate(product.id);
return {
id: product.id, id: product.id,
name: product.name, name: product.name,
shortDescription: product.shortDescription, shortDescription: product.shortDescription,
@ -88,18 +22,16 @@ export const getAllProductsSummary = async (c: Context) => {
unit: product.unitShortNotation, unit: product.unitShortNotation,
productQuantity: product.productQuantity, productQuantity: product.productQuantity,
isOutOfStock: product.isOutOfStock, isOutOfStock: product.isOutOfStock,
nextDeliveryDate: nextDeliveryDate ? nextDeliveryDate.toISOString() : null, nextDeliveryDate: product.nextDeliveryDate ? product.nextDeliveryDate.toISOString() : null,
images: scaffoldAssetUrl((product.images as string[]) || []), images: scaffoldAssetUrl((product.images as string[]) || []),
}; }))
})
);
return c.json({ return c.json({
products: formattedProducts, products: formattedProducts,
count: formattedProducts.length, count: formattedProducts.length,
}); })
} catch (error) { } catch (error) {
console.error("Get products summary error:", error); console.error('Get products summary error:', error)
return c.json({ error: "Failed to fetch products summary" }, 500); return c.json({ error: 'Failed to fetch products summary' }, 500)
}
} }
};

View file

@ -0,0 +1,10 @@
import { getProductsSummaryData as getProductsSummaryDataPostgres } from '@db-helper-postgres/apis/common-apis/common-product'
import { getProductsSummaryData as getProductsSummaryDataSqlite } from '@db-helper-sqlite/apis/common-apis/common-product'
const dialect = process.env.DB_DIALECT || DB_DIALECT_TYPE
const getProductsSummaryData = dialect === 'sqlite'
? getProductsSummaryDataSqlite
: getProductsSummaryDataPostgres
export { getProductsSummaryData }

14
apps/backend/src/db/db_index.ts Executable file → Normal file
View file

@ -1,8 +1,10 @@
import { drizzle } from "drizzle-orm/node-postgres" import { db as postgresDb } from '@db-helper-postgres/db/db_index'
import { migrate } from "drizzle-orm/node-postgres/migrator" import { db as sqliteDb } from '@db-helper-sqlite/db/db_index'
import path from "path"
import * as schema from "@/src/db/schema-postgres" const dialect = process.env.DB_DIALECT || DB_DIALECT_TYPE
type Db = typeof DB_DIALECT_TYPE extends 'sqlite' ? typeof sqliteDb : typeof postgresDb
const db = (dialect === 'sqlite' ? sqliteDb : postgresDb) as Db
const db = drizzle({ connection: process.env.DATABASE_URL!, casing: "snake_case", schema: schema })
// const db = drizzle('postgresql://postgres:postgres@localhost:2345/pooler');
export { db } export { db }

View file

@ -1,10 +0,0 @@
import { drizzle } from 'drizzle-orm/bun-sqlite'
import { Database } from 'bun:sqlite'
import * as schema from '@/src/db/schema-sqlite'
const sqlitePath = process.env.SQLITE_DB_PATH || 'sqlite.db'
const sqlite = new Database(sqlitePath)
const db = drizzle(sqlite, { schema })
export { db }

View file

@ -1,706 +1 @@
import { pgTable, pgSchema, integer, varchar, date, boolean, timestamp, numeric, jsonb, pgEnum, unique, real, text, check, decimal } from "drizzle-orm/pg-core"; export * from '@/db-helper-postgres/db/schema'
import { relations, sql } from "drizzle-orm";
const mf = pgSchema('mf');
export const users = mf.table('users', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
name: varchar({ length: 255 }),
email: varchar({ length: 255 }),
mobile: varchar({ length: 255 }),
createdAt: timestamp('created_at').notNull().defaultNow(),
}, (t) => ({
unq_email: unique('unique_email').on(t.email),
}));
export const userDetails = mf.table('user_details', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id).unique(),
bio: varchar('bio', { length: 500 }),
dateOfBirth: date('date_of_birth'),
gender: varchar('gender', { length: 20 }),
occupation: varchar('occupation', { length: 100 }),
profileImage: varchar('profile_image', { length: 500 }),
isSuspended: boolean('is_suspended').notNull().default(false),
createdAt: timestamp('created_at').notNull().defaultNow(),
updatedAt: timestamp('updated_at').notNull().defaultNow(),
});
export const userCreds = mf.table('user_creds', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
userPassword: varchar('user_password', { length: 255 }).notNull(),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const addresses = mf.table('addresses', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
name: varchar('name', { length: 255 }).notNull(),
phone: varchar('phone', { length: 15 }).notNull(),
addressLine1: varchar('address_line1', { length: 255 }).notNull(),
addressLine2: varchar('address_line2', { length: 255 }),
city: varchar('city', { length: 100 }).notNull(),
state: varchar('state', { length: 100 }).notNull(),
pincode: varchar('pincode', { length: 10 }).notNull(),
isDefault: boolean('is_default').notNull().default(false),
latitude: real('latitude'),
longitude: real('longitude'),
googleMapsUrl: varchar('google_maps_url', { length: 500 }),
adminLatitude: real('admin_latitude'),
adminLongitude: real('admin_longitude'),
zoneId: integer('zone_id').references(() => addressZones.id),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const addressZones = mf.table('address_zones', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
zoneName: varchar('zone_name', { length: 255 }).notNull(),
addedAt: timestamp('added_at').notNull().defaultNow(),
});
export const addressAreas = mf.table('address_areas', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
placeName: varchar('place_name', { length: 255 }).notNull(),
zoneId: integer('zone_id').references(() => addressZones.id),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const staffUsers = mf.table('staff_users', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
name: varchar({ length: 255 }).notNull(),
password: varchar({ length: 255 }).notNull(),
staffRoleId: integer('staff_role_id').references(() => staffRoles.id),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const storeInfo = mf.table('store_info', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
name: varchar({ length: 255 }).notNull(),
description: varchar({ length: 500 }),
imageUrl: varchar('image_url', { length: 500 }),
createdAt: timestamp('created_at').notNull().defaultNow(),
owner: integer('owner').notNull().references(() => staffUsers.id),
});
export const units = mf.table('units', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
shortNotation: varchar('short_notation', { length: 50 }).notNull(),
fullName: varchar('full_name', { length: 100 }).notNull(),
}, (t) => ({
unq_short_notation: unique('unique_short_notation').on(t.shortNotation),
}));
export const productAvailabilityActionEnum = pgEnum('product_availability_action', ['in', 'out']);
export const productInfo = mf.table('product_info', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
name: varchar({ length: 255 }).notNull(),
shortDescription: varchar('short_description', { length: 500 }),
longDescription: varchar('long_description', { length: 1000 }),
unitId: integer('unit_id').notNull().references(() => units.id),
price: numeric({ precision: 10, scale: 2 }).notNull(),
marketPrice: numeric('market_price', { precision: 10, scale: 2 }),
images: jsonb('images'),
isOutOfStock: boolean('is_out_of_stock').notNull().default(false),
isSuspended: boolean('is_suspended').notNull().default(false),
isFlashAvailable: boolean('is_flash_available').notNull().default(false),
flashPrice: numeric('flash_price', { precision: 10, scale: 2 }),
createdAt: timestamp('created_at').notNull().defaultNow(),
incrementStep: real('increment_step').notNull().default(1),
productQuantity: real('product_quantity').notNull().default(1),
storeId: integer('store_id').references(() => storeInfo.id),
scheduledAvailability: boolean('scheduled_availability').notNull().default(true),
});
export const productAvailabilitySchedules = mf.table('product_availability_schedules', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
time: varchar('time', { length: 10 }).notNull(),
scheduleName: varchar('schedule_name', { length: 255 }).notNull().unique(),
action: productAvailabilityActionEnum('action').notNull(),
productIds: integer('product_ids').array().notNull().default([]),
groupIds: integer('group_ids').array().notNull().default([]),
createdAt: timestamp('created_at').notNull().defaultNow(),
lastUpdated: timestamp('last_updated').notNull().defaultNow(),
});
export const productGroupInfo = mf.table('product_group_info', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
groupName: varchar('group_name', { length: 255 }).notNull(),
description: varchar({ length: 500 }),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const productGroupMembership = mf.table('product_group_membership', {
productId: integer('product_id').notNull().references(() => productInfo.id),
groupId: integer('group_id').notNull().references(() => productGroupInfo.id),
addedAt: timestamp('added_at').notNull().defaultNow(),
}, (t) => ({
pk: unique('product_group_membership_pk').on(t.productId, t.groupId),
}));
export const homeBanners = mf.table('home_banners', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
name: varchar('name', { length: 255 }).notNull(),
imageUrl: varchar('image_url', { length: 500 }).notNull(),
description: varchar('description', { length: 500 }),
productIds: integer('product_ids').array(),
redirectUrl: varchar('redirect_url', { length: 500 }),
serialNum: integer('serial_num'),
isActive: boolean('is_active').notNull().default(false),
createdAt: timestamp('created_at').notNull().defaultNow(),
lastUpdated: timestamp('last_updated').notNull().defaultNow(),
});
export const productReviews = mf.table('product_reviews', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
productId: integer('product_id').notNull().references(() => productInfo.id),
reviewBody: text('review_body').notNull(),
imageUrls: jsonb('image_urls').$defaultFn(() => []),
reviewTime: timestamp('review_time').notNull().defaultNow(),
ratings: real('ratings').notNull(),
adminResponse: text('admin_response'),
adminResponseImages: jsonb('admin_response_images').$defaultFn(() => []),
}, (t) => ({
ratingCheck: check('rating_check', sql`${t.ratings} >= 1 AND ${t.ratings} <= 5`),
}));
export const uploadStatusEnum = pgEnum('upload_status', ['pending', 'claimed']);
export const staffRoleEnum = pgEnum('staff_role', ['super_admin', 'admin', 'marketer', 'delivery_staff']);
export const staffPermissionEnum = pgEnum('staff_permission', ['crud_product', 'make_coupon', 'crud_staff_users']);
export const uploadUrlStatus = mf.table('upload_url_status', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
createdAt: timestamp('created_at').notNull().defaultNow(),
key: varchar('key', { length: 500 }).notNull(),
status: uploadStatusEnum('status').notNull().default('pending'),
});
export const productTagInfo = mf.table('product_tag_info', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
tagName: varchar('tag_name', { length: 100 }).notNull().unique(),
tagDescription: varchar('tag_description', { length: 500 }),
imageUrl: varchar('image_url', { length: 500 }),
isDashboardTag: boolean('is_dashboard_tag').notNull().default(false),
relatedStores: jsonb('related_stores').$defaultFn(() => []),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const productTags = mf.table('product_tags', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
productId: integer('product_id').notNull().references(() => productInfo.id),
tagId: integer('tag_id').notNull().references(() => productTagInfo.id),
assignedAt: timestamp('assigned_at').notNull().defaultNow(),
}, (t) => ({
unq_product_tag: unique('unique_product_tag').on(t.productId, t.tagId),
}));
export const deliverySlotInfo = mf.table('delivery_slot_info', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
deliveryTime: timestamp('delivery_time').notNull(),
freezeTime: timestamp('freeze_time').notNull(),
isActive: boolean('is_active').notNull().default(true),
isFlash: boolean('is_flash').notNull().default(false),
isCapacityFull: boolean('is_capacity_full').notNull().default(false),
deliverySequence: jsonb('delivery_sequence').$defaultFn(() => {}),
groupIds: jsonb('group_ids').$defaultFn(() => []),
});
export const vendorSnippets = mf.table('vendor_snippets', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
snippetCode: varchar('snippet_code', { length: 255 }).notNull().unique(),
slotId: integer('slot_id').references(() => deliverySlotInfo.id),
isPermanent: boolean('is_permanent').notNull().default(false),
productIds: integer('product_ids').array().notNull(),
validTill: timestamp('valid_till'),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const vendorSnippetsRelations = relations(vendorSnippets, ({ one }) => ({
slot: one(deliverySlotInfo, { fields: [vendorSnippets.slotId], references: [deliverySlotInfo.id] }),
}));
export const productSlots = mf.table('product_slots', {
productId: integer('product_id').notNull().references(() => productInfo.id),
slotId: integer('slot_id').notNull().references(() => deliverySlotInfo.id),
}, (t) => ({
pk: unique('product_slot_pk').on(t.productId, t.slotId),
}));
export const specialDeals = mf.table('special_deals', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
productId: integer('product_id').notNull().references(() => productInfo.id),
quantity: numeric({ precision: 10, scale: 2 }).notNull(),
price: numeric({ precision: 10, scale: 2 }).notNull(),
validTill: timestamp('valid_till').notNull(),
});
export const orders = mf.table('orders', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
addressId: integer('address_id').notNull().references(() => addresses.id),
slotId: integer('slot_id').references(() => deliverySlotInfo.id),
isCod: boolean('is_cod').notNull().default(false),
isOnlinePayment: boolean('is_online_payment').notNull().default(false),
paymentInfoId: integer('payment_info_id').references(() => paymentInfoTable.id),
totalAmount: numeric('total_amount', { precision: 10, scale: 2 }).notNull(),
deliveryCharge: numeric('delivery_charge', { precision: 10, scale: 2 }).notNull().default('0'),
readableId: integer('readable_id').notNull(),
adminNotes: text('admin_notes'),
userNotes: text('user_notes'),
orderGroupId: varchar('order_group_id', { length: 255 }),
orderGroupProportion: decimal('order_group_proportion', { precision: 10, scale: 4 }),
isFlashDelivery: boolean('is_flash_delivery').notNull().default(false),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const orderItems = mf.table('order_items', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
orderId: integer('order_id').notNull().references(() => orders.id),
productId: integer('product_id').notNull().references(() => productInfo.id),
quantity: varchar('quantity', { length: 50 }).notNull(),
price: numeric({ precision: 10, scale: 2 }).notNull(),
discountedPrice: numeric('discounted_price', { precision: 10, scale: 2 }),
is_packaged: boolean('is_packaged').notNull().default(false),
is_package_verified: boolean('is_package_verified').notNull().default(false),
});
export const paymentStatusEnum = pgEnum('payment_status', ['pending', 'success', 'cod', 'failed']);
export const orderStatus = mf.table('order_status', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
orderTime: timestamp('order_time').notNull().defaultNow(),
userId: integer('user_id').notNull().references(() => users.id),
orderId: integer('order_id').notNull().references(() => orders.id),
isPackaged: boolean('is_packaged').notNull().default(false),
isDelivered: boolean('is_delivered').notNull().default(false),
isCancelled: boolean('is_cancelled').notNull().default(false),
cancelReason: varchar('cancel_reason', { length: 255 }),
isCancelledByAdmin: boolean('is_cancelled_by_admin'),
paymentStatus: paymentStatusEnum('payment_state').notNull().default('pending'),
cancellationUserNotes: text('cancellation_user_notes'),
cancellationAdminNotes: text('cancellation_admin_notes'),
cancellationReviewed: boolean('cancellation_reviewed').notNull().default(false),
cancellationReviewedAt: timestamp('cancellation_reviewed_at'),
refundCouponId: integer('refund_coupon_id').references(() => coupons.id),
});
export const paymentInfoTable = mf.table('payment_info', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
status: varchar({ length: 50 }).notNull(),
gateway: varchar({ length: 50 }).notNull(),
orderId: varchar('order_id', { length: 500 }),
token: varchar({ length: 500 }),
merchantOrderId: varchar('merchant_order_id', { length: 255 }).notNull().unique(),
payload: jsonb('payload'),
});
export const payments = mf.table('payments', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
status: varchar({ length: 50 }).notNull(),
gateway: varchar({ length: 50 }).notNull(),
orderId: integer('order_id').notNull().references(() => orders.id),
token: varchar({ length: 500 }),
merchantOrderId: varchar('merchant_order_id', { length: 255 }).notNull().unique(),
payload: jsonb('payload'),
});
export const refunds = mf.table('refunds', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
orderId: integer('order_id').notNull().references(() => orders.id),
refundAmount: numeric('refund_amount', { precision: 10, scale: 2 }),
refundStatus: varchar('refund_status', { length: 50 }).default('none'),
merchantRefundId: varchar('merchant_refund_id', { length: 255 }),
refundProcessedAt: timestamp('refund_processed_at'),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const keyValStore = mf.table('key_val_store', {
key: varchar('key', { length: 255 }).primaryKey(),
value: jsonb('value'),
});
export const notifications = mf.table('notifications', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
title: varchar({ length: 255 }).notNull(),
body: varchar({ length: 512 }).notNull(),
type: varchar({ length: 50 }),
isRead: boolean('is_read').notNull().default(false),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const productCategories = mf.table('product_categories', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
name: varchar({ length: 255 }).notNull(),
description: varchar({ length: 500 }),
});
export const cartItems = mf.table('cart_items', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
productId: integer('product_id').notNull().references(() => productInfo.id),
quantity: numeric({ precision: 10, scale: 2 }).notNull(),
addedAt: timestamp('added_at').notNull().defaultNow(),
}, (t) => ({
unq_user_product: unique('unique_user_product').on(t.userId, t.productId),
}));
export const complaints = mf.table('complaints', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
orderId: integer('order_id').references(() => orders.id),
complaintBody: varchar('complaint_body', { length: 1000 }).notNull(),
images: jsonb('images'),
response: varchar('response', { length: 1000 }),
isResolved: boolean('is_resolved').notNull().default(false),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const coupons = mf.table('coupons', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
couponCode: varchar('coupon_code', { length: 50 }).notNull().unique('unique_coupon_code'),
isUserBased: boolean('is_user_based').notNull().default(false),
discountPercent: numeric('discount_percent', { precision: 5, scale: 2 }),
flatDiscount: numeric('flat_discount', { precision: 10, scale: 2 }),
minOrder: numeric('min_order', { precision: 10, scale: 2 }),
productIds: jsonb('product_ids'),
createdBy: integer('created_by').references(() => staffUsers.id),
maxValue: numeric('max_value', { precision: 10, scale: 2 }),
isApplyForAll: boolean('is_apply_for_all').notNull().default(false),
validTill: timestamp('valid_till'),
maxLimitForUser: integer('max_limit_for_user'),
isInvalidated: boolean('is_invalidated').notNull().default(false),
exclusiveApply: boolean('exclusive_apply').notNull().default(false),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const couponUsage = mf.table('coupon_usage', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
couponId: integer('coupon_id').notNull().references(() => coupons.id),
orderId: integer('order_id').references(() => orders.id),
orderItemId: integer('order_item_id').references(() => orderItems.id),
usedAt: timestamp('used_at').notNull().defaultNow(),
});
export const couponApplicableUsers = mf.table('coupon_applicable_users', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
couponId: integer('coupon_id').notNull().references(() => coupons.id),
userId: integer('user_id').notNull().references(() => users.id),
}, (t) => ({
unq_coupon_user: unique('unique_coupon_user').on(t.couponId, t.userId),
}));
export const couponApplicableProducts = mf.table('coupon_applicable_products', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
couponId: integer('coupon_id').notNull().references(() => coupons.id),
productId: integer('product_id').notNull().references(() => productInfo.id),
}, (t) => ({
unq_coupon_product: unique('unique_coupon_product').on(t.couponId, t.productId),
}));
export const userIncidents = mf.table('user_incidents', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
orderId: integer('order_id').references(() => orders.id),
dateAdded: timestamp('date_added').notNull().defaultNow(),
adminComment: text('admin_comment'),
addedBy: integer('added_by').references(() => staffUsers.id),
negativityScore: integer('negativity_score'),
});
export const reservedCoupons = mf.table('reserved_coupons', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
secretCode: varchar('secret_code', { length: 50 }).notNull().unique(),
couponCode: varchar('coupon_code', { length: 50 }).notNull(),
discountPercent: numeric('discount_percent', { precision: 5, scale: 2 }),
flatDiscount: numeric('flat_discount', { precision: 10, scale: 2 }),
minOrder: numeric('min_order', { precision: 10, scale: 2 }),
productIds: jsonb('product_ids'),
maxValue: numeric('max_value', { precision: 10, scale: 2 }),
validTill: timestamp('valid_till'),
maxLimitForUser: integer('max_limit_for_user'),
exclusiveApply: boolean('exclusive_apply').notNull().default(false),
isRedeemed: boolean('is_redeemed').notNull().default(false),
redeemedBy: integer('redeemed_by').references(() => users.id),
redeemedAt: timestamp('redeemed_at'),
createdBy: integer('created_by').notNull().references(() => staffUsers.id),
createdAt: timestamp('created_at').notNull().defaultNow(),
}, (t) => ({
unq_secret_code: unique('unique_secret_code').on(t.secretCode),
}));
export const notifCreds = mf.table('notif_creds', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
token: varchar({ length: 500 }).notNull().unique(),
addedAt: timestamp('added_at').notNull().defaultNow(),
userId: integer('user_id').notNull().references(() => users.id),
lastVerified: timestamp('last_verified'),
});
export const unloggedUserTokens = mf.table('unlogged_user_tokens', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
token: varchar({ length: 500 }).notNull().unique(),
addedAt: timestamp('added_at').notNull().defaultNow(),
lastVerified: timestamp('last_verified'),
});
export const userNotifications = mf.table('user_notifications', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
title: varchar('title', { length: 255 }).notNull(),
imageUrl: varchar('image_url', { length: 500 }),
createdAt: timestamp('created_at').notNull().defaultNow(),
body: text('body').notNull(),
applicableUsers: jsonb('applicable_users'),
});
export const staffRoles = mf.table('staff_roles', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
roleName: staffRoleEnum('role_name').notNull(),
createdAt: timestamp('created_at').notNull().defaultNow(),
}, (t) => ({
unq_role_name: unique('unique_role_name').on(t.roleName),
}));
export const staffPermissions = mf.table('staff_permissions', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
permissionName: staffPermissionEnum('permission_name').notNull(),
createdAt: timestamp('created_at').notNull().defaultNow(),
}, (t) => ({
unq_permission_name: unique('unique_permission_name').on(t.permissionName),
}));
export const staffRolePermissions = mf.table('staff_role_permissions', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
staffRoleId: integer('staff_role_id').notNull().references(() => staffRoles.id),
staffPermissionId: integer('staff_permission_id').notNull().references(() => staffPermissions.id),
createdAt: timestamp('created_at').notNull().defaultNow(),
}, (t) => ({
unq_role_permission: unique('unique_role_permission').on(t.staffRoleId, t.staffPermissionId),
}));
// Relations
export const usersRelations = relations(users, ({ many, one }) => ({
addresses: many(addresses),
orders: many(orders),
notifications: many(notifications),
cartItems: many(cartItems),
userCreds: one(userCreds),
coupons: many(coupons),
couponUsages: many(couponUsage),
applicableCoupons: many(couponApplicableUsers),
userDetails: one(userDetails),
notifCreds: many(notifCreds),
userIncidents: many(userIncidents),
}));
export const userCredsRelations = relations(userCreds, ({ one }) => ({
user: one(users, { fields: [userCreds.userId], references: [users.id] }),
}));
export const staffUsersRelations = relations(staffUsers, ({ one, many }) => ({
role: one(staffRoles, { fields: [staffUsers.staffRoleId], references: [staffRoles.id] }),
coupons: many(coupons),
stores: many(storeInfo),
}));
export const addressesRelations = relations(addresses, ({ one, many }) => ({
user: one(users, { fields: [addresses.userId], references: [users.id] }),
orders: many(orders),
zone: one(addressZones, { fields: [addresses.zoneId], references: [addressZones.id] }),
}));
export const unitsRelations = relations(units, ({ many }) => ({
products: many(productInfo),
}));
export const productInfoRelations = relations(productInfo, ({ one, many }) => ({
unit: one(units, { fields: [productInfo.unitId], references: [units.id] }),
store: one(storeInfo, { fields: [productInfo.storeId], references: [storeInfo.id] }),
productSlots: many(productSlots),
specialDeals: many(specialDeals),
orderItems: many(orderItems),
cartItems: many(cartItems),
tags: many(productTags),
applicableCoupons: many(couponApplicableProducts),
reviews: many(productReviews),
groups: many(productGroupMembership),
}));
export const productTagInfoRelations = relations(productTagInfo, ({ many }) => ({
products: many(productTags),
}));
export const productTagsRelations = relations(productTags, ({ one }) => ({
product: one(productInfo, { fields: [productTags.productId], references: [productInfo.id] }),
tag: one(productTagInfo, { fields: [productTags.tagId], references: [productTagInfo.id] }),
}));
export const deliverySlotInfoRelations = relations(deliverySlotInfo, ({ many }) => ({
productSlots: many(productSlots),
orders: many(orders),
vendorSnippets: many(vendorSnippets),
}));
export const productSlotsRelations = relations(productSlots, ({ one }) => ({
product: one(productInfo, { fields: [productSlots.productId], references: [productInfo.id] }),
slot: one(deliverySlotInfo, { fields: [productSlots.slotId], references: [deliverySlotInfo.id] }),
}));
export const specialDealsRelations = relations(specialDeals, ({ one }) => ({
product: one(productInfo, { fields: [specialDeals.productId], references: [productInfo.id] }),
}));
export const ordersRelations = relations(orders, ({ one, many }) => ({
user: one(users, { fields: [orders.userId], references: [users.id] }),
address: one(addresses, { fields: [orders.addressId], references: [addresses.id] }),
slot: one(deliverySlotInfo, { fields: [orders.slotId], references: [deliverySlotInfo.id] }),
orderItems: many(orderItems),
payment: one(payments),
paymentInfo: one(paymentInfoTable, { fields: [orders.paymentInfoId], references: [paymentInfoTable.id] }),
orderStatus: many(orderStatus),
refunds: many(refunds),
couponUsages: many(couponUsage),
userIncidents: many(userIncidents),
}));
export const orderItemsRelations = relations(orderItems, ({ one }) => ({
order: one(orders, { fields: [orderItems.orderId], references: [orders.id] }),
product: one(productInfo, { fields: [orderItems.productId], references: [productInfo.id] }),
}));
export const orderStatusRelations = relations(orderStatus, ({ one }) => ({
order: one(orders, { fields: [orderStatus.orderId], references: [orders.id] }),
user: one(users, { fields: [orderStatus.userId], references: [users.id] }),
refundCoupon: one(coupons, { fields: [orderStatus.refundCouponId], references: [coupons.id] }),
}));
export const paymentInfoRelations = relations(paymentInfoTable, ({ one }) => ({
order: one(orders, { fields: [paymentInfoTable.id], references: [orders.paymentInfoId] }),
}));
export const paymentsRelations = relations(payments, ({ one }) => ({
order: one(orders, { fields: [payments.orderId], references: [orders.id] }),
}));
export const refundsRelations = relations(refunds, ({ one }) => ({
order: one(orders, { fields: [refunds.orderId], references: [orders.id] }),
}));
export const notificationsRelations = relations(notifications, ({ one }) => ({
user: one(users, { fields: [notifications.userId], references: [users.id] }),
}));
export const productCategoriesRelations = relations(productCategories, ({}) => ({}));
export const cartItemsRelations = relations(cartItems, ({ one }) => ({
user: one(users, { fields: [cartItems.userId], references: [users.id] }),
product: one(productInfo, { fields: [cartItems.productId], references: [productInfo.id] }),
}));
export const complaintsRelations = relations(complaints, ({ one }) => ({
user: one(users, { fields: [complaints.userId], references: [users.id] }),
order: one(orders, { fields: [complaints.orderId], references: [orders.id] }),
}));
export const couponsRelations = relations(coupons, ({ one, many }) => ({
creator: one(staffUsers, { fields: [coupons.createdBy], references: [staffUsers.id] }),
usages: many(couponUsage),
applicableUsers: many(couponApplicableUsers),
applicableProducts: many(couponApplicableProducts),
}));
export const couponUsageRelations = relations(couponUsage, ({ one }) => ({
user: one(users, { fields: [couponUsage.userId], references: [users.id] }),
coupon: one(coupons, { fields: [couponUsage.couponId], references: [coupons.id] }),
order: one(orders, { fields: [couponUsage.orderId], references: [orders.id] }),
orderItem: one(orderItems, { fields: [couponUsage.orderItemId], references: [orderItems.id] }),
}));
export const userDetailsRelations = relations(userDetails, ({ one }) => ({
user: one(users, { fields: [userDetails.userId], references: [users.id] }),
}));
export const notifCredsRelations = relations(notifCreds, ({ one }) => ({
user: one(users, { fields: [notifCreds.userId], references: [users.id] }),
}));
export const userNotificationsRelations = relations(userNotifications, ({}) => ({
// No relations needed for now
}));
export const storeInfoRelations = relations(storeInfo, ({ one, many }) => ({
owner: one(staffUsers, { fields: [storeInfo.owner], references: [staffUsers.id] }),
products: many(productInfo),
}));
export const couponApplicableUsersRelations = relations(couponApplicableUsers, ({ one }) => ({
coupon: one(coupons, { fields: [couponApplicableUsers.couponId], references: [coupons.id] }),
user: one(users, { fields: [couponApplicableUsers.userId], references: [users.id] }),
}));
export const couponApplicableProductsRelations = relations(couponApplicableProducts, ({ one }) => ({
coupon: one(coupons, { fields: [couponApplicableProducts.couponId], references: [coupons.id] }),
product: one(productInfo, { fields: [couponApplicableProducts.productId], references: [productInfo.id] }),
}));
export const reservedCouponsRelations = relations(reservedCoupons, ({ one }) => ({
redeemedUser: one(users, { fields: [reservedCoupons.redeemedBy], references: [users.id] }),
creator: one(staffUsers, { fields: [reservedCoupons.createdBy], references: [staffUsers.id] }),
}));
export const productReviewsRelations = relations(productReviews, ({ one }) => ({
user: one(users, { fields: [productReviews.userId], references: [users.id] }),
product: one(productInfo, { fields: [productReviews.productId], references: [productInfo.id] }),
}));
export const addressZonesRelations = relations(addressZones, ({ many }) => ({
addresses: many(addresses),
areas: many(addressAreas),
}));
export const addressAreasRelations = relations(addressAreas, ({ one }) => ({
zone: one(addressZones, { fields: [addressAreas.zoneId], references: [addressZones.id] }),
}));
export const productGroupInfoRelations = relations(productGroupInfo, ({ many }) => ({
memberships: many(productGroupMembership),
}));
export const productGroupMembershipRelations = relations(productGroupMembership, ({ one }) => ({
product: one(productInfo, { fields: [productGroupMembership.productId], references: [productInfo.id] }),
group: one(productGroupInfo, { fields: [productGroupMembership.groupId], references: [productGroupInfo.id] }),
}));
export const homeBannersRelations = relations(homeBanners, ({}) => ({
// Relations for productIds array would be more complex, skipping for now
}));
export const staffRolesRelations = relations(staffRoles, ({ many }) => ({
staffUsers: many(staffUsers),
rolePermissions: many(staffRolePermissions),
}));
export const staffPermissionsRelations = relations(staffPermissions, ({ many }) => ({
rolePermissions: many(staffRolePermissions),
}));
export const staffRolePermissionsRelations = relations(staffRolePermissions, ({ one }) => ({
role: one(staffRoles, { fields: [staffRolePermissions.staffRoleId], references: [staffRoles.id] }),
permission: one(staffPermissions, { fields: [staffRolePermissions.staffPermissionId], references: [staffPermissions.id] }),
}));
export const userIncidentsRelations = relations(userIncidents, ({ one }) => ({
user: one(users, { fields: [userIncidents.userId], references: [users.id] }),
order: one(orders, { fields: [userIncidents.orderId], references: [orders.id] }),
addedBy: one(staffUsers, { fields: [userIncidents.addedBy], references: [staffUsers.id] }),
}));
export const productAvailabilitySchedulesRelations = relations(productAvailabilitySchedules, ({}) => ({
}));

View file

@ -1,735 +1 @@
import { export * from '@/db-helper-sqlite/db/schema'
sqliteTable,
integer,
text,
real,
unique,
check,
} from 'drizzle-orm/sqlite-core'
import { relations, sql } from 'drizzle-orm'
const epochSeconds = sql`(strftime('%s','now'))`
const sqliteEnum = <T extends readonly [string, ...string[]]>(
_name: string,
values: T
) => (columnName: string) => text(columnName, { enum: values })
export const users = sqliteTable('users', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name'),
email: text('email'),
mobile: text('mobile'),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
}, (t) => ({
unq_email: unique('unique_email').on(t.email),
}))
export const userDetails = sqliteTable('user_details', {
id: integer('id').primaryKey({ autoIncrement: true }),
userId: integer('user_id').notNull().references(() => users.id).unique(),
bio: text('bio'),
dateOfBirth: integer('date_of_birth', { mode: 'timestamp' }),
gender: text('gender'),
occupation: text('occupation'),
profileImage: text('profile_image'),
isSuspended: integer('is_suspended', { mode: 'boolean' }).notNull().default(false),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const userCreds = sqliteTable('user_creds', {
id: integer('id').primaryKey({ autoIncrement: true }),
userId: integer('user_id').notNull().references(() => users.id),
userPassword: text('user_password').notNull(),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const addressZones = sqliteTable('address_zones', {
id: integer('id').primaryKey({ autoIncrement: true }),
zoneName: text('zone_name').notNull(),
addedAt: integer('added_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const addresses = sqliteTable('addresses', {
id: integer('id').primaryKey({ autoIncrement: true }),
userId: integer('user_id').notNull().references(() => users.id),
name: text('name').notNull(),
phone: text('phone').notNull(),
addressLine1: text('address_line1').notNull(),
addressLine2: text('address_line2'),
city: text('city').notNull(),
state: text('state').notNull(),
pincode: text('pincode').notNull(),
isDefault: integer('is_default', { mode: 'boolean' }).notNull().default(false),
latitude: real('latitude'),
longitude: real('longitude'),
googleMapsUrl: text('google_maps_url'),
adminLatitude: real('admin_latitude'),
adminLongitude: real('admin_longitude'),
zoneId: integer('zone_id').references(() => addressZones.id),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const addressAreas = sqliteTable('address_areas', {
id: integer('id').primaryKey({ autoIncrement: true }),
placeName: text('place_name').notNull(),
zoneId: integer('zone_id').references(() => addressZones.id),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const staffRoleEnum = sqliteEnum('staff_role', [
'super_admin',
'admin',
'marketer',
'delivery_staff',
])
export const staffPermissionEnum = sqliteEnum('staff_permission', [
'crud_product',
'make_coupon',
'crud_staff_users',
])
export const staffRoles = sqliteTable('staff_roles', {
id: integer('id').primaryKey({ autoIncrement: true }),
roleName: staffRoleEnum('role_name').notNull(),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
}, (t) => ({
unq_role_name: unique('unique_role_name').on(t.roleName),
}))
export const staffPermissions = sqliteTable('staff_permissions', {
id: integer('id').primaryKey({ autoIncrement: true }),
permissionName: staffPermissionEnum('permission_name').notNull(),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
}, (t) => ({
unq_permission_name: unique('unique_permission_name').on(t.permissionName),
}))
export const staffRolePermissions = sqliteTable('staff_role_permissions', {
id: integer('id').primaryKey({ autoIncrement: true }),
staffRoleId: integer('staff_role_id').notNull().references(() => staffRoles.id),
staffPermissionId: integer('staff_permission_id').notNull().references(() => staffPermissions.id),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
}, (t) => ({
unq_role_permission: unique('unique_role_permission').on(
t.staffRoleId,
t.staffPermissionId
),
}))
export const staffUsers = sqliteTable('staff_users', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name').notNull(),
password: text('password').notNull(),
staffRoleId: integer('staff_role_id').references(() => staffRoles.id),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const storeInfo = sqliteTable('store_info', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name').notNull(),
description: text('description'),
imageUrl: text('image_url'),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
owner: integer('owner').notNull().references(() => staffUsers.id),
})
export const units = sqliteTable('units', {
id: integer('id').primaryKey({ autoIncrement: true }),
shortNotation: text('short_notation').notNull(),
fullName: text('full_name').notNull(),
}, (t) => ({
unq_short_notation: unique('unique_short_notation').on(t.shortNotation),
}))
export const productAvailabilityActionEnum = sqliteEnum(
'product_availability_action',
['in', 'out']
)
export const productInfo = sqliteTable('product_info', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name').notNull(),
shortDescription: text('short_description'),
longDescription: text('long_description'),
unitId: integer('unit_id').notNull().references(() => units.id),
price: text('price').notNull(),
marketPrice: text('market_price'),
images: text('images'),
isOutOfStock: integer('is_out_of_stock', { mode: 'boolean' }).notNull().default(false),
isSuspended: integer('is_suspended', { mode: 'boolean' }).notNull().default(false),
isFlashAvailable: integer('is_flash_available', { mode: 'boolean' }).notNull().default(false),
flashPrice: text('flash_price'),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
incrementStep: real('increment_step').notNull().default(1),
productQuantity: real('product_quantity').notNull().default(1),
storeId: integer('store_id').references(() => storeInfo.id),
scheduledAvailability: integer('scheduled_availability', { mode: 'boolean' }).notNull().default(true),
})
export const productAvailabilitySchedules = sqliteTable('product_availability_schedules', {
id: integer('id').primaryKey({ autoIncrement: true }),
time: text('time').notNull(),
scheduleName: text('schedule_name').notNull().unique(),
action: productAvailabilityActionEnum('action').notNull(),
productIds: text('product_ids').notNull().default('[]'),
groupIds: text('group_ids').notNull().default('[]'),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
lastUpdated: integer('last_updated', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const productGroupInfo = sqliteTable('product_group_info', {
id: integer('id').primaryKey({ autoIncrement: true }),
groupName: text('group_name').notNull(),
description: text('description'),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const productGroupMembership = sqliteTable('product_group_membership', {
productId: integer('product_id').notNull().references(() => productInfo.id),
groupId: integer('group_id').notNull().references(() => productGroupInfo.id),
addedAt: integer('added_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
}, (t) => ({
pk: unique('product_group_membership_pk').on(t.productId, t.groupId),
}))
export const homeBanners = sqliteTable('home_banners', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name').notNull(),
imageUrl: text('image_url').notNull(),
description: text('description'),
productIds: text('product_ids'),
redirectUrl: text('redirect_url'),
serialNum: integer('serial_num'),
isActive: integer('is_active', { mode: 'boolean' }).notNull().default(false),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
lastUpdated: integer('last_updated', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const productReviews = sqliteTable('product_reviews', {
id: integer('id').primaryKey({ autoIncrement: true }),
userId: integer('user_id').notNull().references(() => users.id),
productId: integer('product_id').notNull().references(() => productInfo.id),
reviewBody: text('review_body').notNull(),
imageUrls: text('image_urls').default('[]'),
reviewTime: integer('review_time', { mode: 'timestamp' }).notNull().default(epochSeconds),
ratings: real('ratings').notNull(),
adminResponse: text('admin_response'),
adminResponseImages: text('admin_response_images').default('[]'),
}, (t) => ({
ratingCheck: check('rating_check', sql`${t.ratings} >= 1 AND ${t.ratings} <= 5`),
}))
export const uploadStatusEnum = sqliteEnum('upload_status', ['pending', 'claimed'])
export const uploadUrlStatus = sqliteTable('upload_url_status', {
id: integer('id').primaryKey({ autoIncrement: true }),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
key: text('key').notNull(),
status: uploadStatusEnum('status').notNull().default('pending'),
})
export const productTagInfo = sqliteTable('product_tag_info', {
id: integer('id').primaryKey({ autoIncrement: true }),
tagName: text('tag_name').notNull().unique(),
tagDescription: text('tag_description'),
imageUrl: text('image_url'),
isDashboardTag: integer('is_dashboard_tag', { mode: 'boolean' }).notNull().default(false),
relatedStores: text('related_stores').default('[]'),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const productTags = sqliteTable('product_tags', {
id: integer('id').primaryKey({ autoIncrement: true }),
productId: integer('product_id').notNull().references(() => productInfo.id),
tagId: integer('tag_id').notNull().references(() => productTagInfo.id),
assignedAt: integer('assigned_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
}, (t) => ({
unq_product_tag: unique('unique_product_tag').on(t.productId, t.tagId),
}))
export const deliverySlotInfo = sqliteTable('delivery_slot_info', {
id: integer('id').primaryKey({ autoIncrement: true }),
deliveryTime: integer('delivery_time', { mode: 'timestamp' }).notNull(),
freezeTime: integer('freeze_time', { mode: 'timestamp' }).notNull(),
isActive: integer('is_active', { mode: 'boolean' }).notNull().default(true),
isFlash: integer('is_flash', { mode: 'boolean' }).notNull().default(false),
isCapacityFull: integer('is_capacity_full', { mode: 'boolean' }).notNull().default(false),
deliverySequence: text('delivery_sequence').default('{}'),
groupIds: text('group_ids').default('[]'),
})
export const vendorSnippets = sqliteTable('vendor_snippets', {
id: integer('id').primaryKey({ autoIncrement: true }),
snippetCode: text('snippet_code').notNull().unique(),
slotId: integer('slot_id').references(() => deliverySlotInfo.id),
isPermanent: integer('is_permanent', { mode: 'boolean' }).notNull().default(false),
productIds: text('product_ids').notNull(),
validTill: integer('valid_till', { mode: 'timestamp' }),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const productSlots = sqliteTable('product_slots', {
productId: integer('product_id').notNull().references(() => productInfo.id),
slotId: integer('slot_id').notNull().references(() => deliverySlotInfo.id),
}, (t) => ({
pk: unique('product_slot_pk').on(t.productId, t.slotId),
}))
export const specialDeals = sqliteTable('special_deals', {
id: integer('id').primaryKey({ autoIncrement: true }),
productId: integer('product_id').notNull().references(() => productInfo.id),
quantity: text('quantity').notNull(),
price: text('price').notNull(),
validTill: integer('valid_till', { mode: 'timestamp' }).notNull(),
})
export const paymentInfoTable = sqliteTable('payment_info', {
id: integer('id').primaryKey({ autoIncrement: true }),
status: text('status').notNull(),
gateway: text('gateway').notNull(),
orderId: text('order_id'),
token: text('token'),
merchantOrderId: text('merchant_order_id').notNull().unique(),
payload: text('payload'),
})
export const orders = sqliteTable('orders', {
id: integer('id').primaryKey({ autoIncrement: true }),
userId: integer('user_id').notNull().references(() => users.id),
addressId: integer('address_id').notNull().references(() => addresses.id),
slotId: integer('slot_id').references(() => deliverySlotInfo.id),
isCod: integer('is_cod', { mode: 'boolean' }).notNull().default(false),
isOnlinePayment: integer('is_online_payment', { mode: 'boolean' }).notNull().default(false),
paymentInfoId: integer('payment_info_id').references(() => paymentInfoTable.id),
totalAmount: text('total_amount').notNull(),
deliveryCharge: text('delivery_charge').notNull().default('0'),
readableId: integer('readable_id').notNull(),
adminNotes: text('admin_notes'),
userNotes: text('user_notes'),
orderGroupId: text('order_group_id'),
orderGroupProportion: text('order_group_proportion'),
isFlashDelivery: integer('is_flash_delivery', { mode: 'boolean' }).notNull().default(false),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const orderItems = sqliteTable('order_items', {
id: integer('id').primaryKey({ autoIncrement: true }),
orderId: integer('order_id').notNull().references(() => orders.id),
productId: integer('product_id').notNull().references(() => productInfo.id),
quantity: text('quantity').notNull(),
price: text('price').notNull(),
discountedPrice: text('discounted_price'),
is_packaged: integer('is_packaged', { mode: 'boolean' }).notNull().default(false),
is_package_verified: integer('is_package_verified', { mode: 'boolean' }).notNull().default(false),
})
export const paymentStatusEnum = sqliteEnum('payment_status', [
'pending',
'success',
'cod',
'failed',
])
export const orderStatus = sqliteTable('order_status', {
id: integer('id').primaryKey({ autoIncrement: true }),
orderTime: integer('order_time', { mode: 'timestamp' }).notNull().default(epochSeconds),
userId: integer('user_id').notNull().references(() => users.id),
orderId: integer('order_id').notNull().references(() => orders.id),
isPackaged: integer('is_packaged', { mode: 'boolean' }).notNull().default(false),
isDelivered: integer('is_delivered', { mode: 'boolean' }).notNull().default(false),
isCancelled: integer('is_cancelled', { mode: 'boolean' }).notNull().default(false),
cancelReason: text('cancel_reason'),
isCancelledByAdmin: integer('is_cancelled_by_admin', { mode: 'boolean' }),
paymentStatus: paymentStatusEnum('payment_state').notNull().default('pending'),
cancellationUserNotes: text('cancellation_user_notes'),
cancellationAdminNotes: text('cancellation_admin_notes'),
cancellationReviewed: integer('cancellation_reviewed', { mode: 'boolean' }).notNull().default(false),
cancellationReviewedAt: integer('cancellation_reviewed_at', { mode: 'timestamp' }),
refundCouponId: integer('refund_coupon_id').references(() => coupons.id),
})
export const payments = sqliteTable('payments', {
id: integer('id').primaryKey({ autoIncrement: true }),
status: text('status').notNull(),
gateway: text('gateway').notNull(),
orderId: integer('order_id').notNull().references(() => orders.id),
token: text('token'),
merchantOrderId: text('merchant_order_id').notNull().unique(),
payload: text('payload'),
})
export const refunds = sqliteTable('refunds', {
id: integer('id').primaryKey({ autoIncrement: true }),
orderId: integer('order_id').notNull().references(() => orders.id),
refundAmount: text('refund_amount'),
refundStatus: text('refund_status').default('none'),
merchantRefundId: text('merchant_refund_id'),
refundProcessedAt: integer('refund_processed_at', { mode: 'timestamp' }),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const keyValStore = sqliteTable('key_val_store', {
key: text('key').primaryKey(),
value: text('value'),
})
export const notifications = sqliteTable('notifications', {
id: integer('id').primaryKey({ autoIncrement: true }),
userId: integer('user_id').notNull().references(() => users.id),
title: text('title').notNull(),
body: text('body').notNull(),
type: text('type'),
isRead: integer('is_read', { mode: 'boolean' }).notNull().default(false),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const productCategories = sqliteTable('product_categories', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name').notNull(),
description: text('description'),
})
export const cartItems = sqliteTable('cart_items', {
id: integer('id').primaryKey({ autoIncrement: true }),
userId: integer('user_id').notNull().references(() => users.id),
productId: integer('product_id').notNull().references(() => productInfo.id),
quantity: text('quantity').notNull(),
addedAt: integer('added_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
}, (t) => ({
unq_user_product: unique('unique_user_product').on(t.userId, t.productId),
}))
export const complaints = sqliteTable('complaints', {
id: integer('id').primaryKey({ autoIncrement: true }),
userId: integer('user_id').notNull().references(() => users.id),
orderId: integer('order_id').references(() => orders.id),
complaintBody: text('complaint_body').notNull(),
images: text('images'),
response: text('response'),
isResolved: integer('is_resolved', { mode: 'boolean' }).notNull().default(false),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const coupons = sqliteTable('coupons', {
id: integer('id').primaryKey({ autoIncrement: true }),
couponCode: text('coupon_code').notNull().unique('unique_coupon_code'),
isUserBased: integer('is_user_based', { mode: 'boolean' }).notNull().default(false),
discountPercent: text('discount_percent'),
flatDiscount: text('flat_discount'),
minOrder: text('min_order'),
productIds: text('product_ids'),
createdBy: integer('created_by').references(() => staffUsers.id),
maxValue: text('max_value'),
isApplyForAll: integer('is_apply_for_all', { mode: 'boolean' }).notNull().default(false),
validTill: integer('valid_till', { mode: 'timestamp' }),
maxLimitForUser: integer('max_limit_for_user'),
isInvalidated: integer('is_invalidated', { mode: 'boolean' }).notNull().default(false),
exclusiveApply: integer('exclusive_apply', { mode: 'boolean' }).notNull().default(false),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const couponUsage = sqliteTable('coupon_usage', {
id: integer('id').primaryKey({ autoIncrement: true }),
userId: integer('user_id').notNull().references(() => users.id),
couponId: integer('coupon_id').notNull().references(() => coupons.id),
orderId: integer('order_id').references(() => orders.id),
orderItemId: integer('order_item_id').references(() => orderItems.id),
usedAt: integer('used_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
})
export const couponApplicableUsers = sqliteTable('coupon_applicable_users', {
id: integer('id').primaryKey({ autoIncrement: true }),
couponId: integer('coupon_id').notNull().references(() => coupons.id),
userId: integer('user_id').notNull().references(() => users.id),
}, (t) => ({
unq_coupon_user: unique('unique_coupon_user').on(t.couponId, t.userId),
}))
export const couponApplicableProducts = sqliteTable('coupon_applicable_products', {
id: integer('id').primaryKey({ autoIncrement: true }),
couponId: integer('coupon_id').notNull().references(() => coupons.id),
productId: integer('product_id').notNull().references(() => productInfo.id),
}, (t) => ({
unq_coupon_product: unique('unique_coupon_product').on(t.couponId, t.productId),
}))
export const userIncidents = sqliteTable('user_incidents', {
id: integer('id').primaryKey({ autoIncrement: true }),
userId: integer('user_id').notNull().references(() => users.id),
orderId: integer('order_id').references(() => orders.id),
dateAdded: integer('date_added', { mode: 'timestamp' }).notNull().default(epochSeconds),
adminComment: text('admin_comment'),
addedBy: integer('added_by').references(() => staffUsers.id),
negativityScore: integer('negativity_score'),
})
export const reservedCoupons = sqliteTable('reserved_coupons', {
id: integer('id').primaryKey({ autoIncrement: true }),
secretCode: text('secret_code').notNull().unique(),
couponCode: text('coupon_code').notNull(),
discountPercent: text('discount_percent'),
flatDiscount: text('flat_discount'),
minOrder: text('min_order'),
productIds: text('product_ids'),
maxValue: text('max_value'),
validTill: integer('valid_till', { mode: 'timestamp' }),
maxLimitForUser: integer('max_limit_for_user'),
exclusiveApply: integer('exclusive_apply', { mode: 'boolean' }).notNull().default(false),
isRedeemed: integer('is_redeemed', { mode: 'boolean' }).notNull().default(false),
redeemedBy: integer('redeemed_by').references(() => users.id),
redeemedAt: integer('redeemed_at', { mode: 'timestamp' }),
createdBy: integer('created_by').notNull().references(() => staffUsers.id),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
}, (t) => ({
unq_secret_code: unique('unique_secret_code').on(t.secretCode),
}))
export const notifCreds = sqliteTable('notif_creds', {
id: integer('id').primaryKey({ autoIncrement: true }),
token: text('token').notNull().unique(),
addedAt: integer('added_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
userId: integer('user_id').notNull().references(() => users.id),
lastVerified: integer('last_verified', { mode: 'timestamp' }),
})
export const unloggedUserTokens = sqliteTable('unlogged_user_tokens', {
id: integer('id').primaryKey({ autoIncrement: true }),
token: text('token').notNull().unique(),
addedAt: integer('added_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
lastVerified: integer('last_verified', { mode: 'timestamp' }),
})
export const userNotifications = sqliteTable('user_notifications', {
id: integer('id').primaryKey({ autoIncrement: true }),
title: text('title').notNull(),
imageUrl: text('image_url'),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(epochSeconds),
body: text('body').notNull(),
applicableUsers: text('applicable_users'),
})
export const uploadUrlStatusRelations = relations(uploadUrlStatus, ({}) => ({}))
export const userCredsRelations = relations(userCreds, ({ one }) => ({
user: one(users, { fields: [userCreds.userId], references: [users.id] }),
}))
export const staffUsersRelations = relations(staffUsers, ({ one, many }) => ({
role: one(staffRoles, { fields: [staffUsers.staffRoleId], references: [staffRoles.id] }),
coupons: many(coupons),
stores: many(storeInfo),
}))
export const addressesRelations = relations(addresses, ({ one, many }) => ({
user: one(users, { fields: [addresses.userId], references: [users.id] }),
orders: many(orders),
zone: one(addressZones, { fields: [addresses.zoneId], references: [addressZones.id] }),
}))
export const unitsRelations = relations(units, ({ many }) => ({
products: many(productInfo),
}))
export const productInfoRelations = relations(productInfo, ({ one, many }) => ({
unit: one(units, { fields: [productInfo.unitId], references: [units.id] }),
store: one(storeInfo, { fields: [productInfo.storeId], references: [storeInfo.id] }),
productSlots: many(productSlots),
specialDeals: many(specialDeals),
orderItems: many(orderItems),
cartItems: many(cartItems),
tags: many(productTags),
applicableCoupons: many(couponApplicableProducts),
reviews: many(productReviews),
groups: many(productGroupMembership),
}))
export const productTagInfoRelations = relations(productTagInfo, ({ many }) => ({
products: many(productTags),
}))
export const productTagsRelations = relations(productTags, ({ one }) => ({
product: one(productInfo, { fields: [productTags.productId], references: [productInfo.id] }),
tag: one(productTagInfo, { fields: [productTags.tagId], references: [productTagInfo.id] }),
}))
export const deliverySlotInfoRelations = relations(deliverySlotInfo, ({ many }) => ({
productSlots: many(productSlots),
orders: many(orders),
vendorSnippets: many(vendorSnippets),
}))
export const vendorSnippetsRelations = relations(vendorSnippets, ({ one }) => ({
slot: one(deliverySlotInfo, { fields: [vendorSnippets.slotId], references: [deliverySlotInfo.id] }),
}))
export const productSlotsRelations = relations(productSlots, ({ one }) => ({
product: one(productInfo, { fields: [productSlots.productId], references: [productInfo.id] }),
slot: one(deliverySlotInfo, { fields: [productSlots.slotId], references: [deliverySlotInfo.id] }),
}))
export const specialDealsRelations = relations(specialDeals, ({ one }) => ({
product: one(productInfo, { fields: [specialDeals.productId], references: [productInfo.id] }),
}))
export const ordersRelations = relations(orders, ({ one, many }) => ({
user: one(users, { fields: [orders.userId], references: [users.id] }),
address: one(addresses, { fields: [orders.addressId], references: [addresses.id] }),
slot: one(deliverySlotInfo, { fields: [orders.slotId], references: [deliverySlotInfo.id] }),
orderItems: many(orderItems),
payment: one(payments),
paymentInfo: one(paymentInfoTable, { fields: [orders.paymentInfoId], references: [paymentInfoTable.id] }),
orderStatus: many(orderStatus),
refunds: many(refunds),
couponUsages: many(couponUsage),
userIncidents: many(userIncidents),
}))
export const orderItemsRelations = relations(orderItems, ({ one }) => ({
order: one(orders, { fields: [orderItems.orderId], references: [orders.id] }),
product: one(productInfo, { fields: [orderItems.productId], references: [productInfo.id] }),
}))
export const orderStatusRelations = relations(orderStatus, ({ one }) => ({
order: one(orders, { fields: [orderStatus.orderId], references: [orders.id] }),
user: one(users, { fields: [orderStatus.userId], references: [users.id] }),
refundCoupon: one(coupons, { fields: [orderStatus.refundCouponId], references: [coupons.id] }),
}))
export const paymentInfoRelations = relations(paymentInfoTable, ({ one }) => ({
order: one(orders, { fields: [paymentInfoTable.id], references: [orders.paymentInfoId] }),
}))
export const paymentsRelations = relations(payments, ({ one }) => ({
order: one(orders, { fields: [payments.orderId], references: [orders.id] }),
}))
export const refundsRelations = relations(refunds, ({ one }) => ({
order: one(orders, { fields: [refunds.orderId], references: [orders.id] }),
}))
export const notificationsRelations = relations(notifications, ({ one }) => ({
user: one(users, { fields: [notifications.userId], references: [users.id] }),
}))
export const productCategoriesRelations = relations(productCategories, ({}) => ({}))
export const cartItemsRelations = relations(cartItems, ({ one }) => ({
user: one(users, { fields: [cartItems.userId], references: [users.id] }),
product: one(productInfo, { fields: [cartItems.productId], references: [productInfo.id] }),
}))
export const complaintsRelations = relations(complaints, ({ one }) => ({
user: one(users, { fields: [complaints.userId], references: [users.id] }),
order: one(orders, { fields: [complaints.orderId], references: [orders.id] }),
}))
export const couponsRelations = relations(coupons, ({ one, many }) => ({
creator: one(staffUsers, { fields: [coupons.createdBy], references: [staffUsers.id] }),
usages: many(couponUsage),
applicableUsers: many(couponApplicableUsers),
applicableProducts: many(couponApplicableProducts),
}))
export const couponUsageRelations = relations(couponUsage, ({ one }) => ({
user: one(users, { fields: [couponUsage.userId], references: [users.id] }),
coupon: one(coupons, { fields: [couponUsage.couponId], references: [coupons.id] }),
order: one(orders, { fields: [couponUsage.orderId], references: [orders.id] }),
orderItem: one(orderItems, { fields: [couponUsage.orderItemId], references: [orderItems.id] }),
}))
export const userDetailsRelations = relations(userDetails, ({ one }) => ({
user: one(users, { fields: [userDetails.userId], references: [users.id] }),
}))
export const notifCredsRelations = relations(notifCreds, ({ one }) => ({
user: one(users, { fields: [notifCreds.userId], references: [users.id] }),
}))
export const userNotificationsRelations = relations(userNotifications, ({}) => ({}))
export const storeInfoRelations = relations(storeInfo, ({ one, many }) => ({
owner: one(staffUsers, { fields: [storeInfo.owner], references: [staffUsers.id] }),
products: many(productInfo),
}))
export const couponApplicableUsersRelations = relations(couponApplicableUsers, ({ one }) => ({
coupon: one(coupons, { fields: [couponApplicableUsers.couponId], references: [coupons.id] }),
user: one(users, { fields: [couponApplicableUsers.userId], references: [users.id] }),
}))
export const couponApplicableProductsRelations = relations(couponApplicableProducts, ({ one }) => ({
coupon: one(coupons, { fields: [couponApplicableProducts.couponId], references: [coupons.id] }),
product: one(productInfo, { fields: [couponApplicableProducts.productId], references: [productInfo.id] }),
}))
export const reservedCouponsRelations = relations(reservedCoupons, ({ one }) => ({
redeemedUser: one(users, { fields: [reservedCoupons.redeemedBy], references: [users.id] }),
creator: one(staffUsers, { fields: [reservedCoupons.createdBy], references: [staffUsers.id] }),
}))
export const productReviewsRelations = relations(productReviews, ({ one }) => ({
user: one(users, { fields: [productReviews.userId], references: [users.id] }),
product: one(productInfo, { fields: [productReviews.productId], references: [productInfo.id] }),
}))
export const addressZonesRelations = relations(addressZones, ({ many }) => ({
addresses: many(addresses),
areas: many(addressAreas),
}))
export const addressAreasRelations = relations(addressAreas, ({ one }) => ({
zone: one(addressZones, { fields: [addressAreas.zoneId], references: [addressZones.id] }),
}))
export const productGroupInfoRelations = relations(productGroupInfo, ({ many }) => ({
memberships: many(productGroupMembership),
}))
export const productGroupMembershipRelations = relations(productGroupMembership, ({ one }) => ({
product: one(productInfo, { fields: [productGroupMembership.productId], references: [productInfo.id] }),
group: one(productGroupInfo, { fields: [productGroupMembership.groupId], references: [productGroupInfo.id] }),
}))
export const homeBannersRelations = relations(homeBanners, ({}) => ({}))
export const staffRolesRelations = relations(staffRoles, ({ many }) => ({
staffUsers: many(staffUsers),
rolePermissions: many(staffRolePermissions),
}))
export const staffPermissionsRelations = relations(staffPermissions, ({ many }) => ({
rolePermissions: many(staffRolePermissions),
}))
export const staffRolePermissionsRelations = relations(staffRolePermissions, ({ one }) => ({
role: one(staffRoles, { fields: [staffRolePermissions.staffRoleId], references: [staffRoles.id] }),
permission: one(staffPermissions, { fields: [staffRolePermissions.staffPermissionId], references: [staffPermissions.id] }),
}))
export const userIncidentsRelations = relations(userIncidents, ({ one }) => ({
user: one(users, { fields: [userIncidents.userId], references: [users.id] }),
order: one(orders, { fields: [userIncidents.orderId], references: [orders.id] }),
addedBy: one(staffUsers, { fields: [userIncidents.addedBy], references: [staffUsers.id] }),
}))
export const productAvailabilitySchedulesRelations = relations(
productAvailabilitySchedules,
({}) => ({})
)
export const usersRelations = relations(users, ({ many, one }) => ({
addresses: many(addresses),
orders: many(orders),
notifications: many(notifications),
cartItems: many(cartItems),
userCreds: one(userCreds),
coupons: many(coupons),
couponUsages: many(couponUsage),
applicableCoupons: many(couponApplicableUsers),
userDetails: one(userDetails),
notifCreds: many(notifCreds),
userIncidents: many(userIncidents),
}))

View file

@ -1,138 +1,8 @@
import { db } from "@/src/db/db_index" import { seed as seedPostgres } from '@db-helper-postgres/db/seed'
import { units, productInfo, deliverySlotInfo, productSlots, keyValStore, staffRoles, staffPermissions, staffRolePermissions } from "@/src/db/schema" import { seed as seedSqlite } from '@db-helper-sqlite/db/seed'
import { eq } from "drizzle-orm";
import { minOrderValue, deliveryCharge } from '@/src/lib/env-exporter'
import { CONST_KEYS } from '@/src/lib/const-keys'
export async function seed() { const dialect = process.env.DB_DIALECT || DB_DIALECT_TYPE
console.log("Seeding database...");
// Seed units individually const seedImpl = dialect === 'sqlite' ? seedSqlite : seedPostgres
const unitsToSeed = [
{ shortNotation: "Kg", fullName: "Kilogram" },
{ shortNotation: "L", fullName: "Litre" },
{ shortNotation: "Dz", fullName: "Dozen" },
{ shortNotation: "Pc", fullName: "Unit Piece" },
];
for (const unit of unitsToSeed) { export const seed = async () => seedImpl()
const existingUnit = await db.query.units.findFirst({
where: eq(units.shortNotation, unit.shortNotation),
});
if (!existingUnit) {
await db.insert(units).values(unit);
}
}
// Seed staff roles individually
const rolesToSeed = ['super_admin', 'admin', 'marketer', 'delivery_staff'] as const;
for (const roleName of rolesToSeed) {
const existingRole = await db.query.staffRoles.findFirst({
where: eq(staffRoles.roleName, roleName),
});
if (!existingRole) {
await db.insert(staffRoles).values({ roleName });
}
}
// Seed staff permissions individually
const permissionsToSeed = ['crud_product', 'make_coupon', 'crud_staff_users'] as const;
for (const permissionName of permissionsToSeed) {
const existingPermission = await db.query.staffPermissions.findFirst({
where: eq(staffPermissions.permissionName, permissionName),
});
if (!existingPermission) {
await db.insert(staffPermissions).values({ permissionName });
}
}
// Seed role-permission assignments
await db.transaction(async (tx) => {
// Get role IDs
const superAdminRole = await tx.query.staffRoles.findFirst({ where: eq(staffRoles.roleName, 'super_admin') });
const adminRole = await tx.query.staffRoles.findFirst({ where: eq(staffRoles.roleName, 'admin') });
const marketerRole = await tx.query.staffRoles.findFirst({ where: eq(staffRoles.roleName, 'marketer') });
// Get permission IDs
const crudProductPerm = await tx.query.staffPermissions.findFirst({ where: eq(staffPermissions.permissionName, 'crud_product') });
const makeCouponPerm = await tx.query.staffPermissions.findFirst({ where: eq(staffPermissions.permissionName, 'make_coupon') });
const crudStaffUsersPerm = await tx.query.staffPermissions.findFirst({ where: eq(staffPermissions.permissionName, 'crud_staff_users') });
// Assign all permissions to super_admin
[crudProductPerm, makeCouponPerm, crudStaffUsersPerm].forEach(async (perm) => {
if (superAdminRole && perm) {
const existingSuperAdminPerm = await tx.query.staffRolePermissions.findFirst({
where: eq(staffRolePermissions.staffRoleId, superAdminRole.id) && eq(staffRolePermissions.staffPermissionId, perm.id),
});
if (!existingSuperAdminPerm) {
await tx.insert(staffRolePermissions).values({
staffRoleId: superAdminRole.id,
staffPermissionId: perm.id,
});
}
}
});
// Assign all permissions to admin
[crudProductPerm, makeCouponPerm].forEach(async (perm) => {
if (adminRole && perm) {
const existingAdminPerm = await tx.query.staffRolePermissions.findFirst({
where: eq(staffRolePermissions.staffRoleId, adminRole.id) && eq(staffRolePermissions.staffPermissionId, perm.id),
});
if (!existingAdminPerm) {
await tx.insert(staffRolePermissions).values({
staffRoleId: adminRole.id,
staffPermissionId: perm.id,
});
}
}
});
// Assign make_coupon to marketer
if (marketerRole && makeCouponPerm) {
const existingMarketerCoupon = await tx.query.staffRolePermissions.findFirst({
where: eq(staffRolePermissions.staffRoleId, marketerRole.id) && eq(staffRolePermissions.staffPermissionId, makeCouponPerm.id),
});
if (!existingMarketerCoupon) {
await tx.insert(staffRolePermissions).values({
staffRoleId: marketerRole.id,
staffPermissionId: makeCouponPerm.id,
});
}
}
});
// Seed key-val store constants using CONST_KEYS
const constantsToSeed = [
{ key: CONST_KEYS.readableOrderId, value: 0 },
{ key: CONST_KEYS.minRegularOrderValue, value: minOrderValue },
{ key: CONST_KEYS.freeDeliveryThreshold, value: minOrderValue },
{ key: CONST_KEYS.deliveryCharge, value: deliveryCharge },
{ key: CONST_KEYS.flashFreeDeliveryThreshold, value: 500 },
{ key: CONST_KEYS.flashDeliveryCharge, value: 69 },
{ key: CONST_KEYS.popularItems, value: [] },
{ key: CONST_KEYS.allItemsOrder, value: [] },
{ key: CONST_KEYS.versionNum, value: '1.1.0' },
{ key: CONST_KEYS.playStoreUrl, value: 'https://play.google.com/store/apps/details?id=in.freshyo.app' },
{ key: CONST_KEYS.appStoreUrl, value: 'https://apps.apple.com/in/app/freshyo/id6756889077' },
{ key: CONST_KEYS.isFlashDeliveryEnabled, value: false },
{ key: CONST_KEYS.supportMobile, value: '8688182552' },
{ key: CONST_KEYS.supportEmail, value: 'qushammohd@gmail.com' },
];
for (const constant of constantsToSeed) {
const existing = await db.query.keyValStore.findFirst({
where: eq(keyValStore.key, constant.key),
});
if (!existing) {
await db.insert(keyValStore).values({
key: constant.key,
value: constant.value,
});
}
}
console.log("Seeding completed.");
}

View file

@ -1,34 +1 @@
export const parseJsonValue = <T>(value: unknown, fallback: T): T => { export * from '@/db-helper-sqlite/db/sqlite-casts'
if (value === null || value === undefined) return fallback
if (typeof value === 'string') {
try {
return JSON.parse(value) as T
} catch {
return fallback
}
}
return value as T
}
export const parseNumberArray = (value: unknown): number[] => {
const parsed = parseJsonValue<unknown[]>(value, [])
return parsed
.map((item) => Number(item))
.filter((item) => !Number.isNaN(item))
}
export const toJsonString = (value: unknown, fallback: string): string => {
if (value === null || value === undefined) return fallback
if (typeof value === 'string') return value
return JSON.stringify(value)
}
export const toEpochSeconds = (value: Date | number): number => {
if (typeof value === 'number') return value
return Math.floor(value.getTime() / 1000)
}
export const fromEpochSeconds = (value: number | null | undefined): Date | null => {
if (value === null || value === undefined) return null
return new Date(value * 1000)
}

View file

@ -1,47 +1,58 @@
import type { InferSelectModel } from "drizzle-orm";
import type { import type {
users, User as PostgresUser,
addresses, Address as PostgresAddress,
units, Unit as PostgresUnit,
productInfo, ProductInfo as PostgresProductInfo,
deliverySlotInfo, DeliverySlotInfo as PostgresDeliverySlotInfo,
productSlots, ProductSlot as PostgresProductSlot,
specialDeals, SpecialDeal as PostgresSpecialDeal,
orders, Order as PostgresOrder,
orderItems, OrderItem as PostgresOrderItem,
payments, Payment as PostgresPayment,
notifications, Notification as PostgresNotification,
productCategories, ProductCategory as PostgresProductCategory,
cartItems, CartItem as PostgresCartItem,
coupons, Coupon as PostgresCoupon,
} from "@/src/db/schema"; ProductWithUnit as PostgresProductWithUnit,
OrderWithItems as PostgresOrderWithItems,
CartItemWithProduct as PostgresCartItemWithProduct,
} from '@db-helper-postgres/db/types'
import type {
User as SqliteUser,
Address as SqliteAddress,
Unit as SqliteUnit,
ProductInfo as SqliteProductInfo,
DeliverySlotInfo as SqliteDeliverySlotInfo,
ProductSlot as SqliteProductSlot,
SpecialDeal as SqliteSpecialDeal,
Order as SqliteOrder,
OrderItem as SqliteOrderItem,
Payment as SqlitePayment,
Notification as SqliteNotification,
ProductCategory as SqliteProductCategory,
CartItem as SqliteCartItem,
Coupon as SqliteCoupon,
ProductWithUnit as SqliteProductWithUnit,
OrderWithItems as SqliteOrderWithItems,
CartItemWithProduct as SqliteCartItemWithProduct,
} from '@db-helper-sqlite/db/types'
export type User = InferSelectModel<typeof users>; type UseSqlite = typeof DB_DIALECT_TYPE extends 'sqlite' ? true : false
export type Address = InferSelectModel<typeof addresses>;
export type Unit = InferSelectModel<typeof units>;
export type ProductInfo = InferSelectModel<typeof productInfo>;
export type DeliverySlotInfo = InferSelectModel<typeof deliverySlotInfo>;
export type ProductSlot = InferSelectModel<typeof productSlots>;
export type SpecialDeal = InferSelectModel<typeof specialDeals>;
export type Order = InferSelectModel<typeof orders>;
export type OrderItem = InferSelectModel<typeof orderItems>;
export type Payment = InferSelectModel<typeof payments>;
export type Notification = InferSelectModel<typeof notifications>;
export type ProductCategory = InferSelectModel<typeof productCategories>;
export type CartItem = InferSelectModel<typeof cartItems>;
export type Coupon = InferSelectModel<typeof coupons>;
// Combined types export type User = UseSqlite extends true ? SqliteUser : PostgresUser
export type ProductWithUnit = ProductInfo & { export type Address = UseSqlite extends true ? SqliteAddress : PostgresAddress
unit: Unit; export type Unit = UseSqlite extends true ? SqliteUnit : PostgresUnit
}; export type ProductInfo = UseSqlite extends true ? SqliteProductInfo : PostgresProductInfo
export type DeliverySlotInfo = UseSqlite extends true ? SqliteDeliverySlotInfo : PostgresDeliverySlotInfo
export type OrderWithItems = Order & { export type ProductSlot = UseSqlite extends true ? SqliteProductSlot : PostgresProductSlot
items: (OrderItem & { product: ProductInfo })[]; export type SpecialDeal = UseSqlite extends true ? SqliteSpecialDeal : PostgresSpecialDeal
address: Address; export type Order = UseSqlite extends true ? SqliteOrder : PostgresOrder
slot: DeliverySlotInfo; export type OrderItem = UseSqlite extends true ? SqliteOrderItem : PostgresOrderItem
}; export type Payment = UseSqlite extends true ? SqlitePayment : PostgresPayment
export type Notification = UseSqlite extends true ? SqliteNotification : PostgresNotification
export type CartItemWithProduct = CartItem & { export type ProductCategory = UseSqlite extends true ? SqliteProductCategory : PostgresProductCategory
product: ProductInfo; export type CartItem = UseSqlite extends true ? SqliteCartItem : PostgresCartItem
}; export type Coupon = UseSqlite extends true ? SqliteCoupon : PostgresCoupon
export type ProductWithUnit = UseSqlite extends true ? SqliteProductWithUnit : PostgresProductWithUnit
export type OrderWithItems = UseSqlite extends true ? SqliteOrderWithItems : PostgresOrderWithItems
export type CartItemWithProduct = UseSqlite extends true ? SqliteCartItemWithProduct : PostgresCartItemWithProduct

View file

@ -0,0 +1,14 @@
import { claimUploadUrlStatus as claimUploadUrlStatusPostgres, createUploadUrlStatus as createUploadUrlStatusPostgres } from '@db-helper-postgres/lib/upload-url'
import { claimUploadUrlStatus as claimUploadUrlStatusSqlite, createUploadUrlStatus as createUploadUrlStatusSqlite } from '@db-helper-sqlite/lib/upload-url'
const dialect = process.env.DB_DIALECT || DB_DIALECT_TYPE
const createUploadUrlStatus = dialect === 'sqlite'
? createUploadUrlStatusSqlite
: createUploadUrlStatusPostgres
const claimUploadUrlStatus = dialect === 'sqlite'
? claimUploadUrlStatusSqlite
: claimUploadUrlStatusPostgres
export { claimUploadUrlStatus, createUploadUrlStatus }

View file

@ -1,56 +1,54 @@
import { eq } from "drizzle-orm"; import { deleteImageUtil, getOriginalUrlFromSignedUrl } from '@/src/lib/s3-client'
import { db } from "@/src/db/db_index" import { assetsDomain, s3Url } from '@/src/lib/env-exporter'
import { deleteImageUtil, getOriginalUrlFromSignedUrl } from "@/src/lib/s3-client"
import { assetsDomain, s3Url } from "@/src/lib/env-exporter"
function extractS3Key(url: string): string | null { function extractS3Key(url: string): string | null {
try { try {
// Check if this is a signed URL first and get the original if it is // Check if this is a signed URL first and get the original if it is
const originalUrl = getOriginalUrlFromSignedUrl(url) || url; const originalUrl = getOriginalUrlFromSignedUrl(url) || url
// Find the index of '.com/' in the URL // Find the index of '.com/' in the URL
// const comIndex = originalUrl.indexOf(".com/"); // const comIndex = originalUrl.indexOf(".com/");
const baseUrlIndex = originalUrl.indexOf(s3Url); const baseUrlIndex = originalUrl.indexOf(s3Url)
// If '.com/' is found, return everything after it // If '.com/' is found, return everything after it
if (baseUrlIndex !== -1) { if (baseUrlIndex !== -1) {
return originalUrl.substring(baseUrlIndex + s3Url.length); // +5 to skip '.com/' return originalUrl.substring(baseUrlIndex + s3Url.length) // +5 to skip '.com/'
} }
} catch (error) { } catch (error) {
console.error("Error extracting key from URL:", error); console.error('Error extracting key from URL:', error)
} }
// Return null if the pattern isn't found or there was an error // Return null if the pattern isn't found or there was an error
return null; return null
} }
export async function deleteS3Image(imageUrl: string) { export async function deleteS3Image(imageUrl: string) {
try { try {
let key:string | null = ''; let key: string | null = ''
if (imageUrl.includes(assetsDomain)) { if (imageUrl.includes(assetsDomain)) {
key = imageUrl.replace(assetsDomain, '') key = imageUrl.replace(assetsDomain, '')
} }
else if (imageUrl.startsWith('http')) { else if (imageUrl.startsWith('http')) {
// First check if this is a signed URL and get the original if it is // First check if this is a signed URL and get the original if it is
const originalUrl = getOriginalUrlFromSignedUrl(imageUrl) || imageUrl; const originalUrl = getOriginalUrlFromSignedUrl(imageUrl) || imageUrl
key = extractS3Key(originalUrl || ""); key = extractS3Key(originalUrl || '')
} }
else { else {
key = imageUrl; key = imageUrl
} }
if (!key) { if (!key) {
throw new Error("Invalid image URL format"); throw new Error('Invalid image URL format')
} }
const deleteS3 = await deleteImageUtil({keys: [key] }); const deleteS3 = await deleteImageUtil({ keys: [key] })
if (!deleteS3) { if (!deleteS3) {
throw new Error("Failed to delete image from S3"); throw new Error('Failed to delete image from S3')
} }
} catch (error) { } catch (error) {
console.error("Error deleting image from S3:", error); console.error('Error deleting image from S3:', error)
} }
} }

View file

@ -1,7 +1,5 @@
import { db } from "@/src/db/db_index" import { sendPushNotificationsMany } from '@/src/lib/expo-service'
import { sendPushNotificationsMany } from "@/src/lib/expo-service"
// import { usersTable, notifCredsTable, notificationTable } from "@/src/db/schema"; // import { usersTable, notifCredsTable, notificationTable } from "@/src/db/schema";
import { eq, inArray } from "drizzle-orm";
// Core notification dispatch methods (renamed for clarity) // Core notification dispatch methods (renamed for clarity)
export async function dispatchBulkNotification({ export async function dispatchBulkNotification({

View file

@ -1,5 +1,3 @@
import { db } from "@/src/db/db_index"
/** /**
* Constants for role names to avoid hardcoding and typos * Constants for role names to avoid hardcoding and typos
*/ */

View file

@ -3,9 +3,7 @@ import { DeleteObjectCommand, DeleteObjectsCommand, PutObjectCommand, S3Client,
import { getSignedUrl } from "@aws-sdk/s3-request-presigner" import { getSignedUrl } from "@aws-sdk/s3-request-presigner"
import signedUrlCache from "@/src/lib/signed-url-cache" import signedUrlCache from "@/src/lib/signed-url-cache"
import { s3AccessKeyId, s3Region, s3Url, s3SecretAccessKey, s3BucketName, assetsDomain } from "@/src/lib/env-exporter" import { s3AccessKeyId, s3Region, s3Url, s3SecretAccessKey, s3BucketName, assetsDomain } from "@/src/lib/env-exporter"
import { db } from "@/src/db/db_index"; // Adjust path if needed import { claimUploadUrlStatus, createUploadUrlStatus } from '@/src/db/upload-url'
import { uploadUrlStatus } from "@/src/db/schema"
import { and, eq } from 'drizzle-orm';
const s3Client = new S3Client({ const s3Client = new S3Client({
region: s3Region, region: s3Region,
@ -161,10 +159,7 @@ export async function generateSignedUrlsFromS3Urls(s3Urls: (string|null)[], expi
export async function generateUploadUrl(key: string, mimeType: string, expiresIn: number = 180): Promise<string> { export async function generateUploadUrl(key: string, mimeType: string, expiresIn: number = 180): Promise<string> {
try { try {
// Insert record into upload_url_status // Insert record into upload_url_status
await db.insert(uploadUrlStatus).values({ await createUploadUrlStatus(key)
key: key,
status: 'pending',
});
// Generate signed upload URL // Generate signed upload URL
const command = new PutObjectCommand({ const command = new PutObjectCommand({
@ -207,16 +202,7 @@ export async function claimUploadUrl(url: string): Promise<void> {
semiKey = extractKeyFromPresignedUrl(url); semiKey = extractKeyFromPresignedUrl(url);
else else
semiKey = url semiKey = url
// Update status to 'claimed' if currently 'pending' await claimUploadUrlStatus(semiKey)
const result = await db
.update(uploadUrlStatus)
.set({ status: 'claimed' })
.where(and(eq(uploadUrlStatus.key, semiKey), eq(uploadUrlStatus.status, 'pending')))
.returning();
if (result.length === 0) {
throw new Error('Upload URL not found or already claimed');
}
} catch (error) { } catch (error) {
console.error('Error claiming upload URL:', error); console.error('Error claiming upload URL:', error);
throw new Error('Failed to claim upload URL'); throw new Error('Failed to claim upload URL');

View file

@ -1,55 +1,60 @@
export type { IBannerDbService, Banner, NewBanner } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/banner-db-service.interface' export type { IBannerDbService, Banner, NewBanner } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/banner-db-service.interface'
// export { bannerDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/postgres/banner-queries'
export { bannerDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/sqlite/banner-queries'
export type { IComplaintDbService, Complaint, NewComplaint } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/complaint-db-service.interface' export type { IComplaintDbService, Complaint, NewComplaint } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/complaint-db-service.interface'
// export { complaintDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/postgres/complaint-queries'
export { complaintDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/sqlite/complaint-queries'
export type { IConstantDbService, Constant, NewConstant } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/constant-db-service.interface' export type { IConstantDbService, Constant, NewConstant } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/constant-db-service.interface'
// export { constantDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/postgres/constant-queries'
export { constantDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/sqlite/constant-queries'
export type { ICouponDbService, Coupon, NewCoupon, ReservedCoupon, NewReservedCoupon, CouponWithRelations } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/coupon-db-service.interface' export type { ICouponDbService, Coupon, NewCoupon, ReservedCoupon, NewReservedCoupon, CouponWithRelations } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/coupon-db-service.interface'
// export { couponDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/postgres/coupon-queries'
export { couponDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/sqlite/coupon-queries'
export type { IOrderDbService, Order, OrderItem, OrderStatus, OrderWithRelations, OrderWithStatus, OrderWithCouponUsages } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/order-db-service.interface' export type { IOrderDbService, Order, OrderItem, OrderStatus, OrderWithRelations, OrderWithStatus, OrderWithCouponUsages } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/order-db-service.interface'
// export { orderDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/postgres/order-queries'
export { orderDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/sqlite/order-queries'
export type { IProductDbService, Product, NewProduct, ProductGroup, NewProductGroup } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/product-db-service.interface' export type { IProductDbService, Product, NewProduct, ProductGroup, NewProductGroup } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/product-db-service.interface'
// export { productDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/postgres/product-queries'
export { productDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/sqlite/product-queries'
export type { IRefundDbService, Refund, NewRefund } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/refund-db-service.interface' export type { IRefundDbService, Refund, NewRefund } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/refund-db-service.interface'
// export { refundDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/postgres/refund-queries'
export { refundDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/sqlite/refund-queries'
export type { IScheduleDbService, Schedule, NewSchedule } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/schedule-db-service.interface' export type { IScheduleDbService, Schedule, NewSchedule } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/schedule-db-service.interface'
// export { scheduleDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/postgres/schedule-queries'
export { scheduleDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/sqlite/schedule-queries'
export type { ISlotDbService, Slot, NewSlot, ProductSlot, NewProductSlot, SlotWithRelations } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/slot-db-service.interface' export type { ISlotDbService, Slot, NewSlot, ProductSlot, NewProductSlot, SlotWithRelations } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/slot-db-service.interface'
// export { slotDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/postgres/slot-queries'
export { slotDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/sqlite/slot-queries'
export type { IStaffUserDbService, StaffUser, NewStaffUser, StaffRole, StaffUserWithRole } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/staff-user-db-service.interface' export type { IStaffUserDbService, StaffUser, NewStaffUser, StaffRole, StaffUserWithRole } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/staff-user-db-service.interface'
// export { staffUserDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/postgres/staff-user-queries'
export { staffUserDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/sqlite/staff-user-queries'
export type { IStoreDbService, Store, NewStore } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/store-db-service.interface' export type { IStoreDbService, Store, NewStore } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/store-db-service.interface'
// export { storeDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/postgres/store-queries'
export { storeDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/sqlite/store-queries'
export type { ITagDbService, Tag, NewTag } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/tag-db-service.interface' export type { ITagDbService, Tag, NewTag } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/tag-db-service.interface'
// export { tagDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/postgres/tag-queries'
export { tagDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/sqlite/tag-queries'
export type { IUserDbService, User, NewUser, UserDetail } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/user-db-service.interface' export type { IUserDbService, User, NewUser, UserDetail } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/user-db-service.interface'
// export { userDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/postgres/user-queries'
export { userDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/sqlite/user-queries'
export type { IVendorSnippetDbService, VendorSnippet, NewVendorSnippet } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/vendor-snippet-db-service.interface' export type { IVendorSnippetDbService, VendorSnippet, NewVendorSnippet } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/vendor-snippet-db-service.interface'
// export { vendorSnippetDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/postgres/vendor-snippets-queries'
export { vendorSnippetDbService } from '@/src/trpc/apis/admin-apis/dataAccessors/sqlite/vendor-snippets-queries' import { bannerDbService as sqliteBannerDbService } from '@db-helper-sqlite/dataAccessors/admin-apis/banner-queries'
import { bannerDbService as postgresBannerDbService } from '@db-helper-postgres/dataAccessors/admin-apis/banner-queries'
import { complaintDbService as sqliteComplaintDbService } from '@db-helper-sqlite/dataAccessors/admin-apis/complaint-queries'
import { complaintDbService as postgresComplaintDbService } from '@db-helper-postgres/dataAccessors/admin-apis/complaint-queries'
import { constantDbService as sqliteConstantDbService } from '@db-helper-sqlite/dataAccessors/admin-apis/constant-queries'
import { constantDbService as postgresConstantDbService } from '@db-helper-postgres/dataAccessors/admin-apis/constant-queries'
import { couponDbService as sqliteCouponDbService } from '@db-helper-sqlite/dataAccessors/admin-apis/coupon-queries'
import { couponDbService as postgresCouponDbService } from '@db-helper-postgres/dataAccessors/admin-apis/coupon-queries'
import { orderDbService as sqliteOrderDbService } from '@db-helper-sqlite/dataAccessors/admin-apis/order-queries'
import { orderDbService as postgresOrderDbService } from '@db-helper-postgres/dataAccessors/admin-apis/order-queries'
import { productDbService as sqliteProductDbService } from '@db-helper-sqlite/dataAccessors/admin-apis/product-queries'
import { productDbService as postgresProductDbService } from '@db-helper-postgres/dataAccessors/admin-apis/product-queries'
import { refundDbService as sqliteRefundDbService } from '@db-helper-sqlite/dataAccessors/admin-apis/refund-queries'
import { refundDbService as postgresRefundDbService } from '@db-helper-postgres/dataAccessors/admin-apis/refund-queries'
import { scheduleDbService as sqliteScheduleDbService } from '@db-helper-sqlite/dataAccessors/admin-apis/schedule-queries'
import { scheduleDbService as postgresScheduleDbService } from '@db-helper-postgres/dataAccessors/admin-apis/schedule-queries'
import { slotDbService as sqliteSlotDbService } from '@db-helper-sqlite/dataAccessors/admin-apis/slot-queries'
import { slotDbService as postgresSlotDbService } from '@db-helper-postgres/dataAccessors/admin-apis/slot-queries'
import { staffUserDbService as sqliteStaffUserDbService } from '@db-helper-sqlite/dataAccessors/admin-apis/staff-user-queries'
import { staffUserDbService as postgresStaffUserDbService } from '@db-helper-postgres/dataAccessors/admin-apis/staff-user-queries'
import { storeDbService as sqliteStoreDbService } from '@db-helper-sqlite/dataAccessors/admin-apis/store-queries'
import { storeDbService as postgresStoreDbService } from '@db-helper-postgres/dataAccessors/admin-apis/store-queries'
import { tagDbService as sqliteTagDbService } from '@db-helper-sqlite/dataAccessors/admin-apis/tag-queries'
import { tagDbService as postgresTagDbService } from '@db-helper-postgres/dataAccessors/admin-apis/tag-queries'
import { userDbService as sqliteUserDbService } from '@db-helper-sqlite/dataAccessors/admin-apis/user-queries'
import { userDbService as postgresUserDbService } from '@db-helper-postgres/dataAccessors/admin-apis/user-queries'
import { vendorSnippetDbService as sqliteVendorSnippetDbService } from '@db-helper-sqlite/dataAccessors/admin-apis/vendor-snippets-queries'
import { vendorSnippetDbService as postgresVendorSnippetDbService } from '@db-helper-postgres/dataAccessors/admin-apis/vendor-snippets-queries'
const isSqlite = process.env.DB_DIALECT === 'sqlite'
export const bannerDbService = isSqlite ? sqliteBannerDbService : postgresBannerDbService
export const complaintDbService = isSqlite ? sqliteComplaintDbService : postgresComplaintDbService
export const constantDbService = isSqlite ? sqliteConstantDbService : postgresConstantDbService
export const couponDbService = isSqlite ? sqliteCouponDbService : postgresCouponDbService
export const orderDbService = isSqlite ? sqliteOrderDbService : postgresOrderDbService
export const productDbService = isSqlite ? sqliteProductDbService : postgresProductDbService
export const refundDbService = isSqlite ? sqliteRefundDbService : postgresRefundDbService
export const scheduleDbService = isSqlite ? sqliteScheduleDbService : postgresScheduleDbService
export const slotDbService = isSqlite ? sqliteSlotDbService : postgresSlotDbService
export const staffUserDbService = isSqlite ? sqliteStaffUserDbService : postgresStaffUserDbService
export const storeDbService = isSqlite ? sqliteStoreDbService : postgresStoreDbService
export const tagDbService = isSqlite ? sqliteTagDbService : postgresTagDbService
export const userDbService = isSqlite ? sqliteUserDbService : postgresUserDbService
export const vendorSnippetDbService = isSqlite ? sqliteVendorSnippetDbService : postgresVendorSnippetDbService

View file

@ -1,43 +1,48 @@
export type { IUserBannerDbService, UserBanner } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-banner-db-service.interface' export type { IUserBannerDbService, UserBanner } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-banner-db-service.interface'
// export { userBannerDbService } from '@/src/trpc/apis/user-apis/dataAccessors/postgres/user-banner-queries'
export { userBannerDbService } from '@/src/trpc/apis/user-apis/dataAccessors/sqlite/user-banner-queries'
export type { IUserStoreDbService, Store as UserStore, StoreBasic } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-store-db-service.interface' export type { IUserStoreDbService, Store as UserStore, StoreBasic } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-store-db-service.interface'
// export { userStoreDbService } from '@/src/trpc/apis/user-apis/dataAccessors/postgres/user-store-queries'
export { userStoreDbService } from '@/src/trpc/apis/user-apis/dataAccessors/sqlite/user-store-queries'
export type { IUserAddressDbService, Address, NewAddress } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-address-db-service.interface' export type { IUserAddressDbService, Address, NewAddress } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-address-db-service.interface'
// export { userAddressDbService } from '@/src/trpc/apis/user-apis/dataAccessors/postgres/user-address-queries'
export { userAddressDbService } from '@/src/trpc/apis/user-apis/dataAccessors/sqlite/user-address-queries'
export type { IUserCartDbService, CartItem } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-cart-db-service.interface' export type { IUserCartDbService, CartItem } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-cart-db-service.interface'
// export { userCartDbService } from '@/src/trpc/apis/user-apis/dataAccessors/postgres/user-cart-queries'
export { userCartDbService } from '@/src/trpc/apis/user-apis/dataAccessors/sqlite/user-cart-queries'
export type { IUserComplaintDbService, Complaint, NewComplaint } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-complaint-db-service.interface' export type { IUserComplaintDbService, Complaint, NewComplaint } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-complaint-db-service.interface'
// export { userComplaintDbService } from '@/src/trpc/apis/user-apis/dataAccessors/postgres/user-complaint-queries'
export { userComplaintDbService } from '@/src/trpc/apis/user-apis/dataAccessors/sqlite/user-complaint-queries'
export type { IUserProductDbService, Product, Store as ProductStore, Review, ProductWithUnit } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-product-db-service.interface' export type { IUserProductDbService, Product, Store as ProductStore, Review, ProductWithUnit } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-product-db-service.interface'
// export { userProductDbService } from '@/src/trpc/apis/user-apis/dataAccessors/postgres/user-product-queries'
export { userProductDbService } from '@/src/trpc/apis/user-apis/dataAccessors/sqlite/user-product-queries'
export type { IUserAuthDbService, User, UserCred, UserDetail } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-auth-db-service.interface' export type { IUserAuthDbService, User, UserCred, UserDetail } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-auth-db-service.interface'
// export { userAuthDbService } from '@/src/trpc/apis/user-apis/dataAccessors/postgres/user-auth-queries'
export { userAuthDbService } from '@/src/trpc/apis/user-apis/dataAccessors/sqlite/user-auth-queries'
export type { IUserProfileDbService, User as ProfileUser, UserDetail as ProfileUserDetail, UserCred as ProfileUserCred, NotifCred, UnloggedToken } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-profile-db-service.interface' export type { IUserProfileDbService, User as ProfileUser, UserDetail as ProfileUserDetail, UserCred as ProfileUserCred, NotifCred, UnloggedToken } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-profile-db-service.interface'
// export { userProfileDbService } from '@/src/trpc/apis/user-apis/dataAccessors/postgres/user-profile-queries'
export { userProfileDbService } from '@/src/trpc/apis/user-apis/dataAccessors/sqlite/user-profile-queries'
export type { IUserSlotDbService, Slot } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-slot-db-service.interface' export type { IUserSlotDbService, Slot } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-slot-db-service.interface'
// export { userSlotDbService } from '@/src/trpc/apis/user-apis/dataAccessors/postgres/user-slot-queries'
export { userSlotDbService } from '@/src/trpc/apis/user-apis/dataAccessors/sqlite/user-slot-queries'
export type { IUserCouponDbService, Coupon, CouponWithRelations, ReservedCoupon } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-coupon-db-service.interface' export type { IUserCouponDbService, Coupon, CouponWithRelations, ReservedCoupon } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-coupon-db-service.interface'
// export { userCouponDbService } from '@/src/trpc/apis/user-apis/dataAccessors/postgres/user-coupon-queries'
export { userCouponDbService } from '@/src/trpc/apis/user-apis/dataAccessors/sqlite/user-coupon-queries'
export type { IUserOrderDbService, Order, OrderInsert, OrderItemInsert, OrderStatusInsert, Coupon as OrderCoupon } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-order-db-service.interface' export type { IUserOrderDbService, Order, OrderInsert, OrderItemInsert, OrderStatusInsert, Coupon as OrderCoupon } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-order-db-service.interface'
// export { userOrderDbService } from '@/src/trpc/apis/user-apis/dataAccessors/postgres/user-order-queries'
export { userOrderDbService } from '@/src/trpc/apis/user-apis/dataAccessors/sqlite/user-order-queries' import { userBannerDbService as sqliteUserBannerDbService } from '@db-helper-sqlite/dataAccessors/user-apis/user-banner-queries'
import { userBannerDbService as postgresUserBannerDbService } from '@db-helper-postgres/dataAccessors/user-apis/user-banner-queries'
import { userStoreDbService as sqliteUserStoreDbService } from '@db-helper-sqlite/dataAccessors/user-apis/user-store-queries'
import { userStoreDbService as postgresUserStoreDbService } from '@db-helper-postgres/dataAccessors/user-apis/user-store-queries'
import { userAddressDbService as sqliteUserAddressDbService } from '@db-helper-sqlite/dataAccessors/user-apis/user-address-queries'
import { userAddressDbService as postgresUserAddressDbService } from '@db-helper-postgres/dataAccessors/user-apis/user-address-queries'
import { userCartDbService as sqliteUserCartDbService } from '@db-helper-sqlite/dataAccessors/user-apis/user-cart-queries'
import { userCartDbService as postgresUserCartDbService } from '@db-helper-postgres/dataAccessors/user-apis/user-cart-queries'
import { userComplaintDbService as sqliteUserComplaintDbService } from '@db-helper-sqlite/dataAccessors/user-apis/user-complaint-queries'
import { userComplaintDbService as postgresUserComplaintDbService } from '@db-helper-postgres/dataAccessors/user-apis/user-complaint-queries'
import { userProductDbService as sqliteUserProductDbService } from '@db-helper-sqlite/dataAccessors/user-apis/user-product-queries'
import { userProductDbService as postgresUserProductDbService } from '@db-helper-postgres/dataAccessors/user-apis/user-product-queries'
import { userAuthDbService as sqliteUserAuthDbService } from '@db-helper-sqlite/dataAccessors/user-apis/user-auth-queries'
import { userAuthDbService as postgresUserAuthDbService } from '@db-helper-postgres/dataAccessors/user-apis/user-auth-queries'
import { userProfileDbService as sqliteUserProfileDbService } from '@db-helper-sqlite/dataAccessors/user-apis/user-profile-queries'
import { userProfileDbService as postgresUserProfileDbService } from '@db-helper-postgres/dataAccessors/user-apis/user-profile-queries'
import { userSlotDbService as sqliteUserSlotDbService } from '@db-helper-sqlite/dataAccessors/user-apis/user-slot-queries'
import { userSlotDbService as postgresUserSlotDbService } from '@db-helper-postgres/dataAccessors/user-apis/user-slot-queries'
import { userCouponDbService as sqliteUserCouponDbService } from '@db-helper-sqlite/dataAccessors/user-apis/user-coupon-queries'
import { userCouponDbService as postgresUserCouponDbService } from '@db-helper-postgres/dataAccessors/user-apis/user-coupon-queries'
import { userOrderDbService as sqliteUserOrderDbService } from '@db-helper-sqlite/dataAccessors/user-apis/user-order-queries'
import { userOrderDbService as postgresUserOrderDbService } from '@db-helper-postgres/dataAccessors/user-apis/user-order-queries'
const isSqlite = process.env.DB_DIALECT === 'sqlite'
export const userBannerDbService = isSqlite ? sqliteUserBannerDbService : postgresUserBannerDbService
export const userStoreDbService = isSqlite ? sqliteUserStoreDbService : postgresUserStoreDbService
export const userAddressDbService = isSqlite ? sqliteUserAddressDbService : postgresUserAddressDbService
export const userCartDbService = isSqlite ? sqliteUserCartDbService : postgresUserCartDbService
export const userComplaintDbService = isSqlite ? sqliteUserComplaintDbService : postgresUserComplaintDbService
export const userProductDbService = isSqlite ? sqliteUserProductDbService : postgresUserProductDbService
export const userAuthDbService = isSqlite ? sqliteUserAuthDbService : postgresUserAuthDbService
export const userProfileDbService = isSqlite ? sqliteUserProfileDbService : postgresUserProfileDbService
export const userSlotDbService = isSqlite ? sqliteUserSlotDbService : postgresUserSlotDbService
export const userCouponDbService = isSqlite ? sqliteUserCouponDbService : postgresUserCouponDbService
export const userOrderDbService = isSqlite ? sqliteUserOrderDbService : postgresUserOrderDbService

View file

@ -30,6 +30,8 @@
// "baseUrl": ".", // "baseUrl": ".",
"paths": { "paths": {
"@/*": ["./*"], "@/*": ["./*"],
"@db-helper-postgres/*": ["../db-helper-postgres/src/*"],
"@db-helper-sqlite/*": ["../db-helper-sqlite/src/*"],
"shared-types": ["../shared-types"], "shared-types": ["../shared-types"],
"@commonTypes": ["../../packages/ui/shared-types"], "@commonTypes": ["../../packages/ui/shared-types"],
"@commonTypes/*": ["../../packages/ui/shared-types/*"], "@commonTypes/*": ["../../packages/ui/shared-types/*"],
@ -122,4 +124,3 @@
}, },
"include": ["src", "types", "index.ts", "../shared-types", "../../packages/shared"] "include": ["src", "types", "index.ts", "../shared-types", "../../packages/shared"]
} }

1
apps/backend/types/db-dialect.d.ts vendored Normal file
View file

@ -0,0 +1 @@
declare const DB_DIALECT_TYPE: 'postgres'

View file

@ -2,8 +2,8 @@ import 'dotenv/config'
import { defineConfig } from 'drizzle-kit' import { defineConfig } from 'drizzle-kit'
export default defineConfig({ export default defineConfig({
out: './drizzle/pg', out: './drizzle',
schema: './src/db/schema-postgres.ts', schema: './src/db/schema.ts',
dialect: 'postgresql', dialect: 'postgresql',
dbCredentials: { dbCredentials: {
url: process.env.DATABASE_URL!, url: process.env.DATABASE_URL!,

View file

@ -0,0 +1,10 @@
{
"name": "db-helper-postgres",
"version": "0.1.0",
"private": true,
"type": "module",
"dependencies": {
"drizzle-orm": "^0.45.1",
"pg": "^8.16.3"
}
}

View file

@ -0,0 +1,84 @@
import { and, eq, gt, inArray } from 'drizzle-orm'
import { db } from '../../db/db_index'
import { deliverySlotInfo, productInfo, productSlots, productTags, units } from '../../db/schema'
type ProductSummaryRow = {
id: number
name: string
shortDescription: string | null
price: string
marketPrice: string
images: unknown
isOutOfStock: boolean | null
unitShortNotation: string
productQuantity: number | null
nextDeliveryDate: Date | null
}
const getNextDeliveryDate = async (productId: number): Promise<Date | null> => {
const result = await db
.select({ deliveryTime: deliverySlotInfo.deliveryTime })
.from(productSlots)
.innerJoin(deliverySlotInfo, eq(productSlots.slotId, deliverySlotInfo.id))
.where(
and(
eq(productSlots.productId, productId),
eq(deliverySlotInfo.isActive, true),
gt(deliverySlotInfo.deliveryTime, new Date())
)
)
.orderBy(deliverySlotInfo.deliveryTime)
.limit(1)
return result[0]?.deliveryTime || null
}
export const getProductsSummaryData = async (tagId?: number | null): Promise<ProductSummaryRow[]> => {
let productIds: number[] | null = null
if (tagId) {
const taggedProducts = await db
.select({ productId: productTags.productId })
.from(productTags)
.where(eq(productTags.tagId, tagId))
productIds = taggedProducts.map((taggedProduct) => taggedProduct.productId)
if (productIds.length === 0) {
return []
}
}
const whereCondition = productIds && productIds.length > 0
? inArray(productInfo.id, productIds)
: undefined
const productsWithUnits = await db
.select({
id: productInfo.id,
name: productInfo.name,
shortDescription: productInfo.shortDescription,
price: productInfo.price,
marketPrice: productInfo.marketPrice,
images: productInfo.images,
isOutOfStock: productInfo.isOutOfStock,
unitShortNotation: units.shortNotation,
productQuantity: productInfo.productQuantity,
})
.from(productInfo)
.innerJoin(units, eq(productInfo.unitId, units.id))
.where(whereCondition)
const productsWithDelivery = await Promise.all(
productsWithUnits.map(async (product) => {
const nextDeliveryDate = await getNextDeliveryDate(product.id)
return {
...product,
nextDeliveryDate,
}
})
)
return productsWithDelivery
}

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { homeBanners } from '@/src/db/schema' import { homeBanners } from '../../db/schema'
import { eq, desc } from 'drizzle-orm' import { eq, desc } from 'drizzle-orm'
import { IBannerDbService, Banner, NewBanner } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/banner-db-service.interface' import { IBannerDbService, Banner, NewBanner } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/banner-db-service.interface'
export class BannerDbService implements IBannerDbService { export class BannerDbService implements IBannerDbService {
async getAllBanners(): Promise<Banner[]> { async getAllBanners(): Promise<Banner[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { complaints, users } from '@/src/db/schema' import { complaints, users } from '../../db/schema'
import { eq, desc, lt } from 'drizzle-orm' import { eq, desc, lt } from 'drizzle-orm'
import { IComplaintDbService, Complaint, NewComplaint } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/complaint-db-service.interface' import { IComplaintDbService, Complaint, NewComplaint } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/complaint-db-service.interface'
export class ComplaintDbService implements IComplaintDbService { export class ComplaintDbService implements IComplaintDbService {
async getComplaints( async getComplaints(

View file

@ -1,6 +1,6 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { keyValStore } from '@/src/db/schema' import { keyValStore } from '../../db/schema'
import { IConstantDbService, Constant, NewConstant } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/constant-db-service.interface' import { IConstantDbService, Constant, NewConstant } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/constant-db-service.interface'
export class ConstantDbService implements IConstantDbService { export class ConstantDbService implements IConstantDbService {
async getAllConstants(): Promise<Constant[]> { async getAllConstants(): Promise<Constant[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { coupons, couponApplicableUsers, couponApplicableProducts, reservedCoupons, users, orders, orderStatus } from '@/src/db/schema' import { coupons, couponApplicableUsers, couponApplicableProducts, reservedCoupons, users, orders, orderStatus } from '../../db/schema'
import { eq, and, like, or, inArray, lt, asc } from 'drizzle-orm' import { eq, and, like, or, inArray, lt, asc } from 'drizzle-orm'
import { ICouponDbService, Coupon, NewCoupon, ReservedCoupon, NewReservedCoupon, CouponWithRelations } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/coupon-db-service.interface' import { ICouponDbService, Coupon, NewCoupon, ReservedCoupon, NewReservedCoupon, CouponWithRelations } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/coupon-db-service.interface'
export class CouponDbService implements ICouponDbService { export class CouponDbService implements ICouponDbService {
async createCoupon(data: NewCoupon): Promise<Coupon> { async createCoupon(data: NewCoupon): Promise<Coupon> {

View file

@ -1,4 +1,4 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { import {
orders, orders,
orderItems, orderItems,
@ -14,7 +14,7 @@ import {
productInfo, productInfo,
units, units,
paymentInfoTable, paymentInfoTable,
} from '@/src/db/schema' } from '../../db/schema'
import { eq, and, gte, lt, desc, inArray, SQL } from 'drizzle-orm' import { eq, and, gte, lt, desc, inArray, SQL } from 'drizzle-orm'
import { import {
IOrderDbService, IOrderDbService,
@ -26,7 +26,7 @@ import {
OrderWithRelations, OrderWithRelations,
OrderWithStatus, OrderWithStatus,
OrderWithCouponUsages, OrderWithCouponUsages,
} from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/order-db-service.interface' } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/order-db-service.interface'
export class OrderDbService implements IOrderDbService { export class OrderDbService implements IOrderDbService {
async updateOrderNotes(orderId: number, adminNotes: string | null): Promise<Order> { async updateOrderNotes(orderId: number, adminNotes: string | null): Promise<Order> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { productInfo, units, specialDeals, productSlots, productTags, productReviews, productGroupInfo, productGroupMembership, users } from '@/src/db/schema' import { productInfo, units, specialDeals, productSlots, productTags, productReviews, productGroupInfo, productGroupMembership, users } from '../../db/schema'
import { eq, and, inArray, desc, sql } from 'drizzle-orm' import { eq, and, inArray, desc, sql } from 'drizzle-orm'
import { IProductDbService, Product, NewProduct, ProductGroup, NewProductGroup } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/product-db-service.interface' import { IProductDbService, Product, NewProduct, ProductGroup, NewProductGroup } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/product-db-service.interface'
export class ProductDbService implements IProductDbService { export class ProductDbService implements IProductDbService {
async getAllProducts(): Promise<Product[]> { async getAllProducts(): Promise<Product[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { refunds, orders, orderStatus, payments } from '@/src/db/schema' import { refunds, orders, orderStatus, payments } from '../../db/schema'
import { eq, and } from 'drizzle-orm' import { eq, and } from 'drizzle-orm'
import { IRefundDbService, Refund, NewRefund } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/refund-db-service.interface' import { IRefundDbService, Refund, NewRefund } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/refund-db-service.interface'
export class RefundDbService implements IRefundDbService { export class RefundDbService implements IRefundDbService {
async createRefund(data: NewRefund): Promise<Refund> { async createRefund(data: NewRefund): Promise<Refund> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { productAvailabilitySchedules } from '@/src/db/schema' import { productAvailabilitySchedules } from '../../db/schema'
import { eq, desc } from 'drizzle-orm' import { eq, desc } from 'drizzle-orm'
import { IScheduleDbService, Schedule, NewSchedule } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/schedule-db-service.interface' import { IScheduleDbService, Schedule, NewSchedule } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/schedule-db-service.interface'
export class ScheduleDbService implements IScheduleDbService { export class ScheduleDbService implements IScheduleDbService {
async createSchedule(data: NewSchedule): Promise<Schedule> { async createSchedule(data: NewSchedule): Promise<Schedule> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { deliverySlotInfo, productSlots, vendorSnippets, productInfo, productGroupInfo } from '@/src/db/schema' import { deliverySlotInfo, productSlots, vendorSnippets, productInfo, productGroupInfo } from '../../db/schema'
import { eq, inArray, and, desc } from 'drizzle-orm' import { eq, inArray, and, desc } from 'drizzle-orm'
import { ISlotDbService, Slot, NewSlot, ProductSlot, SlotWithRelations } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/slot-db-service.interface' import { ISlotDbService, Slot, NewSlot, ProductSlot, SlotWithRelations } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/slot-db-service.interface'
export class SlotDbService implements ISlotDbService { export class SlotDbService implements ISlotDbService {
async getAllSlots(): Promise<SlotWithRelations[]> { async getAllSlots(): Promise<SlotWithRelations[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { staffUsers, staffRoles, users, userDetails, orders } from '@/src/db/schema' import { staffUsers, staffRoles, users, userDetails, orders } from '../../db/schema'
import { eq, or, ilike, and, lt, desc } from 'drizzle-orm' import { eq, or, ilike, and, lt, desc } from 'drizzle-orm'
import { IStaffUserDbService, StaffUser, NewStaffUser, StaffRole } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/staff-user-db-service.interface' import { IStaffUserDbService, StaffUser, NewStaffUser, StaffRole } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/staff-user-db-service.interface'
export class StaffUserDbService implements IStaffUserDbService { export class StaffUserDbService implements IStaffUserDbService {
async getStaffUserByName(name: string): Promise<StaffUser | undefined> { async getStaffUserByName(name: string): Promise<StaffUser | undefined> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { storeInfo, productInfo } from '@/src/db/schema' import { storeInfo, productInfo } from '../../db/schema'
import { eq, inArray } from 'drizzle-orm' import { eq, inArray } from 'drizzle-orm'
import { IStoreDbService, Store, NewStore } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/store-db-service.interface' import { IStoreDbService, Store, NewStore } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/store-db-service.interface'
export class StoreDbService implements IStoreDbService { export class StoreDbService implements IStoreDbService {
async getAllStores(): Promise<Store[]> { async getAllStores(): Promise<Store[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { productTagInfo } from '@/src/db/schema' import { productTagInfo } from '../../db/schema'
import { eq } from 'drizzle-orm' import { eq } from 'drizzle-orm'
import { ITagDbService, Tag, NewTag } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/tag-db-service.interface' import { ITagDbService, Tag, NewTag } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/tag-db-service.interface'
export class TagDbService implements ITagDbService { export class TagDbService implements ITagDbService {
async getAllTags(): Promise<Tag[]> { async getAllTags(): Promise<Tag[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { users, userDetails, orders, orderItems, orderStatus, complaints, notifCreds, unloggedUserTokens, userIncidents } from '@/src/db/schema' import { users, userDetails, orders, orderItems, orderStatus, complaints, notifCreds, unloggedUserTokens, userIncidents } from '../../db/schema'
import { eq, sql, desc, asc, count, max, inArray } from 'drizzle-orm' import { eq, sql, desc, asc, count, max, inArray } from 'drizzle-orm'
import { IUserDbService, User, NewUser, UserDetail } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/user-db-service.interface' import { IUserDbService, User, NewUser, UserDetail } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/user-db-service.interface'
export class UserDbService implements IUserDbService { export class UserDbService implements IUserDbService {
async getUserById(id: number): Promise<User | undefined> { async getUserById(id: number): Promise<User | undefined> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { vendorSnippets, deliverySlotInfo, orders, orderItems, productInfo } from '@/src/db/schema' import { vendorSnippets, deliverySlotInfo, orders, orderItems, productInfo } from '../../db/schema'
import { eq, and, inArray, gt, asc, desc } from 'drizzle-orm' import { eq, and, inArray, gt, asc, desc } from 'drizzle-orm'
import { IVendorSnippetDbService, VendorSnippet, NewVendorSnippet } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/vendor-snippet-db-service.interface' import { IVendorSnippetDbService, VendorSnippet, NewVendorSnippet } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/vendor-snippet-db-service.interface'
export class VendorSnippetDbService implements IVendorSnippetDbService { export class VendorSnippetDbService implements IVendorSnippetDbService {
async createSnippet(data: NewVendorSnippet): Promise<VendorSnippet> { async createSnippet(data: NewVendorSnippet): Promise<VendorSnippet> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { addresses, orders, orderStatus, deliverySlotInfo } from '@/src/db/schema' import { addresses, orders, orderStatus, deliverySlotInfo } from '../../db/schema'
import { eq, and, gte } from 'drizzle-orm' import { eq, and, gte } from 'drizzle-orm'
import { IUserAddressDbService, Address, NewAddress } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-address-db-service.interface' import { IUserAddressDbService, Address, NewAddress } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-address-db-service.interface'
export class UserAddressDbService implements IUserAddressDbService { export class UserAddressDbService implements IUserAddressDbService {
async getDefaultAddress(userId: number): Promise<Address | undefined> { async getDefaultAddress(userId: number): Promise<Address | undefined> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { users, userCreds, userDetails, addresses, cartItems, complaints, couponApplicableUsers, couponUsage, notifCreds, notifications, orderItems, orderStatus, orders, payments, refunds, productReviews, reservedCoupons } from '@/src/db/schema' import { users, userCreds, userDetails, addresses, cartItems, complaints, couponApplicableUsers, couponUsage, notifCreds, notifications, orderItems, orderStatus, orders, payments, refunds, productReviews, reservedCoupons } from '../../db/schema'
import { eq } from 'drizzle-orm' import { eq } from 'drizzle-orm'
import { IUserAuthDbService, User, UserCred, UserDetail } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-auth-db-service.interface' import { IUserAuthDbService, User, UserCred, UserDetail } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-auth-db-service.interface'
export class UserAuthDbService implements IUserAuthDbService { export class UserAuthDbService implements IUserAuthDbService {
async getUserByEmail(email: string): Promise<User | undefined> { async getUserByEmail(email: string): Promise<User | undefined> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { homeBanners } from '@/src/db/schema' import { homeBanners } from '../../db/schema'
import { isNotNull, asc } from 'drizzle-orm' import { isNotNull, asc } from 'drizzle-orm'
import { IUserBannerDbService, UserBanner } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-banner-db-service.interface' import { IUserBannerDbService, UserBanner } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-banner-db-service.interface'
export class UserBannerDbService implements IUserBannerDbService { export class UserBannerDbService implements IUserBannerDbService {
async getActiveBanners(): Promise<UserBanner[]> { async getActiveBanners(): Promise<UserBanner[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { cartItems, productInfo, units } from '@/src/db/schema' import { cartItems, productInfo, units } from '../../db/schema'
import { eq, and, sql } from 'drizzle-orm' import { eq, and, sql } from 'drizzle-orm'
import { IUserCartDbService, CartItem } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-cart-db-service.interface' import { IUserCartDbService, CartItem } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-cart-db-service.interface'
export class UserCartDbService implements IUserCartDbService { export class UserCartDbService implements IUserCartDbService {
async getCartItemsWithProducts(userId: number) { async getCartItemsWithProducts(userId: number) {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { complaints } from '@/src/db/schema' import { complaints } from '../../db/schema'
import { eq, asc } from 'drizzle-orm' import { eq, asc } from 'drizzle-orm'
import { IUserComplaintDbService } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-complaint-db-service.interface' import { IUserComplaintDbService } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-complaint-db-service.interface'
export class UserComplaintDbService implements IUserComplaintDbService { export class UserComplaintDbService implements IUserComplaintDbService {
async getComplaintsByUserId(userId: number) { async getComplaintsByUserId(userId: number) {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { coupons, couponUsage, couponApplicableUsers, couponApplicableProducts, reservedCoupons } from '@/src/db/schema' import { coupons, couponUsage, couponApplicableUsers, couponApplicableProducts, reservedCoupons } from '../../db/schema'
import { eq, and, or, gt, isNull } from 'drizzle-orm' import { eq, and, or, gt, isNull } from 'drizzle-orm'
import { IUserCouponDbService, Coupon, ReservedCoupon, CouponWithRelations } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-coupon-db-service.interface' import { IUserCouponDbService, Coupon, ReservedCoupon, CouponWithRelations } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-coupon-db-service.interface'
export class UserCouponDbService implements IUserCouponDbService { export class UserCouponDbService implements IUserCouponDbService {
async getActiveCouponsForUser(userId: number): Promise<CouponWithRelations[]> { async getActiveCouponsForUser(userId: number): Promise<CouponWithRelations[]> {

View file

@ -1,4 +1,4 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { import {
orders, orders,
orderItems, orderItems,
@ -12,12 +12,12 @@ import {
refunds, refunds,
units, units,
userDetails, userDetails,
} from '@/src/db/schema' } from '../../db/schema'
import { and, desc, eq, gte, inArray } from 'drizzle-orm' import { and, desc, eq, gte, inArray } from 'drizzle-orm'
import { import {
IUserOrderDbService, IUserOrderDbService,
Order, Order,
} from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-order-db-service.interface' } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-order-db-service.interface'
export class UserOrderDbService implements IUserOrderDbService { export class UserOrderDbService implements IUserOrderDbService {
async getUserDetailByUserId(userId: number) { async getUserDetailByUserId(userId: number) {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { productInfo, units, storeInfo, productSlots, deliverySlotInfo, specialDeals, productReviews, users } from '@/src/db/schema' import { productInfo, units, storeInfo, productSlots, deliverySlotInfo, specialDeals, productReviews, users } from '../../db/schema'
import { eq, and, gt, sql, desc } from 'drizzle-orm' import { eq, and, gt, sql, desc } from 'drizzle-orm'
import { IUserProductDbService, Review } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-product-db-service.interface' import { IUserProductDbService, Review } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-product-db-service.interface'
export class UserProductDbService implements IUserProductDbService { export class UserProductDbService implements IUserProductDbService {
async getProductById(productId: number) { async getProductById(productId: number) {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { users, userDetails, userCreds, notifCreds, unloggedUserTokens } from '@/src/db/schema' import { users, userDetails, userCreds, notifCreds, unloggedUserTokens } from '../../db/schema'
import { eq, and } from 'drizzle-orm' import { eq, and } from 'drizzle-orm'
import { IUserProfileDbService, User, UserDetail, UserCred, NotifCred, UnloggedToken } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-profile-db-service.interface' import { IUserProfileDbService, User, UserDetail, UserCred, NotifCred, UnloggedToken } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-profile-db-service.interface'
export class UserProfileDbService implements IUserProfileDbService { export class UserProfileDbService implements IUserProfileDbService {
async getUserById(userId: number): Promise<User | undefined> { async getUserById(userId: number): Promise<User | undefined> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { deliverySlotInfo, productInfo } from '@/src/db/schema' import { deliverySlotInfo, productInfo } from '../../db/schema'
import { eq } from 'drizzle-orm' import { eq } from 'drizzle-orm'
import { IUserSlotDbService, Slot } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-slot-db-service.interface' import { IUserSlotDbService, Slot } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-slot-db-service.interface'
export class UserSlotDbService implements IUserSlotDbService { export class UserSlotDbService implements IUserSlotDbService {
async getActiveSlots(): Promise<Slot[]> { async getActiveSlots(): Promise<Slot[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { storeInfo, productInfo, units } from '@/src/db/schema' import { storeInfo, productInfo, units } from '../../db/schema'
import { eq, and, sql } from 'drizzle-orm' import { eq, and, sql } from 'drizzle-orm'
import { IUserStoreDbService } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-store-db-service.interface' import { IUserStoreDbService } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-store-db-service.interface'
export class UserStoreDbService implements IUserStoreDbService { export class UserStoreDbService implements IUserStoreDbService {
async getStoresWithProductCount(): Promise<Array<{ id: number; name: string; description: string | null; imageUrl: string | null; productCount: number }>> { async getStoresWithProductCount(): Promise<Array<{ id: number; name: string; description: string | null; imageUrl: string | null; productCount: number }>> {

View file

@ -0,0 +1,10 @@
import { drizzle } from 'drizzle-orm/node-postgres'
import * as schema from './schema'
const db = drizzle({
connection: process.env.DATABASE_URL!,
casing: 'snake_case',
schema,
})
export { db }

View file

@ -2,13 +2,13 @@
* This was a one time script to change the composition of the signed urls * This was a one time script to change the composition of the signed urls
*/ */
import { db } from '@/src/db/db_index' import { db } from './db_index'
import { import {
userDetails, userDetails,
productInfo, productInfo,
productTagInfo, productTagInfo,
complaints complaints
} from '@/src/db/schema'; } from './schema';
import { eq, not, isNull } from 'drizzle-orm'; import { eq, not, isNull } from 'drizzle-orm';
const S3_DOMAIN = 'https://s3.sgp.io.cloud.ovh.net'; const S3_DOMAIN = 'https://s3.sgp.io.cloud.ovh.net';

View file

@ -0,0 +1,706 @@
import { pgTable, pgSchema, integer, varchar, date, boolean, timestamp, numeric, jsonb, pgEnum, unique, real, text, check, decimal } from "drizzle-orm/pg-core";
import { relations, sql } from "drizzle-orm";
const mf = pgSchema('mf');
export const users = mf.table('users', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
name: varchar({ length: 255 }),
email: varchar({ length: 255 }),
mobile: varchar({ length: 255 }),
createdAt: timestamp('created_at').notNull().defaultNow(),
}, (t) => ({
unq_email: unique('unique_email').on(t.email),
}));
export const userDetails = mf.table('user_details', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id).unique(),
bio: varchar('bio', { length: 500 }),
dateOfBirth: date('date_of_birth'),
gender: varchar('gender', { length: 20 }),
occupation: varchar('occupation', { length: 100 }),
profileImage: varchar('profile_image', { length: 500 }),
isSuspended: boolean('is_suspended').notNull().default(false),
createdAt: timestamp('created_at').notNull().defaultNow(),
updatedAt: timestamp('updated_at').notNull().defaultNow(),
});
export const userCreds = mf.table('user_creds', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
userPassword: varchar('user_password', { length: 255 }).notNull(),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const addresses = mf.table('addresses', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
name: varchar('name', { length: 255 }).notNull(),
phone: varchar('phone', { length: 15 }).notNull(),
addressLine1: varchar('address_line1', { length: 255 }).notNull(),
addressLine2: varchar('address_line2', { length: 255 }),
city: varchar('city', { length: 100 }).notNull(),
state: varchar('state', { length: 100 }).notNull(),
pincode: varchar('pincode', { length: 10 }).notNull(),
isDefault: boolean('is_default').notNull().default(false),
latitude: real('latitude'),
longitude: real('longitude'),
googleMapsUrl: varchar('google_maps_url', { length: 500 }),
adminLatitude: real('admin_latitude'),
adminLongitude: real('admin_longitude'),
zoneId: integer('zone_id').references(() => addressZones.id),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const addressZones = mf.table('address_zones', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
zoneName: varchar('zone_name', { length: 255 }).notNull(),
addedAt: timestamp('added_at').notNull().defaultNow(),
});
export const addressAreas = mf.table('address_areas', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
placeName: varchar('place_name', { length: 255 }).notNull(),
zoneId: integer('zone_id').references(() => addressZones.id),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const staffUsers = mf.table('staff_users', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
name: varchar({ length: 255 }).notNull(),
password: varchar({ length: 255 }).notNull(),
staffRoleId: integer('staff_role_id').references(() => staffRoles.id),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const storeInfo = mf.table('store_info', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
name: varchar({ length: 255 }).notNull(),
description: varchar({ length: 500 }),
imageUrl: varchar('image_url', { length: 500 }),
createdAt: timestamp('created_at').notNull().defaultNow(),
owner: integer('owner').notNull().references(() => staffUsers.id),
});
export const units = mf.table('units', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
shortNotation: varchar('short_notation', { length: 50 }).notNull(),
fullName: varchar('full_name', { length: 100 }).notNull(),
}, (t) => ({
unq_short_notation: unique('unique_short_notation').on(t.shortNotation),
}));
export const productAvailabilityActionEnum = pgEnum('product_availability_action', ['in', 'out']);
export const productInfo = mf.table('product_info', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
name: varchar({ length: 255 }).notNull(),
shortDescription: varchar('short_description', { length: 500 }),
longDescription: varchar('long_description', { length: 1000 }),
unitId: integer('unit_id').notNull().references(() => units.id),
price: numeric({ precision: 10, scale: 2 }).notNull(),
marketPrice: numeric('market_price', { precision: 10, scale: 2 }),
images: jsonb('images'),
isOutOfStock: boolean('is_out_of_stock').notNull().default(false),
isSuspended: boolean('is_suspended').notNull().default(false),
isFlashAvailable: boolean('is_flash_available').notNull().default(false),
flashPrice: numeric('flash_price', { precision: 10, scale: 2 }),
createdAt: timestamp('created_at').notNull().defaultNow(),
incrementStep: real('increment_step').notNull().default(1),
productQuantity: real('product_quantity').notNull().default(1),
storeId: integer('store_id').references(() => storeInfo.id),
scheduledAvailability: boolean('scheduled_availability').notNull().default(true),
});
export const productAvailabilitySchedules = mf.table('product_availability_schedules', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
time: varchar('time', { length: 10 }).notNull(),
scheduleName: varchar('schedule_name', { length: 255 }).notNull().unique(),
action: productAvailabilityActionEnum('action').notNull(),
productIds: integer('product_ids').array().notNull().default([]),
groupIds: integer('group_ids').array().notNull().default([]),
createdAt: timestamp('created_at').notNull().defaultNow(),
lastUpdated: timestamp('last_updated').notNull().defaultNow(),
});
export const productGroupInfo = mf.table('product_group_info', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
groupName: varchar('group_name', { length: 255 }).notNull(),
description: varchar({ length: 500 }),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const productGroupMembership = mf.table('product_group_membership', {
productId: integer('product_id').notNull().references(() => productInfo.id),
groupId: integer('group_id').notNull().references(() => productGroupInfo.id),
addedAt: timestamp('added_at').notNull().defaultNow(),
}, (t) => ({
pk: unique('product_group_membership_pk').on(t.productId, t.groupId),
}));
export const homeBanners = mf.table('home_banners', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
name: varchar('name', { length: 255 }).notNull(),
imageUrl: varchar('image_url', { length: 500 }).notNull(),
description: varchar('description', { length: 500 }),
productIds: integer('product_ids').array(),
redirectUrl: varchar('redirect_url', { length: 500 }),
serialNum: integer('serial_num'),
isActive: boolean('is_active').notNull().default(false),
createdAt: timestamp('created_at').notNull().defaultNow(),
lastUpdated: timestamp('last_updated').notNull().defaultNow(),
});
export const productReviews = mf.table('product_reviews', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
productId: integer('product_id').notNull().references(() => productInfo.id),
reviewBody: text('review_body').notNull(),
imageUrls: jsonb('image_urls').$defaultFn(() => []),
reviewTime: timestamp('review_time').notNull().defaultNow(),
ratings: real('ratings').notNull(),
adminResponse: text('admin_response'),
adminResponseImages: jsonb('admin_response_images').$defaultFn(() => []),
}, (t) => ({
ratingCheck: check('rating_check', sql`${t.ratings} >= 1 AND ${t.ratings} <= 5`),
}));
export const uploadStatusEnum = pgEnum('upload_status', ['pending', 'claimed']);
export const staffRoleEnum = pgEnum('staff_role', ['super_admin', 'admin', 'marketer', 'delivery_staff']);
export const staffPermissionEnum = pgEnum('staff_permission', ['crud_product', 'make_coupon', 'crud_staff_users']);
export const uploadUrlStatus = mf.table('upload_url_status', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
createdAt: timestamp('created_at').notNull().defaultNow(),
key: varchar('key', { length: 500 }).notNull(),
status: uploadStatusEnum('status').notNull().default('pending'),
});
export const productTagInfo = mf.table('product_tag_info', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
tagName: varchar('tag_name', { length: 100 }).notNull().unique(),
tagDescription: varchar('tag_description', { length: 500 }),
imageUrl: varchar('image_url', { length: 500 }),
isDashboardTag: boolean('is_dashboard_tag').notNull().default(false),
relatedStores: jsonb('related_stores').$defaultFn(() => []),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const productTags = mf.table('product_tags', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
productId: integer('product_id').notNull().references(() => productInfo.id),
tagId: integer('tag_id').notNull().references(() => productTagInfo.id),
assignedAt: timestamp('assigned_at').notNull().defaultNow(),
}, (t) => ({
unq_product_tag: unique('unique_product_tag').on(t.productId, t.tagId),
}));
export const deliverySlotInfo = mf.table('delivery_slot_info', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
deliveryTime: timestamp('delivery_time').notNull(),
freezeTime: timestamp('freeze_time').notNull(),
isActive: boolean('is_active').notNull().default(true),
isFlash: boolean('is_flash').notNull().default(false),
isCapacityFull: boolean('is_capacity_full').notNull().default(false),
deliverySequence: jsonb('delivery_sequence').$defaultFn(() => {}),
groupIds: jsonb('group_ids').$defaultFn(() => []),
});
export const vendorSnippets = mf.table('vendor_snippets', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
snippetCode: varchar('snippet_code', { length: 255 }).notNull().unique(),
slotId: integer('slot_id').references(() => deliverySlotInfo.id),
isPermanent: boolean('is_permanent').notNull().default(false),
productIds: integer('product_ids').array().notNull(),
validTill: timestamp('valid_till'),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const vendorSnippetsRelations = relations(vendorSnippets, ({ one }) => ({
slot: one(deliverySlotInfo, { fields: [vendorSnippets.slotId], references: [deliverySlotInfo.id] }),
}));
export const productSlots = mf.table('product_slots', {
productId: integer('product_id').notNull().references(() => productInfo.id),
slotId: integer('slot_id').notNull().references(() => deliverySlotInfo.id),
}, (t) => ({
pk: unique('product_slot_pk').on(t.productId, t.slotId),
}));
export const specialDeals = mf.table('special_deals', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
productId: integer('product_id').notNull().references(() => productInfo.id),
quantity: numeric({ precision: 10, scale: 2 }).notNull(),
price: numeric({ precision: 10, scale: 2 }).notNull(),
validTill: timestamp('valid_till').notNull(),
});
export const orders = mf.table('orders', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
addressId: integer('address_id').notNull().references(() => addresses.id),
slotId: integer('slot_id').references(() => deliverySlotInfo.id),
isCod: boolean('is_cod').notNull().default(false),
isOnlinePayment: boolean('is_online_payment').notNull().default(false),
paymentInfoId: integer('payment_info_id').references(() => paymentInfoTable.id),
totalAmount: numeric('total_amount', { precision: 10, scale: 2 }).notNull(),
deliveryCharge: numeric('delivery_charge', { precision: 10, scale: 2 }).notNull().default('0'),
readableId: integer('readable_id').notNull(),
adminNotes: text('admin_notes'),
userNotes: text('user_notes'),
orderGroupId: varchar('order_group_id', { length: 255 }),
orderGroupProportion: decimal('order_group_proportion', { precision: 10, scale: 4 }),
isFlashDelivery: boolean('is_flash_delivery').notNull().default(false),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const orderItems = mf.table('order_items', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
orderId: integer('order_id').notNull().references(() => orders.id),
productId: integer('product_id').notNull().references(() => productInfo.id),
quantity: varchar('quantity', { length: 50 }).notNull(),
price: numeric({ precision: 10, scale: 2 }).notNull(),
discountedPrice: numeric('discounted_price', { precision: 10, scale: 2 }),
is_packaged: boolean('is_packaged').notNull().default(false),
is_package_verified: boolean('is_package_verified').notNull().default(false),
});
export const paymentStatusEnum = pgEnum('payment_status', ['pending', 'success', 'cod', 'failed']);
export const orderStatus = mf.table('order_status', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
orderTime: timestamp('order_time').notNull().defaultNow(),
userId: integer('user_id').notNull().references(() => users.id),
orderId: integer('order_id').notNull().references(() => orders.id),
isPackaged: boolean('is_packaged').notNull().default(false),
isDelivered: boolean('is_delivered').notNull().default(false),
isCancelled: boolean('is_cancelled').notNull().default(false),
cancelReason: varchar('cancel_reason', { length: 255 }),
isCancelledByAdmin: boolean('is_cancelled_by_admin'),
paymentStatus: paymentStatusEnum('payment_state').notNull().default('pending'),
cancellationUserNotes: text('cancellation_user_notes'),
cancellationAdminNotes: text('cancellation_admin_notes'),
cancellationReviewed: boolean('cancellation_reviewed').notNull().default(false),
cancellationReviewedAt: timestamp('cancellation_reviewed_at'),
refundCouponId: integer('refund_coupon_id').references(() => coupons.id),
});
export const paymentInfoTable = mf.table('payment_info', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
status: varchar({ length: 50 }).notNull(),
gateway: varchar({ length: 50 }).notNull(),
orderId: varchar('order_id', { length: 500 }),
token: varchar({ length: 500 }),
merchantOrderId: varchar('merchant_order_id', { length: 255 }).notNull().unique(),
payload: jsonb('payload'),
});
export const payments = mf.table('payments', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
status: varchar({ length: 50 }).notNull(),
gateway: varchar({ length: 50 }).notNull(),
orderId: integer('order_id').notNull().references(() => orders.id),
token: varchar({ length: 500 }),
merchantOrderId: varchar('merchant_order_id', { length: 255 }).notNull().unique(),
payload: jsonb('payload'),
});
export const refunds = mf.table('refunds', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
orderId: integer('order_id').notNull().references(() => orders.id),
refundAmount: numeric('refund_amount', { precision: 10, scale: 2 }),
refundStatus: varchar('refund_status', { length: 50 }).default('none'),
merchantRefundId: varchar('merchant_refund_id', { length: 255 }),
refundProcessedAt: timestamp('refund_processed_at'),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const keyValStore = mf.table('key_val_store', {
key: varchar('key', { length: 255 }).primaryKey(),
value: jsonb('value'),
});
export const notifications = mf.table('notifications', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
title: varchar({ length: 255 }).notNull(),
body: varchar({ length: 512 }).notNull(),
type: varchar({ length: 50 }),
isRead: boolean('is_read').notNull().default(false),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const productCategories = mf.table('product_categories', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
name: varchar({ length: 255 }).notNull(),
description: varchar({ length: 500 }),
});
export const cartItems = mf.table('cart_items', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
productId: integer('product_id').notNull().references(() => productInfo.id),
quantity: numeric({ precision: 10, scale: 2 }).notNull(),
addedAt: timestamp('added_at').notNull().defaultNow(),
}, (t) => ({
unq_user_product: unique('unique_user_product').on(t.userId, t.productId),
}));
export const complaints = mf.table('complaints', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
orderId: integer('order_id').references(() => orders.id),
complaintBody: varchar('complaint_body', { length: 1000 }).notNull(),
images: jsonb('images'),
response: varchar('response', { length: 1000 }),
isResolved: boolean('is_resolved').notNull().default(false),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const coupons = mf.table('coupons', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
couponCode: varchar('coupon_code', { length: 50 }).notNull().unique('unique_coupon_code'),
isUserBased: boolean('is_user_based').notNull().default(false),
discountPercent: numeric('discount_percent', { precision: 5, scale: 2 }),
flatDiscount: numeric('flat_discount', { precision: 10, scale: 2 }),
minOrder: numeric('min_order', { precision: 10, scale: 2 }),
productIds: jsonb('product_ids'),
createdBy: integer('created_by').references(() => staffUsers.id),
maxValue: numeric('max_value', { precision: 10, scale: 2 }),
isApplyForAll: boolean('is_apply_for_all').notNull().default(false),
validTill: timestamp('valid_till'),
maxLimitForUser: integer('max_limit_for_user'),
isInvalidated: boolean('is_invalidated').notNull().default(false),
exclusiveApply: boolean('exclusive_apply').notNull().default(false),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const couponUsage = mf.table('coupon_usage', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
couponId: integer('coupon_id').notNull().references(() => coupons.id),
orderId: integer('order_id').references(() => orders.id),
orderItemId: integer('order_item_id').references(() => orderItems.id),
usedAt: timestamp('used_at').notNull().defaultNow(),
});
export const couponApplicableUsers = mf.table('coupon_applicable_users', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
couponId: integer('coupon_id').notNull().references(() => coupons.id),
userId: integer('user_id').notNull().references(() => users.id),
}, (t) => ({
unq_coupon_user: unique('unique_coupon_user').on(t.couponId, t.userId),
}));
export const couponApplicableProducts = mf.table('coupon_applicable_products', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
couponId: integer('coupon_id').notNull().references(() => coupons.id),
productId: integer('product_id').notNull().references(() => productInfo.id),
}, (t) => ({
unq_coupon_product: unique('unique_coupon_product').on(t.couponId, t.productId),
}));
export const userIncidents = mf.table('user_incidents', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
userId: integer('user_id').notNull().references(() => users.id),
orderId: integer('order_id').references(() => orders.id),
dateAdded: timestamp('date_added').notNull().defaultNow(),
adminComment: text('admin_comment'),
addedBy: integer('added_by').references(() => staffUsers.id),
negativityScore: integer('negativity_score'),
});
export const reservedCoupons = mf.table('reserved_coupons', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
secretCode: varchar('secret_code', { length: 50 }).notNull().unique(),
couponCode: varchar('coupon_code', { length: 50 }).notNull(),
discountPercent: numeric('discount_percent', { precision: 5, scale: 2 }),
flatDiscount: numeric('flat_discount', { precision: 10, scale: 2 }),
minOrder: numeric('min_order', { precision: 10, scale: 2 }),
productIds: jsonb('product_ids'),
maxValue: numeric('max_value', { precision: 10, scale: 2 }),
validTill: timestamp('valid_till'),
maxLimitForUser: integer('max_limit_for_user'),
exclusiveApply: boolean('exclusive_apply').notNull().default(false),
isRedeemed: boolean('is_redeemed').notNull().default(false),
redeemedBy: integer('redeemed_by').references(() => users.id),
redeemedAt: timestamp('redeemed_at'),
createdBy: integer('created_by').notNull().references(() => staffUsers.id),
createdAt: timestamp('created_at').notNull().defaultNow(),
}, (t) => ({
unq_secret_code: unique('unique_secret_code').on(t.secretCode),
}));
export const notifCreds = mf.table('notif_creds', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
token: varchar({ length: 500 }).notNull().unique(),
addedAt: timestamp('added_at').notNull().defaultNow(),
userId: integer('user_id').notNull().references(() => users.id),
lastVerified: timestamp('last_verified'),
});
export const unloggedUserTokens = mf.table('unlogged_user_tokens', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
token: varchar({ length: 500 }).notNull().unique(),
addedAt: timestamp('added_at').notNull().defaultNow(),
lastVerified: timestamp('last_verified'),
});
export const userNotifications = mf.table('user_notifications', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
title: varchar('title', { length: 255 }).notNull(),
imageUrl: varchar('image_url', { length: 500 }),
createdAt: timestamp('created_at').notNull().defaultNow(),
body: text('body').notNull(),
applicableUsers: jsonb('applicable_users'),
});
export const staffRoles = mf.table('staff_roles', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
roleName: staffRoleEnum('role_name').notNull(),
createdAt: timestamp('created_at').notNull().defaultNow(),
}, (t) => ({
unq_role_name: unique('unique_role_name').on(t.roleName),
}));
export const staffPermissions = mf.table('staff_permissions', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
permissionName: staffPermissionEnum('permission_name').notNull(),
createdAt: timestamp('created_at').notNull().defaultNow(),
}, (t) => ({
unq_permission_name: unique('unique_permission_name').on(t.permissionName),
}));
export const staffRolePermissions = mf.table('staff_role_permissions', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
staffRoleId: integer('staff_role_id').notNull().references(() => staffRoles.id),
staffPermissionId: integer('staff_permission_id').notNull().references(() => staffPermissions.id),
createdAt: timestamp('created_at').notNull().defaultNow(),
}, (t) => ({
unq_role_permission: unique('unique_role_permission').on(t.staffRoleId, t.staffPermissionId),
}));
// Relations
export const usersRelations = relations(users, ({ many, one }) => ({
addresses: many(addresses),
orders: many(orders),
notifications: many(notifications),
cartItems: many(cartItems),
userCreds: one(userCreds),
coupons: many(coupons),
couponUsages: many(couponUsage),
applicableCoupons: many(couponApplicableUsers),
userDetails: one(userDetails),
notifCreds: many(notifCreds),
userIncidents: many(userIncidents),
}));
export const userCredsRelations = relations(userCreds, ({ one }) => ({
user: one(users, { fields: [userCreds.userId], references: [users.id] }),
}));
export const staffUsersRelations = relations(staffUsers, ({ one, many }) => ({
role: one(staffRoles, { fields: [staffUsers.staffRoleId], references: [staffRoles.id] }),
coupons: many(coupons),
stores: many(storeInfo),
}));
export const addressesRelations = relations(addresses, ({ one, many }) => ({
user: one(users, { fields: [addresses.userId], references: [users.id] }),
orders: many(orders),
zone: one(addressZones, { fields: [addresses.zoneId], references: [addressZones.id] }),
}));
export const unitsRelations = relations(units, ({ many }) => ({
products: many(productInfo),
}));
export const productInfoRelations = relations(productInfo, ({ one, many }) => ({
unit: one(units, { fields: [productInfo.unitId], references: [units.id] }),
store: one(storeInfo, { fields: [productInfo.storeId], references: [storeInfo.id] }),
productSlots: many(productSlots),
specialDeals: many(specialDeals),
orderItems: many(orderItems),
cartItems: many(cartItems),
tags: many(productTags),
applicableCoupons: many(couponApplicableProducts),
reviews: many(productReviews),
groups: many(productGroupMembership),
}));
export const productTagInfoRelations = relations(productTagInfo, ({ many }) => ({
products: many(productTags),
}));
export const productTagsRelations = relations(productTags, ({ one }) => ({
product: one(productInfo, { fields: [productTags.productId], references: [productInfo.id] }),
tag: one(productTagInfo, { fields: [productTags.tagId], references: [productTagInfo.id] }),
}));
export const deliverySlotInfoRelations = relations(deliverySlotInfo, ({ many }) => ({
productSlots: many(productSlots),
orders: many(orders),
vendorSnippets: many(vendorSnippets),
}));
export const productSlotsRelations = relations(productSlots, ({ one }) => ({
product: one(productInfo, { fields: [productSlots.productId], references: [productInfo.id] }),
slot: one(deliverySlotInfo, { fields: [productSlots.slotId], references: [deliverySlotInfo.id] }),
}));
export const specialDealsRelations = relations(specialDeals, ({ one }) => ({
product: one(productInfo, { fields: [specialDeals.productId], references: [productInfo.id] }),
}));
export const ordersRelations = relations(orders, ({ one, many }) => ({
user: one(users, { fields: [orders.userId], references: [users.id] }),
address: one(addresses, { fields: [orders.addressId], references: [addresses.id] }),
slot: one(deliverySlotInfo, { fields: [orders.slotId], references: [deliverySlotInfo.id] }),
orderItems: many(orderItems),
payment: one(payments),
paymentInfo: one(paymentInfoTable, { fields: [orders.paymentInfoId], references: [paymentInfoTable.id] }),
orderStatus: many(orderStatus),
refunds: many(refunds),
couponUsages: many(couponUsage),
userIncidents: many(userIncidents),
}));
export const orderItemsRelations = relations(orderItems, ({ one }) => ({
order: one(orders, { fields: [orderItems.orderId], references: [orders.id] }),
product: one(productInfo, { fields: [orderItems.productId], references: [productInfo.id] }),
}));
export const orderStatusRelations = relations(orderStatus, ({ one }) => ({
order: one(orders, { fields: [orderStatus.orderId], references: [orders.id] }),
user: one(users, { fields: [orderStatus.userId], references: [users.id] }),
refundCoupon: one(coupons, { fields: [orderStatus.refundCouponId], references: [coupons.id] }),
}));
export const paymentInfoRelations = relations(paymentInfoTable, ({ one }) => ({
order: one(orders, { fields: [paymentInfoTable.id], references: [orders.paymentInfoId] }),
}));
export const paymentsRelations = relations(payments, ({ one }) => ({
order: one(orders, { fields: [payments.orderId], references: [orders.id] }),
}));
export const refundsRelations = relations(refunds, ({ one }) => ({
order: one(orders, { fields: [refunds.orderId], references: [orders.id] }),
}));
export const notificationsRelations = relations(notifications, ({ one }) => ({
user: one(users, { fields: [notifications.userId], references: [users.id] }),
}));
export const productCategoriesRelations = relations(productCategories, ({}) => ({}));
export const cartItemsRelations = relations(cartItems, ({ one }) => ({
user: one(users, { fields: [cartItems.userId], references: [users.id] }),
product: one(productInfo, { fields: [cartItems.productId], references: [productInfo.id] }),
}));
export const complaintsRelations = relations(complaints, ({ one }) => ({
user: one(users, { fields: [complaints.userId], references: [users.id] }),
order: one(orders, { fields: [complaints.orderId], references: [orders.id] }),
}));
export const couponsRelations = relations(coupons, ({ one, many }) => ({
creator: one(staffUsers, { fields: [coupons.createdBy], references: [staffUsers.id] }),
usages: many(couponUsage),
applicableUsers: many(couponApplicableUsers),
applicableProducts: many(couponApplicableProducts),
}));
export const couponUsageRelations = relations(couponUsage, ({ one }) => ({
user: one(users, { fields: [couponUsage.userId], references: [users.id] }),
coupon: one(coupons, { fields: [couponUsage.couponId], references: [coupons.id] }),
order: one(orders, { fields: [couponUsage.orderId], references: [orders.id] }),
orderItem: one(orderItems, { fields: [couponUsage.orderItemId], references: [orderItems.id] }),
}));
export const userDetailsRelations = relations(userDetails, ({ one }) => ({
user: one(users, { fields: [userDetails.userId], references: [users.id] }),
}));
export const notifCredsRelations = relations(notifCreds, ({ one }) => ({
user: one(users, { fields: [notifCreds.userId], references: [users.id] }),
}));
export const userNotificationsRelations = relations(userNotifications, ({}) => ({
// No relations needed for now
}));
export const storeInfoRelations = relations(storeInfo, ({ one, many }) => ({
owner: one(staffUsers, { fields: [storeInfo.owner], references: [staffUsers.id] }),
products: many(productInfo),
}));
export const couponApplicableUsersRelations = relations(couponApplicableUsers, ({ one }) => ({
coupon: one(coupons, { fields: [couponApplicableUsers.couponId], references: [coupons.id] }),
user: one(users, { fields: [couponApplicableUsers.userId], references: [users.id] }),
}));
export const couponApplicableProductsRelations = relations(couponApplicableProducts, ({ one }) => ({
coupon: one(coupons, { fields: [couponApplicableProducts.couponId], references: [coupons.id] }),
product: one(productInfo, { fields: [couponApplicableProducts.productId], references: [productInfo.id] }),
}));
export const reservedCouponsRelations = relations(reservedCoupons, ({ one }) => ({
redeemedUser: one(users, { fields: [reservedCoupons.redeemedBy], references: [users.id] }),
creator: one(staffUsers, { fields: [reservedCoupons.createdBy], references: [staffUsers.id] }),
}));
export const productReviewsRelations = relations(productReviews, ({ one }) => ({
user: one(users, { fields: [productReviews.userId], references: [users.id] }),
product: one(productInfo, { fields: [productReviews.productId], references: [productInfo.id] }),
}));
export const addressZonesRelations = relations(addressZones, ({ many }) => ({
addresses: many(addresses),
areas: many(addressAreas),
}));
export const addressAreasRelations = relations(addressAreas, ({ one }) => ({
zone: one(addressZones, { fields: [addressAreas.zoneId], references: [addressZones.id] }),
}));
export const productGroupInfoRelations = relations(productGroupInfo, ({ many }) => ({
memberships: many(productGroupMembership),
}));
export const productGroupMembershipRelations = relations(productGroupMembership, ({ one }) => ({
product: one(productInfo, { fields: [productGroupMembership.productId], references: [productInfo.id] }),
group: one(productGroupInfo, { fields: [productGroupMembership.groupId], references: [productGroupInfo.id] }),
}));
export const homeBannersRelations = relations(homeBanners, ({}) => ({
// Relations for productIds array would be more complex, skipping for now
}));
export const staffRolesRelations = relations(staffRoles, ({ many }) => ({
staffUsers: many(staffUsers),
rolePermissions: many(staffRolePermissions),
}));
export const staffPermissionsRelations = relations(staffPermissions, ({ many }) => ({
rolePermissions: many(staffRolePermissions),
}));
export const staffRolePermissionsRelations = relations(staffRolePermissions, ({ one }) => ({
role: one(staffRoles, { fields: [staffRolePermissions.staffRoleId], references: [staffRoles.id] }),
permission: one(staffPermissions, { fields: [staffRolePermissions.staffPermissionId], references: [staffPermissions.id] }),
}));
export const userIncidentsRelations = relations(userIncidents, ({ one }) => ({
user: one(users, { fields: [userIncidents.userId], references: [users.id] }),
order: one(orders, { fields: [userIncidents.orderId], references: [orders.id] }),
addedBy: one(staffUsers, { fields: [userIncidents.addedBy], references: [staffUsers.id] }),
}));
export const productAvailabilitySchedulesRelations = relations(productAvailabilitySchedules, ({}) => ({
}));

View file

@ -0,0 +1,153 @@
import { eq } from 'drizzle-orm'
import { CONST_KEYS } from '../../../backend/src/lib/const-keys'
import { deliveryCharge, minOrderValue } from '../../../backend/src/lib/env-exporter'
import { db } from './db_index'
import { keyValStore, staffPermissions, staffRolePermissions, staffRoles, units } from './schema'
export async function seed() {
console.log('Seeding database...')
const unitsToSeed = [
{ shortNotation: 'Kg', fullName: 'Kilogram' },
{ shortNotation: 'L', fullName: 'Litre' },
{ shortNotation: 'Dz', fullName: 'Dozen' },
{ shortNotation: 'Pc', fullName: 'Unit Piece' },
]
for (const unit of unitsToSeed) {
const existingUnit = await db.query.units.findFirst({
where: eq(units.shortNotation, unit.shortNotation),
})
if (!existingUnit) {
await db.insert(units).values(unit)
}
}
const rolesToSeed = ['super_admin', 'admin', 'marketer', 'delivery_staff'] as const
for (const roleName of rolesToSeed) {
const existingRole = await db.query.staffRoles.findFirst({
where: eq(staffRoles.roleName, roleName),
})
if (!existingRole) {
await db.insert(staffRoles).values({ roleName })
}
}
const permissionsToSeed = ['crud_product', 'make_coupon', 'crud_staff_users'] as const
for (const permissionName of permissionsToSeed) {
const existingPermission = await db.query.staffPermissions.findFirst({
where: eq(staffPermissions.permissionName, permissionName),
})
if (!existingPermission) {
await db.insert(staffPermissions).values({ permissionName })
}
}
await db.transaction(async (tx) => {
const superAdminRole = await tx.query.staffRoles.findFirst({
where: eq(staffRoles.roleName, 'super_admin'),
})
const adminRole = await tx.query.staffRoles.findFirst({
where: eq(staffRoles.roleName, 'admin'),
})
const marketerRole = await tx.query.staffRoles.findFirst({
where: eq(staffRoles.roleName, 'marketer'),
})
const crudProductPerm = await tx.query.staffPermissions.findFirst({
where: eq(staffPermissions.permissionName, 'crud_product'),
})
const makeCouponPerm = await tx.query.staffPermissions.findFirst({
where: eq(staffPermissions.permissionName, 'make_coupon'),
})
const crudStaffUsersPerm = await tx.query.staffPermissions.findFirst({
where: eq(staffPermissions.permissionName, 'crud_staff_users'),
})
await Promise.all(
[crudProductPerm, makeCouponPerm, crudStaffUsersPerm].map(async (perm) => {
if (!superAdminRole || !perm) {
return
}
const existingSuperAdminPerm = await tx.query.staffRolePermissions.findFirst({
where: eq(staffRolePermissions.staffRoleId, superAdminRole.id)
&& eq(staffRolePermissions.staffPermissionId, perm.id),
})
if (!existingSuperAdminPerm) {
await tx.insert(staffRolePermissions).values({
staffRoleId: superAdminRole.id,
staffPermissionId: perm.id,
})
}
})
)
await Promise.all(
[crudProductPerm, makeCouponPerm].map(async (perm) => {
if (!adminRole || !perm) {
return
}
const existingAdminPerm = await tx.query.staffRolePermissions.findFirst({
where: eq(staffRolePermissions.staffRoleId, adminRole.id)
&& eq(staffRolePermissions.staffPermissionId, perm.id),
})
if (!existingAdminPerm) {
await tx.insert(staffRolePermissions).values({
staffRoleId: adminRole.id,
staffPermissionId: perm.id,
})
}
})
)
if (marketerRole && makeCouponPerm) {
const existingMarketerCoupon = await tx.query.staffRolePermissions.findFirst({
where: eq(staffRolePermissions.staffRoleId, marketerRole.id)
&& eq(staffRolePermissions.staffPermissionId, makeCouponPerm.id),
})
if (!existingMarketerCoupon) {
await tx.insert(staffRolePermissions).values({
staffRoleId: marketerRole.id,
staffPermissionId: makeCouponPerm.id,
})
}
}
})
const constantsToSeed = [
{ key: CONST_KEYS.readableOrderId, value: 0 },
{ key: CONST_KEYS.minRegularOrderValue, value: minOrderValue },
{ key: CONST_KEYS.freeDeliveryThreshold, value: minOrderValue },
{ key: CONST_KEYS.deliveryCharge, value: deliveryCharge },
{ key: CONST_KEYS.flashFreeDeliveryThreshold, value: 500 },
{ key: CONST_KEYS.flashDeliveryCharge, value: 69 },
{ key: CONST_KEYS.popularItems, value: [] },
{ key: CONST_KEYS.allItemsOrder, value: [] },
{ key: CONST_KEYS.versionNum, value: '1.1.0' },
{ key: CONST_KEYS.playStoreUrl, value: 'https://play.google.com/store/apps/details?id=in.freshyo.app' },
{ key: CONST_KEYS.appStoreUrl, value: 'https://apps.apple.com/in/app/freshyo/id6756889077' },
{ key: CONST_KEYS.isFlashDeliveryEnabled, value: false },
{ key: CONST_KEYS.supportMobile, value: '8688182552' },
{ key: CONST_KEYS.supportEmail, value: 'qushammohd@gmail.com' },
]
for (const constant of constantsToSeed) {
const existing = await db.query.keyValStore.findFirst({
where: eq(keyValStore.key, constant.key),
})
if (!existing) {
await db.insert(keyValStore).values({
key: constant.key,
value: constant.value,
})
}
}
console.log('Seeding completed.')
}

View file

@ -0,0 +1,47 @@
import type { InferSelectModel } from 'drizzle-orm'
import type {
users,
addresses,
units,
productInfo,
deliverySlotInfo,
productSlots,
specialDeals,
orders,
orderItems,
payments,
notifications,
productCategories,
cartItems,
coupons,
} from './schema'
export type User = InferSelectModel<typeof users>
export type Address = InferSelectModel<typeof addresses>
export type Unit = InferSelectModel<typeof units>
export type ProductInfo = InferSelectModel<typeof productInfo>
export type DeliverySlotInfo = InferSelectModel<typeof deliverySlotInfo>
export type ProductSlot = InferSelectModel<typeof productSlots>
export type SpecialDeal = InferSelectModel<typeof specialDeals>
export type Order = InferSelectModel<typeof orders>
export type OrderItem = InferSelectModel<typeof orderItems>
export type Payment = InferSelectModel<typeof payments>
export type Notification = InferSelectModel<typeof notifications>
export type ProductCategory = InferSelectModel<typeof productCategories>
export type CartItem = InferSelectModel<typeof cartItems>
export type Coupon = InferSelectModel<typeof coupons>
export type ProductWithUnit = ProductInfo & {
unit: Unit
}
export type OrderWithItems = Order & {
items: (OrderItem & { product: ProductInfo })[]
address: Address
slot: DeliverySlotInfo
}
export type CartItemWithProduct = CartItem & {
product: ProductInfo
}

View file

@ -1,6 +1,6 @@
import * as cron from 'node-cron'; import * as cron from 'node-cron';
import { db } from '@/src/db/db_index' import { db } from '../db/db_index'
import { productInfo, productAvailabilitySchedules } from '@/src/db/schema' import { productInfo, productAvailabilitySchedules } from '../db/schema'
import { inArray } from 'drizzle-orm'; import { inArray } from 'drizzle-orm';
import { initializeAllStores } from '../stores/store-initializer'; import { initializeAllStores } from '../stores/store-initializer';

View file

@ -5,8 +5,8 @@ import { scaffoldStores } from '@/src/trpc/apis/user-apis/apis/stores'
import { scaffoldSlotsWithProducts } from '@/src/trpc/apis/user-apis/apis/slots' import { scaffoldSlotsWithProducts } from '@/src/trpc/apis/user-apis/apis/slots'
import { scaffoldBanners } from '@/src/trpc/apis/user-apis/apis/banners' import { scaffoldBanners } from '@/src/trpc/apis/user-apis/apis/banners'
import { scaffoldStoreWithProducts } from '@/src/trpc/apis/user-apis/apis/stores' import { scaffoldStoreWithProducts } from '@/src/trpc/apis/user-apis/apis/stores'
import { storeInfo } from '@/src/db/schema' import { storeInfo } from '../db/schema'
import { db } from '@/src/db/db_index' import { db } from '../db/db_index'
import { imageUploadS3 } from '@/src/lib/s3-client' import { imageUploadS3 } from '@/src/lib/s3-client'
import { apiCacheKey, cloudflareApiToken, cloudflareZoneId, assetsDomain } from '@/src/lib/env-exporter' import { apiCacheKey, cloudflareApiToken, cloudflareZoneId, assetsDomain } from '@/src/lib/env-exporter'
import { CACHE_FILENAMES } from '@packages/shared' import { CACHE_FILENAMES } from '@packages/shared'

View file

@ -1,5 +1,5 @@
import { db } from '@/src/db/db_index' import { db } from '../db/db_index'
import { keyValStore } from '@/src/db/schema' import { keyValStore } from '../db/schema'
import redisClient from '@/src/lib/redis-client' import redisClient from '@/src/lib/redis-client'
import { CONST_KEYS, CONST_KEYS_ARRAY, type ConstKey } from '@/src/lib/const-keys' import { CONST_KEYS, CONST_KEYS_ARRAY, type ConstKey } from '@/src/lib/const-keys'

View file

@ -1,5 +1,5 @@
import { db } from '@/src/db/db_index' import { db } from '../db/db_index'
import { orders, orderItems, orderStatus, payments, refunds, couponUsage, complaints } from '@/src/db/schema' import { orders, orderItems, orderStatus, payments, refunds, couponUsage, complaints } from '../db/schema'
import { eq, inArray } from 'drizzle-orm'; import { eq, inArray } from 'drizzle-orm';
/** /**

View file

@ -1,5 +1,5 @@
import { db } from '@/src/db/db_index' import { db } from '../db/db_index'
import { productInfo, productAvailabilitySchedules } from '@/src/db/schema' import { productInfo, productAvailabilitySchedules } from '../db/schema'
import { eq, inArray } from 'drizzle-orm'; import { eq, inArray } from 'drizzle-orm';
import { initializeAllStores } from '@/src/stores/store-initializer'; import { initializeAllStores } from '@/src/stores/store-initializer';
import dayjs from 'dayjs'; import dayjs from 'dayjs';

View file

@ -1,7 +1,7 @@
import { Queue, Worker } from 'bullmq'; import { Queue, Worker } from 'bullmq';
import { Expo } from 'expo-server-sdk'; import { Expo } from 'expo-server-sdk';
import { redisUrl } from '@/src/lib/env-exporter' import { redisUrl } from '@/src/lib/env-exporter'
import { db } from '@/src/db/db_index' import { db } from '../db/db_index'
import { generateSignedUrlFromS3Url } from '@/src/lib/s3-client' import { generateSignedUrlFromS3Url } from '@/src/lib/s3-client'
import { import {
NOTIFS_QUEUE, NOTIFS_QUEUE,

View file

@ -1,5 +1,5 @@
import { db } from '@/src/db/db_index' import { db } from '../db/db_index'
import { orders, orderStatus } from '@/src/db/schema' import { orders, orderStatus } from '../db/schema'
import redisClient from '@/src/lib/redis-client' import redisClient from '@/src/lib/redis-client'
import { sendTelegramMessage } from '@/src/lib/telegram-service' import { sendTelegramMessage } from '@/src/lib/telegram-service'
import { inArray, eq } from 'drizzle-orm'; import { inArray, eq } from 'drizzle-orm';

View file

@ -0,0 +1,23 @@
import { and, eq } from 'drizzle-orm'
import { db } from '../db/db_index'
import { uploadUrlStatus } from '../db/schema'
export const createUploadUrlStatus = async (key: string): Promise<void> => {
await db.insert(uploadUrlStatus).values({
key,
status: 'pending',
})
}
export const claimUploadUrlStatus = async (key: string): Promise<void> => {
const result = await db
.update(uploadUrlStatus)
.set({ status: 'claimed' })
.where(and(eq(uploadUrlStatus.key, key), eq(uploadUrlStatus.status, 'pending')))
.returning()
if (result.length === 0) {
throw new Error('Upload URL not found or already claimed')
}
}

View file

@ -1,6 +1,6 @@
import { createMiddleware } from 'hono/factory' import { createMiddleware } from 'hono/factory'
import { db } from '@/src/db/db_index' import { db } from '../db/db_index'
import { staffUsers, userDetails } from '@/src/db/schema' import { staffUsers, userDetails } from '../db/schema'
import { eq } from 'drizzle-orm' import { eq } from 'drizzle-orm'
import { ApiError } from '@/src/lib/api-error' import { ApiError } from '@/src/lib/api-error'
import { verifyToken, UserJWTPayload, StaffJWTPayload } from '@/src/lib/jwt-utils' import { verifyToken, UserJWTPayload, StaffJWTPayload } from '@/src/lib/jwt-utils'

View file

@ -1,6 +1,6 @@
import { createMiddleware } from 'hono/factory' import { createMiddleware } from 'hono/factory'
import { db } from '@/src/db/db_index' import { db } from '../db/db_index'
import { staffUsers } from '@/src/db/schema' import { staffUsers } from '../db/schema'
import { eq } from 'drizzle-orm'; import { eq } from 'drizzle-orm';
import { ApiError } from '@/src/lib/api-error' import { ApiError } from '@/src/lib/api-error'
import { verifyToken, StaffJWTPayload } from '@/src/lib/jwt-utils' import { verifyToken, StaffJWTPayload } from '@/src/lib/jwt-utils'

View file

@ -1,5 +1,5 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { productInfo, units, productSlots, deliverySlotInfo, specialDeals, storeInfo, productReviews, users } from '@/src/db/schema' import { productInfo, units, productSlots, deliverySlotInfo, specialDeals, storeInfo, productReviews, users } from '../../db/schema'
import { eq, and, gt, sql, desc } from 'drizzle-orm' import { eq, and, gt, sql, desc } from 'drizzle-orm'
/** /**
@ -55,8 +55,8 @@ export async function getProductDeliverySlots(productId: number) {
and( and(
eq(productSlots.productId, productId), eq(productSlots.productId, productId),
eq(deliverySlotInfo.isActive, true), eq(deliverySlotInfo.isActive, true),
gt(deliverySlotInfo.deliveryTime, sql`NOW()`), gt(deliverySlotInfo.deliveryTime, new Date()),
gt(deliverySlotInfo.freezeTime, sql`NOW()`) gt(deliverySlotInfo.freezeTime, new Date())
) )
) )
.orderBy(deliverySlotInfo.deliveryTime) .orderBy(deliverySlotInfo.deliveryTime)
@ -76,7 +76,7 @@ export async function getProductSpecialDeals(productId: number) {
.where( .where(
and( and(
eq(specialDeals.productId, productId), eq(specialDeals.productId, productId),
gt(specialDeals.validTill, sql`NOW()`) gt(specialDeals.validTill, new Date())
) )
) )
.orderBy(specialDeals.quantity) .orderBy(specialDeals.quantity)

View file

@ -1,7 +1,7 @@
// import redisClient from '@/src/stores/redis-client'; // import redisClient from '@/src/stores/redis-client';
import redisClient from '@/src/lib/redis-client'; import redisClient from '@/src/lib/redis-client';
import { db } from '@/src/db/db_index' import { db } from '../db/db_index'
import { homeBanners } from '@/src/db/schema' import { homeBanners } from '../db/schema'
import { isNotNull, asc } from 'drizzle-orm'; import { isNotNull, asc } from 'drizzle-orm';
import { scaffoldAssetUrl } from '@/src/lib/s3-client'; import { scaffoldAssetUrl } from '@/src/lib/s3-client';

View file

@ -1,7 +1,7 @@
// import redisClient from '@/src/stores/redis-client'; // import redisClient from '@/src/stores/redis-client';
import redisClient from '@/src/lib/redis-client'; import redisClient from '@/src/lib/redis-client';
import { db } from '@/src/db/db_index' import { db } from '../db/db_index'
import { productInfo, units, productSlots, deliverySlotInfo, specialDeals, storeInfo, productTags, productTagInfo } from '@/src/db/schema' import { productInfo, units, productSlots, deliverySlotInfo, specialDeals, storeInfo, productTags, productTagInfo } from '../db/schema'
import { eq, and, gt, sql } from 'drizzle-orm'; import { eq, and, gt, sql } from 'drizzle-orm';
import { generateSignedUrlsFromS3Urls, scaffoldAssetUrl } from '@/src/lib/s3-client'; import { generateSignedUrlsFromS3Urls, scaffoldAssetUrl } from '@/src/lib/s3-client';
@ -72,7 +72,7 @@ export async function initializeProducts(): Promise<void> {
and( and(
eq(deliverySlotInfo.isActive, true), eq(deliverySlotInfo.isActive, true),
eq(deliverySlotInfo.isCapacityFull, false), eq(deliverySlotInfo.isCapacityFull, false),
gt(deliverySlotInfo.deliveryTime, sql`NOW()`) gt(deliverySlotInfo.deliveryTime, new Date())
) )
); );
const deliverySlotsMap = new Map<number, typeof allDeliverySlots>(); const deliverySlotsMap = new Map<number, typeof allDeliverySlots>();
@ -90,7 +90,7 @@ export async function initializeProducts(): Promise<void> {
validTill: specialDeals.validTill, validTill: specialDeals.validTill,
}) })
.from(specialDeals) .from(specialDeals)
.where(gt(specialDeals.validTill, sql`NOW()`)); .where(gt(specialDeals.validTill, new Date()));
const specialDealsMap = new Map<number, typeof allSpecialDeals>(); const specialDealsMap = new Map<number, typeof allSpecialDeals>();
for (const deal of allSpecialDeals) { for (const deal of allSpecialDeals) {
if (!specialDealsMap.has(deal.productId)) specialDealsMap.set(deal.productId, []); if (!specialDealsMap.has(deal.productId)) specialDealsMap.set(deal.productId, []);

View file

@ -1,7 +1,7 @@
// import redisClient from '@/src/stores/redis-client'; // import redisClient from '@/src/stores/redis-client';
import redisClient from '@/src/lib/redis-client'; import redisClient from '@/src/lib/redis-client';
import { db } from '@/src/db/db_index' import { db } from '../db/db_index'
import { productTagInfo, productTags } from '@/src/db/schema' import { productTagInfo, productTags } from '../db/schema'
import { eq, inArray } from 'drizzle-orm'; import { eq, inArray } from 'drizzle-orm';
import { generateSignedUrlFromS3Url } from '@/src/lib/s3-client'; import { generateSignedUrlFromS3Url } from '@/src/lib/s3-client';

View file

@ -1,6 +1,6 @@
import redisClient from '@/src/lib/redis-client'; import redisClient from '@/src/lib/redis-client';
import { db } from '@/src/db/db_index' import { db } from '../db/db_index'
import { deliverySlotInfo, productSlots, productInfo, units } from '@/src/db/schema' import { deliverySlotInfo, productSlots, productInfo, units } from '../db/schema'
import { eq, and, gt, asc } from 'drizzle-orm'; import { eq, and, gt, asc } from 'drizzle-orm';
import { generateSignedUrlsFromS3Urls, scaffoldAssetUrl } from '@/src/lib/s3-client'; import { generateSignedUrlsFromS3Urls, scaffoldAssetUrl } from '@/src/lib/s3-client';
import dayjs from 'dayjs'; import dayjs from 'dayjs';

View file

@ -1,6 +1,6 @@
import redisClient from '@/src/lib/redis-client'; import redisClient from '@/src/lib/redis-client';
import { db } from '@/src/db/db_index' import { db } from '../db/db_index'
import { userIncidents } from '@/src/db/schema' import { userIncidents } from '../db/schema'
import { eq, sum } from 'drizzle-orm'; import { eq, sum } from 'drizzle-orm';
export async function initializeUserNegativityStore(): Promise<void> { export async function initializeUserNegativityStore(): Promise<void> {

View file

@ -1,7 +1,7 @@
import { router, publicProcedure, protectedProcedure } from '@/src/trpc/trpc-index' import { router, publicProcedure, protectedProcedure } from '@/src/trpc/trpc-index'
import { commonRouter } from '@/src/trpc/apis/common-apis/common' import { commonRouter } from '@/src/trpc/apis/common-apis/common'
import { db } from '@/src/db/db_index' import { db } from '../../../db/db_index'
import { keyValStore, productInfo, storeInfo } from '@/src/db/schema' import { keyValStore, productInfo, storeInfo } from '../../../db/schema'
import * as turf from '@turf/turf'; import * as turf from '@turf/turf';
import { z } from 'zod'; import { z } from 'zod';
import { mbnrGeoJson } from '@/src/lib/mbnr-geojson' import { mbnrGeoJson } from '@/src/lib/mbnr-geojson'

View file

@ -1,6 +1,6 @@
import { router, publicProcedure } from '@/src/trpc/trpc-index' import { router, publicProcedure } from '@/src/trpc/trpc-index'
import { db } from '@/src/db/db_index' import { db } from '../../../db/db_index'
import { productInfo, units, productSlots, deliverySlotInfo, storeInfo } from '@/src/db/schema' import { productInfo, units, productSlots, deliverySlotInfo, storeInfo } from '../../../db/schema'
import { eq, gt, and, sql, inArray } from 'drizzle-orm'; import { eq, gt, and, sql, inArray } from 'drizzle-orm';
import { generateSignedUrlsFromS3Urls, generateSignedUrlFromS3Url } from '@/src/lib/s3-client' import { generateSignedUrlsFromS3Urls, generateSignedUrlFromS3Url } from '@/src/lib/s3-client'
import { getAllProducts as getAllProductsFromCache } from '@/src/stores/product-store' import { getAllProducts as getAllProductsFromCache } from '@/src/stores/product-store'
@ -16,7 +16,7 @@ export const getNextDeliveryDate = async (productId: number): Promise<Date | nul
eq(productSlots.productId, productId), eq(productSlots.productId, productId),
eq(deliverySlotInfo.isActive, true), eq(deliverySlotInfo.isActive, true),
eq(deliverySlotInfo.isCapacityFull, false), eq(deliverySlotInfo.isCapacityFull, false),
gt(deliverySlotInfo.deliveryTime, sql`NOW()`) gt(deliverySlotInfo.deliveryTime, new Date())
) )
) )
.orderBy(deliverySlotInfo.deliveryTime) .orderBy(deliverySlotInfo.deliveryTime)

View file

@ -0,0 +1,12 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/src/db/*": ["./src/db/*"],
"@/src/*": ["../backend/src/*"],
"@/src/trpc/*": ["../backend/src/trpc/*"],
"@/src/lib/*": ["../backend/src/lib/*"],
"@/src/stores/*": ["../backend/src/stores/*"]
}
}
}

View file

@ -2,8 +2,8 @@ import 'dotenv/config'
import { defineConfig } from 'drizzle-kit' import { defineConfig } from 'drizzle-kit'
export default defineConfig({ export default defineConfig({
out: './drizzle/sqlite', out: './drizzle',
schema: './src/db/schema-sqlite.ts', schema: './src/db/schema.ts',
dialect: 'sqlite', dialect: 'sqlite',
dbCredentials: { dbCredentials: {
url: process.env.SQLITE_DB_PATH!, url: process.env.SQLITE_DB_PATH!,

View file

@ -0,0 +1,9 @@
{
"name": "db-helper-sqlite",
"version": "0.1.0",
"private": true,
"type": "module",
"dependencies": {
"drizzle-orm": "^0.45.1"
}
}

View file

@ -0,0 +1,102 @@
import { and, eq, gt, inArray } from 'drizzle-orm'
import { db } from '../../db/db_index'
import { deliverySlotInfo, productInfo, productSlots, productTags, units } from '../../db/schema'
type ProductSummaryRow = {
id: number
name: string
shortDescription: string | null
price: string
marketPrice: string
images: string[]
isOutOfStock: boolean | null
unitShortNotation: string
productQuantity: number | null
nextDeliveryDate: Date | null
}
const normalizeImages = (images: string | null): string[] => {
if (!images) {
return []
}
try {
const parsed = JSON.parse(images)
if (Array.isArray(parsed)) {
return parsed.filter((value) => typeof value === 'string')
}
} catch (error) {
console.error('Failed to parse product images', error)
}
return []
}
const getNextDeliveryDate = async (productId: number): Promise<Date | null> => {
const result = await db
.select({ deliveryTime: deliverySlotInfo.deliveryTime })
.from(productSlots)
.innerJoin(deliverySlotInfo, eq(productSlots.slotId, deliverySlotInfo.id))
.where(
and(
eq(productSlots.productId, productId),
eq(deliverySlotInfo.isActive, true),
gt(deliverySlotInfo.deliveryTime, new Date())
)
)
.orderBy(deliverySlotInfo.deliveryTime)
.limit(1)
return result[0]?.deliveryTime || null
}
export const getProductsSummaryData = async (tagId?: number | null): Promise<ProductSummaryRow[]> => {
let productIds: number[] | null = null
if (tagId) {
const taggedProducts = await db
.select({ productId: productTags.productId })
.from(productTags)
.where(eq(productTags.tagId, tagId))
productIds = taggedProducts.map((taggedProduct) => taggedProduct.productId)
if (productIds.length === 0) {
return []
}
}
const whereCondition = productIds && productIds.length > 0
? inArray(productInfo.id, productIds)
: undefined
const productsWithUnits = await db
.select({
id: productInfo.id,
name: productInfo.name,
shortDescription: productInfo.shortDescription,
price: productInfo.price,
marketPrice: productInfo.marketPrice,
images: productInfo.images,
isOutOfStock: productInfo.isOutOfStock,
unitShortNotation: units.shortNotation,
productQuantity: productInfo.productQuantity,
})
.from(productInfo)
.innerJoin(units, eq(productInfo.unitId, units.id))
.where(whereCondition)
const productsWithDelivery = await Promise.all(
productsWithUnits.map(async (product) => {
const nextDeliveryDate = await getNextDeliveryDate(product.id)
return {
...product,
images: normalizeImages(product.images),
nextDeliveryDate,
}
})
)
return productsWithDelivery
}

View file

@ -1,8 +1,8 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { homeBanners } from '@/src/db/schema' import { homeBanners } from '../../db/schema'
import { eq, desc } from 'drizzle-orm' import { eq, desc } from 'drizzle-orm'
import { IBannerDbService, Banner, NewBanner } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/banner-db-service.interface' import { IBannerDbService, Banner, NewBanner } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/banner-db-service.interface'
import { toJsonString } from '@/src/db/sqlite-casts' import { toJsonString } from '../../db/sqlite-casts'
export class BannerDbService implements IBannerDbService { export class BannerDbService implements IBannerDbService {
async getAllBanners(): Promise<Banner[]> { async getAllBanners(): Promise<Banner[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { complaints, users } from '@/src/db/schema' import { complaints, users } from '../../db/schema'
import { eq, desc, lt } from 'drizzle-orm' import { eq, desc, lt } from 'drizzle-orm'
import { IComplaintDbService, Complaint, NewComplaint } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/complaint-db-service.interface' import { IComplaintDbService, Complaint, NewComplaint } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/complaint-db-service.interface'
export class ComplaintDbService implements IComplaintDbService { export class ComplaintDbService implements IComplaintDbService {
async getComplaints( async getComplaints(

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { keyValStore } from '@/src/db/schema' import { keyValStore } from '../../db/schema'
import { IConstantDbService, Constant, NewConstant } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/constant-db-service.interface' import { IConstantDbService, Constant, NewConstant } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/constant-db-service.interface'
import { toJsonString } from '@/src/db/sqlite-casts' import { toJsonString } from '../../db/sqlite-casts'
export class ConstantDbService implements IConstantDbService { export class ConstantDbService implements IConstantDbService {
async getAllConstants(): Promise<Constant[]> { async getAllConstants(): Promise<Constant[]> {

View file

@ -1,8 +1,8 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { coupons, couponApplicableUsers, couponApplicableProducts, reservedCoupons, users, orders, orderStatus } from '@/src/db/schema' import { coupons, couponApplicableUsers, couponApplicableProducts, reservedCoupons, users, orders, orderStatus } from '../../db/schema'
import { eq, and, like, or, inArray, lt, asc } from 'drizzle-orm' import { eq, and, like, or, inArray, lt, asc } from 'drizzle-orm'
import { ICouponDbService, Coupon, NewCoupon, ReservedCoupon, NewReservedCoupon, CouponWithRelations } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/coupon-db-service.interface' import { ICouponDbService, Coupon, NewCoupon, ReservedCoupon, NewReservedCoupon, CouponWithRelations } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/coupon-db-service.interface'
import { parseNumberArray, toJsonString } from '@/src/db/sqlite-casts' import { parseNumberArray, toJsonString } from '../../db/sqlite-casts'
export class CouponDbService implements ICouponDbService { export class CouponDbService implements ICouponDbService {
async createCoupon(data: NewCoupon): Promise<Coupon> { async createCoupon(data: NewCoupon): Promise<Coupon> {

View file

@ -1,4 +1,4 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { import {
orders, orders,
orderItems, orderItems,
@ -14,7 +14,7 @@ import {
productInfo, productInfo,
units, units,
paymentInfoTable, paymentInfoTable,
} from '@/src/db/schema' } from '../../db/schema'
import { eq, and, gte, lt, desc, inArray, SQL } from 'drizzle-orm' import { eq, and, gte, lt, desc, inArray, SQL } from 'drizzle-orm'
import { import {
IOrderDbService, IOrderDbService,
@ -26,7 +26,7 @@ import {
OrderWithRelations, OrderWithRelations,
OrderWithStatus, OrderWithStatus,
OrderWithCouponUsages, OrderWithCouponUsages,
} from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/order-db-service.interface' } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/order-db-service.interface'
export class OrderDbService implements IOrderDbService { export class OrderDbService implements IOrderDbService {
async updateOrderNotes(orderId: number, adminNotes: string | null): Promise<Order> { async updateOrderNotes(orderId: number, adminNotes: string | null): Promise<Order> {

View file

@ -1,8 +1,8 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { productInfo, units, specialDeals, productSlots, productTags, productReviews, productGroupInfo, productGroupMembership, users } from '@/src/db/schema' import { productInfo, units, specialDeals, productSlots, productTags, productReviews, productGroupInfo, productGroupMembership, users } from '../../db/schema'
import { eq, and, inArray, desc, sql } from 'drizzle-orm' import { eq, and, inArray, desc, sql } from 'drizzle-orm'
import { IProductDbService, Product, NewProduct, ProductGroup, NewProductGroup } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/product-db-service.interface' import { IProductDbService, Product, NewProduct, ProductGroup, NewProductGroup } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/product-db-service.interface'
import { toJsonString } from '@/src/db/sqlite-casts' import { toJsonString } from '../../db/sqlite-casts'
export class ProductDbService implements IProductDbService { export class ProductDbService implements IProductDbService {
async getAllProducts(): Promise<Product[]> { async getAllProducts(): Promise<Product[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { refunds, orders, orderStatus, payments } from '@/src/db/schema' import { refunds, orders, orderStatus, payments } from '../../db/schema'
import { eq, and } from 'drizzle-orm' import { eq, and } from 'drizzle-orm'
import { IRefundDbService, Refund, NewRefund } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/refund-db-service.interface' import { IRefundDbService, Refund, NewRefund } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/refund-db-service.interface'
export class RefundDbService implements IRefundDbService { export class RefundDbService implements IRefundDbService {
async createRefund(data: NewRefund): Promise<Refund> { async createRefund(data: NewRefund): Promise<Refund> {

View file

@ -1,8 +1,8 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { productAvailabilitySchedules } from '@/src/db/schema' import { productAvailabilitySchedules } from '../../db/schema'
import { eq, desc } from 'drizzle-orm' import { eq, desc } from 'drizzle-orm'
import { IScheduleDbService, Schedule, NewSchedule } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/schedule-db-service.interface' import { IScheduleDbService, Schedule, NewSchedule } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/schedule-db-service.interface'
import { toJsonString } from '@/src/db/sqlite-casts' import { toJsonString } from '../../db/sqlite-casts'
export class ScheduleDbService implements IScheduleDbService { export class ScheduleDbService implements IScheduleDbService {
async createSchedule(data: NewSchedule): Promise<Schedule> { async createSchedule(data: NewSchedule): Promise<Schedule> {

View file

@ -1,8 +1,8 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { deliverySlotInfo, productSlots, vendorSnippets, productInfo, productGroupInfo } from '@/src/db/schema' import { deliverySlotInfo, productSlots, vendorSnippets, productInfo, productGroupInfo } from '../../db/schema'
import { eq, inArray, and, desc } from 'drizzle-orm' import { eq, inArray, and, desc } from 'drizzle-orm'
import { ISlotDbService, Slot, NewSlot, ProductSlot, SlotWithRelations } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/slot-db-service.interface' import { ISlotDbService, Slot, NewSlot, ProductSlot, SlotWithRelations } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/slot-db-service.interface'
import { parseNumberArray, toJsonString } from '@/src/db/sqlite-casts' import { parseNumberArray, toJsonString } from '../../db/sqlite-casts'
export class SlotDbService implements ISlotDbService { export class SlotDbService implements ISlotDbService {
async getAllSlots(): Promise<SlotWithRelations[]> { async getAllSlots(): Promise<SlotWithRelations[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { staffUsers, staffRoles, users, userDetails, orders } from '@/src/db/schema' import { staffUsers, staffRoles, users, userDetails, orders } from '../../db/schema'
import { eq, or, like, and, lt, desc } from 'drizzle-orm' import { eq, or, like, and, lt, desc } from 'drizzle-orm'
import { IStaffUserDbService, StaffUser, NewStaffUser, StaffRole, StaffUserWithRole } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/staff-user-db-service.interface' import { IStaffUserDbService, StaffUser, NewStaffUser, StaffRole, StaffUserWithRole } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/staff-user-db-service.interface'
export class StaffUserDbService implements IStaffUserDbService { export class StaffUserDbService implements IStaffUserDbService {
async getStaffUserByName(name: string): Promise<StaffUser | undefined> { async getStaffUserByName(name: string): Promise<StaffUser | undefined> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { storeInfo, productInfo } from '@/src/db/schema' import { storeInfo, productInfo } from '../../db/schema'
import { eq, inArray } from 'drizzle-orm' import { eq, inArray } from 'drizzle-orm'
import { IStoreDbService, Store, NewStore } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/store-db-service.interface' import { IStoreDbService, Store, NewStore } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/store-db-service.interface'
export class StoreDbService implements IStoreDbService { export class StoreDbService implements IStoreDbService {
async getAllStores(): Promise<Store[]> { async getAllStores(): Promise<Store[]> {

View file

@ -1,8 +1,8 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { productTagInfo } from '@/src/db/schema' import { productTagInfo } from '../../db/schema'
import { eq } from 'drizzle-orm' import { eq } from 'drizzle-orm'
import { ITagDbService, Tag, NewTag } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/tag-db-service.interface' import { ITagDbService, Tag, NewTag } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/tag-db-service.interface'
import { toJsonString } from '@/src/db/sqlite-casts' import { toJsonString } from '../../db/sqlite-casts'
export class TagDbService implements ITagDbService { export class TagDbService implements ITagDbService {
async getAllTags(): Promise<Tag[]> { async getAllTags(): Promise<Tag[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { users, userDetails, orders, orderItems, orderStatus, complaints, notifCreds, unloggedUserTokens, userIncidents } from '@/src/db/schema' import { users, userDetails, orders, orderItems, orderStatus, complaints, notifCreds, unloggedUserTokens, userIncidents } from '../../db/schema'
import { eq, desc, asc, count, max, inArray, and, like, gt } from 'drizzle-orm' import { eq, desc, asc, count, max, inArray, and, like, gt } from 'drizzle-orm'
import { IUserDbService, User, NewUser, UserDetail } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/user-db-service.interface' import { IUserDbService, User, NewUser, UserDetail } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/user-db-service.interface'
export class UserDbService implements IUserDbService { export class UserDbService implements IUserDbService {
async getUserById(id: number): Promise<User | undefined> { async getUserById(id: number): Promise<User | undefined> {

View file

@ -1,8 +1,8 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { vendorSnippets, deliverySlotInfo, orders, orderItems, productInfo } from '@/src/db/schema' import { vendorSnippets, deliverySlotInfo, orders, orderItems, productInfo } from '../../db/schema'
import { eq, and, inArray, gt, asc, desc } from 'drizzle-orm' import { eq, and, inArray, gt, asc, desc } from 'drizzle-orm'
import { IVendorSnippetDbService, VendorSnippet, NewVendorSnippet } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/vendor-snippet-db-service.interface' import { IVendorSnippetDbService, VendorSnippet, NewVendorSnippet } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/vendor-snippet-db-service.interface'
import { toJsonString } from '@/src/db/sqlite-casts' import { toJsonString } from '../../db/sqlite-casts'
export class VendorSnippetDbService implements IVendorSnippetDbService { export class VendorSnippetDbService implements IVendorSnippetDbService {
async createSnippet(data: NewVendorSnippet): Promise<VendorSnippet> { async createSnippet(data: NewVendorSnippet): Promise<VendorSnippet> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { addresses, orders, orderStatus, deliverySlotInfo } from '@/src/db/schema' import { addresses, orders, orderStatus, deliverySlotInfo } from '../../db/schema'
import { eq, and, gte } from 'drizzle-orm' import { eq, and, gte } from 'drizzle-orm'
import { IUserAddressDbService, Address, NewAddress } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-address-db-service.interface' import { IUserAddressDbService, Address, NewAddress } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-address-db-service.interface'
export class UserAddressDbService implements IUserAddressDbService { export class UserAddressDbService implements IUserAddressDbService {
async getDefaultAddress(userId: number): Promise<Address | undefined> { async getDefaultAddress(userId: number): Promise<Address | undefined> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { users, userCreds, userDetails, addresses, cartItems, complaints, couponApplicableUsers, couponUsage, notifCreds, notifications, orderItems, orderStatus, orders, payments, refunds, productReviews, reservedCoupons } from '@/src/db/schema' import { users, userCreds, userDetails, addresses, cartItems, complaints, couponApplicableUsers, couponUsage, notifCreds, notifications, orderItems, orderStatus, orders, payments, refunds, productReviews, reservedCoupons } from '../../db/schema'
import { eq } from 'drizzle-orm' import { eq } from 'drizzle-orm'
import { IUserAuthDbService, User, UserCred, UserDetail } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-auth-db-service.interface' import { IUserAuthDbService, User, UserCred, UserDetail } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-auth-db-service.interface'
export class UserAuthDbService implements IUserAuthDbService { export class UserAuthDbService implements IUserAuthDbService {
async getUserByEmail(email: string): Promise<User | undefined> { async getUserByEmail(email: string): Promise<User | undefined> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { homeBanners } from '@/src/db/schema' import { homeBanners } from '../../db/schema'
import { isNotNull, asc } from 'drizzle-orm' import { isNotNull, asc } from 'drizzle-orm'
import { IUserBannerDbService, UserBanner } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-banner-db-service.interface' import { IUserBannerDbService, UserBanner } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-banner-db-service.interface'
export class UserBannerDbService implements IUserBannerDbService { export class UserBannerDbService implements IUserBannerDbService {
async getActiveBanners(): Promise<UserBanner[]> { async getActiveBanners(): Promise<UserBanner[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { cartItems, productInfo, units } from '@/src/db/schema' import { cartItems, productInfo, units } from '../../db/schema'
import { eq, and, sql } from 'drizzle-orm' import { eq, and, sql } from 'drizzle-orm'
import { IUserCartDbService, CartItem } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-cart-db-service.interface' import { IUserCartDbService, CartItem } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-cart-db-service.interface'
export class UserCartDbService implements IUserCartDbService { export class UserCartDbService implements IUserCartDbService {
async getCartItemsWithProducts(userId: number) { async getCartItemsWithProducts(userId: number) {

View file

@ -1,7 +1,8 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { complaints } from '@/src/db/schema' import { complaints } from '../../db/schema'
import { eq, asc } from 'drizzle-orm' import { eq, asc } from 'drizzle-orm'
import { IUserComplaintDbService } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-complaint-db-service.interface' import { IUserComplaintDbService, NewComplaint } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-complaint-db-service.interface'
import { toJsonString } from '../../db/sqlite-casts'
export class UserComplaintDbService implements IUserComplaintDbService { export class UserComplaintDbService implements IUserComplaintDbService {
async getComplaintsByUserId(userId: number) { async getComplaintsByUserId(userId: number) {
@ -20,8 +21,12 @@ export class UserComplaintDbService implements IUserComplaintDbService {
.orderBy(asc(complaints.createdAt)) .orderBy(asc(complaints.createdAt))
} }
async createComplaint(data: { userId: number; orderId?: number | null; complaintBody: string; images: string[] }) { async createComplaint(data: NewComplaint) {
await db.insert(complaints).values(data) const normalized = {
...data,
images: data.images ? toJsonString(data.images, '[]') : data.images,
}
await db.insert(complaints).values(normalized)
} }
} }

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { coupons, couponUsage, couponApplicableUsers, couponApplicableProducts, reservedCoupons } from '@/src/db/schema' import { coupons, couponUsage, couponApplicableUsers, couponApplicableProducts, reservedCoupons } from '../../db/schema'
import { eq, and, or, gt, isNull } from 'drizzle-orm' import { eq, and, or, gt, isNull } from 'drizzle-orm'
import { IUserCouponDbService, Coupon, ReservedCoupon, CouponWithRelations } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-coupon-db-service.interface' import { IUserCouponDbService, Coupon, ReservedCoupon, CouponWithRelations } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-coupon-db-service.interface'
export class UserCouponDbService implements IUserCouponDbService { export class UserCouponDbService implements IUserCouponDbService {
async getActiveCouponsForUser(userId: number): Promise<CouponWithRelations[]> { async getActiveCouponsForUser(userId: number): Promise<CouponWithRelations[]> {

View file

@ -1,4 +1,4 @@
import { db } from '@/src/db/db_index' import { db } from '../../db/db_index'
import { import {
orders, orders,
orderItems, orderItems,
@ -12,12 +12,12 @@ import {
refunds, refunds,
units, units,
userDetails, userDetails,
} from '@/src/db/schema' } from '../../db/schema'
import { and, desc, eq, gte, inArray } from 'drizzle-orm' import { and, desc, eq, gte, inArray } from 'drizzle-orm'
import { import {
IUserOrderDbService, IUserOrderDbService,
Order, Order,
} from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-order-db-service.interface' } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-order-db-service.interface'
export class UserOrderDbService implements IUserOrderDbService { export class UserOrderDbService implements IUserOrderDbService {
async getUserDetailByUserId(userId: number) { async getUserDetailByUserId(userId: number) {

View file

@ -1,7 +1,8 @@
import { db } from '@/src/db/db_index_sqlite' import { db } from '../../db/db_index'
import { productInfo, units, storeInfo, productSlots, deliverySlotInfo, specialDeals, productReviews, users } from '@/src/db/schema' import { productInfo, units, storeInfo, productSlots, deliverySlotInfo, specialDeals, productReviews, users } from '../../db/schema'
import { eq, and, gt, sql, desc } from 'drizzle-orm' import { eq, and, gt, sql, desc } from 'drizzle-orm'
import { IUserProductDbService, Review } from '@/src/trpc/apis/user-apis/dataAccessors/interfaces/user-product-db-service.interface' import { toJsonString } from '../../db/sqlite-casts'
import { IUserProductDbService, Review } from '../../../../backend/src/trpc/apis/user-apis/dataAccessors/interfaces/user-product-db-service.interface'
export class UserProductDbService implements IUserProductDbService { export class UserProductDbService implements IUserProductDbService {
async getProductById(productId: number) { async getProductById(productId: number) {
@ -103,7 +104,11 @@ export class UserProductDbService implements IUserProductDbService {
} }
async createReview(data: { userId: number; productId: number; reviewBody: string; ratings: number; imageUrls: string[] }): Promise<Review> { async createReview(data: { userId: number; productId: number; reviewBody: string; ratings: number; imageUrls: string[] }): Promise<Review> {
const [newReview] = await db.insert(productReviews).values(data).returning() const normalized = {
...data,
imageUrls: toJsonString(data.imageUrls, '[]'),
}
const [newReview] = await db.insert(productReviews).values(normalized).returning()
return newReview return newReview
} }
} }

Some files were not shown because too many files have changed in this diff Show more