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
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
SQLITE_DB_PATH='./sqlite.db'
DB_DIALECT='sqlite'
PHONE_PE_BASE_URL=https://api-preprod.phonepe.com/
PHONE_PE_CLIENT_ID=TEST-M23F2IGP34ZAR_25090
PHONE_PE_CLIENT_VERSION=1
PHONE_PE_CLIENT_SECRET=MTU1MmIzOTgtM2Q0Mi00N2M5LTkyMWUtNzBiMjdmYzVmZWUy

View file

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

View file

@ -157,7 +157,6 @@ app.onError((err, c) => {
return c.json({ message }, status)
})
<<<<<<< HEAD
// Start server
serve({
fetch: app.fetch,
@ -166,8 +165,3 @@ serve({
})
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",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"migrate": "drizzle-kit generate --config drizzle.config.postgres.ts",
"migrate:pg": "drizzle-kit generate --config drizzle.config.postgres.ts",
"migrate:sqlite": "drizzle-kit generate --config drizzle.config.sqlite.ts",
"generate:pg": "bunx drizzle-kit generate --config drizzle.config.postgres.ts",
"generate:sqlite": "bunx drizzle-kit generate --config drizzle.config.sqlite.ts",
"migrate": "drizzle-kit generate --config ../db-helper-postgres/drizzle.config.ts",
"migrate:pg": "drizzle-kit generate --config ../db-helper-postgres/drizzle.config.ts",
"migrate:sqlite": "drizzle-kit generate --config ../db-helper-sqlite/drizzle.config.ts",
"generate:pg": "bunx drizzle-kit generate --config ../db-helper-postgres/drizzle.config.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",
"build2": "rimraf ./dist && tsc",
"db:push": "drizzle-kit push --config drizzle.config.postgres.ts",
"db:push:pg": "drizzle-kit push --config drizzle.config.postgres.ts",
"db:push:sqlite": "drizzle-kit push --config drizzle.config.sqlite.ts",
"db:push": "drizzle-kit push --config ../db-helper-postgres/drizzle.config.ts",
"db:push:pg": "drizzle-kit push --config ../db-helper-postgres/drizzle.config.ts",
"db:push:sqlite": "drizzle-kit push --config ../db-helper-sqlite/drizzle.config.ts",
"db:seed": "tsx src/db/seed.ts",
"dev:express": "bun --watch index-express.ts",
"dev:hono": "bun --watch index.ts",
@ -46,7 +46,6 @@
"jose": "^5.10.0",
"node-cron": "^4.2.1",
"pg": "^8.16.3",
"razorpay": "^2.9.6",
"redis": "^5.9.0",
"zod": "^4.1.12"
},

BIN
apps/backend/sqlite.db Normal file

Binary file not shown.

View file

@ -1,105 +1,37 @@
import { eq, gt, and, sql, inArray } from "drizzle-orm";
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 { Context } from 'hono'
/**
* Get next delivery date for a product
*/
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;
};
import { getProductsSummaryData } from '@/src/db/common-product'
import { scaffoldAssetUrl } from '@/src/lib/s3-client'
/**
* Get all products summary for dropdown
*/
export const getAllProductsSummary = async (c: Context) => {
try {
const tagId = c.req.query('tagId');
const tagIdNum = tagId ? parseInt(tagId) : null;
const tagId = c.req.query('tagId')
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
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,
name: product.name,
shortDescription: product.shortDescription,
price: product.price,
marketPrice: product.marketPrice,
unit: product.unitShortNotation,
productQuantity: product.productQuantity,
isOutOfStock: product.isOutOfStock,
nextDeliveryDate: nextDeliveryDate ? nextDeliveryDate.toISOString() : null,
images: scaffoldAssetUrl((product.images as string[]) || []),
};
})
);
const formattedProducts = productsWithUnits.map((product) => ({
id: product.id,
name: product.name,
shortDescription: product.shortDescription,
price: product.price,
marketPrice: product.marketPrice,
unit: product.unitShortNotation,
productQuantity: product.productQuantity,
isOutOfStock: product.isOutOfStock,
nextDeliveryDate: product.nextDeliveryDate ? product.nextDeliveryDate.toISOString() : null,
images: scaffoldAssetUrl((product.images as string[]) || []),
}))
return c.json({
products: formattedProducts,
count: formattedProducts.length,
});
})
} catch (error) {
console.error("Get products summary error:", error);
return c.json({ error: "Failed to fetch products summary" }, 500);
console.error('Get products summary error:', error)
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 { migrate } from "drizzle-orm/node-postgres/migrator"
import path from "path"
import * as schema from "@/src/db/schema-postgres"
import { db as postgresDb } from '@db-helper-postgres/db/db_index'
import { db as sqliteDb } from '@db-helper-sqlite/db/db_index'
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 }

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";
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, ({}) => ({
}));
export * from '@/db-helper-postgres/db/schema'

View file

@ -1,735 +1 @@
import {
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),
}))
export * from '@/db-helper-sqlite/db/schema'

View file

@ -1,138 +1,8 @@
import { db } from "@/src/db/db_index"
import { units, productInfo, deliverySlotInfo, productSlots, keyValStore, staffRoles, staffPermissions, staffRolePermissions } from "@/src/db/schema"
import { eq } from "drizzle-orm";
import { minOrderValue, deliveryCharge } from '@/src/lib/env-exporter'
import { CONST_KEYS } from '@/src/lib/const-keys'
import { seed as seedPostgres } from '@db-helper-postgres/db/seed'
import { seed as seedSqlite } from '@db-helper-sqlite/db/seed'
export async function seed() {
console.log("Seeding database...");
const dialect = process.env.DB_DIALECT || DB_DIALECT_TYPE
// Seed units individually
const unitsToSeed = [
{ shortNotation: "Kg", fullName: "Kilogram" },
{ shortNotation: "L", fullName: "Litre" },
{ shortNotation: "Dz", fullName: "Dozen" },
{ shortNotation: "Pc", fullName: "Unit Piece" },
];
const seedImpl = dialect === 'sqlite' ? seedSqlite : seedPostgres
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);
}
}
// 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.");
}
export const seed = async () => seedImpl()

View file

@ -1,34 +1 @@
export const parseJsonValue = <T>(value: unknown, fallback: T): T => {
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)
}
export * from '@/db-helper-sqlite/db/sqlite-casts'

View file

@ -1,47 +1,58 @@
import type { InferSelectModel } from "drizzle-orm";
import type {
users,
addresses,
units,
productInfo,
deliverySlotInfo,
productSlots,
specialDeals,
orders,
orderItems,
payments,
notifications,
productCategories,
cartItems,
coupons,
} from "@/src/db/schema";
User as PostgresUser,
Address as PostgresAddress,
Unit as PostgresUnit,
ProductInfo as PostgresProductInfo,
DeliverySlotInfo as PostgresDeliverySlotInfo,
ProductSlot as PostgresProductSlot,
SpecialDeal as PostgresSpecialDeal,
Order as PostgresOrder,
OrderItem as PostgresOrderItem,
Payment as PostgresPayment,
Notification as PostgresNotification,
ProductCategory as PostgresProductCategory,
CartItem as PostgresCartItem,
Coupon as PostgresCoupon,
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>;
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>;
type UseSqlite = typeof DB_DIALECT_TYPE extends 'sqlite' ? true : false
// Combined types
export type ProductWithUnit = ProductInfo & {
unit: Unit;
};
export type OrderWithItems = Order & {
items: (OrderItem & { product: ProductInfo })[];
address: Address;
slot: DeliverySlotInfo;
};
export type CartItemWithProduct = CartItem & {
product: ProductInfo;
};
export type User = UseSqlite extends true ? SqliteUser : PostgresUser
export type Address = UseSqlite extends true ? SqliteAddress : PostgresAddress
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 ProductSlot = UseSqlite extends true ? SqliteProductSlot : PostgresProductSlot
export type SpecialDeal = UseSqlite extends true ? SqliteSpecialDeal : PostgresSpecialDeal
export type Order = UseSqlite extends true ? SqliteOrder : PostgresOrder
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 ProductCategory = UseSqlite extends true ? SqliteProductCategory : PostgresProductCategory
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 { db } from "@/src/db/db_index"
import { deleteImageUtil, getOriginalUrlFromSignedUrl } from "@/src/lib/s3-client"
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 {
try {
// 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
// const comIndex = originalUrl.indexOf(".com/");
const baseUrlIndex = originalUrl.indexOf(s3Url);
const baseUrlIndex = originalUrl.indexOf(s3Url)
// If '.com/' is found, return everything after it
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) {
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;
return null
}
export async function deleteS3Image(imageUrl: string) {
try {
let key:string | null = '';
let key: string | null = ''
if(imageUrl.includes(assetsDomain)) {
if (imageUrl.includes(assetsDomain)) {
key = imageUrl.replace(assetsDomain, '')
}
else if(imageUrl.startsWith('http')){
// First check if this is a signed URL and get the original if it is
const originalUrl = getOriginalUrlFromSignedUrl(imageUrl) || imageUrl;
else if (imageUrl.startsWith('http')) {
// First check if this is a signed URL and get the original if it is
const originalUrl = getOriginalUrlFromSignedUrl(imageUrl) || imageUrl
key = extractS3Key(originalUrl || "");
key = extractS3Key(originalUrl || '')
}
else {
key = imageUrl;
key = imageUrl
}
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) {
throw new Error("Failed to delete image from S3");
throw new Error('Failed to delete image from S3')
}
} 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 { eq, inArray } from "drizzle-orm";
// Core notification dispatch methods (renamed for clarity)
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
*/

View file

@ -3,9 +3,7 @@ import { DeleteObjectCommand, DeleteObjectsCommand, PutObjectCommand, S3Client,
import { getSignedUrl } from "@aws-sdk/s3-request-presigner"
import signedUrlCache from "@/src/lib/signed-url-cache"
import { s3AccessKeyId, s3Region, s3Url, s3SecretAccessKey, s3BucketName, assetsDomain } from "@/src/lib/env-exporter"
import { db } from "@/src/db/db_index"; // Adjust path if needed
import { uploadUrlStatus } from "@/src/db/schema"
import { and, eq } from 'drizzle-orm';
import { claimUploadUrlStatus, createUploadUrlStatus } from '@/src/db/upload-url'
const s3Client = new S3Client({
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> {
try {
// Insert record into upload_url_status
await db.insert(uploadUrlStatus).values({
key: key,
status: 'pending',
});
await createUploadUrlStatus(key)
// Generate signed upload URL
const command = new PutObjectCommand({
@ -207,16 +202,7 @@ export async function claimUploadUrl(url: string): Promise<void> {
semiKey = extractKeyFromPresignedUrl(url);
else
semiKey = url
// Update status to 'claimed' if currently 'pending'
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');
}
await claimUploadUrlStatus(semiKey)
} catch (error) {
console.error('Error claiming upload URL:', error);
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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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": ".",
"paths": {
"@/*": ["./*"],
"@db-helper-postgres/*": ["../db-helper-postgres/src/*"],
"@db-helper-sqlite/*": ["../db-helper-sqlite/src/*"],
"shared-types": ["../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"]
}

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'
export default defineConfig({
out: './drizzle/pg',
schema: './src/db/schema-postgres.ts',
out: './drizzle',
schema: './src/db/schema.ts',
dialect: 'postgresql',
dbCredentials: {
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 { homeBanners } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { homeBanners } from '../../db/schema'
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 {
async getAllBanners(): Promise<Banner[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite'
import { complaints, users } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { complaints, users } from '../../db/schema'
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 {
async getComplaints(

View file

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

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { coupons, couponApplicableUsers, couponApplicableProducts, reservedCoupons, users, orders, orderStatus } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { coupons, couponApplicableUsers, couponApplicableProducts, reservedCoupons, users, orders, orderStatus } from '../../db/schema'
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 {
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 {
orders,
orderItems,
@ -14,7 +14,7 @@ import {
productInfo,
units,
paymentInfoTable,
} from '@/src/db/schema'
} from '../../db/schema'
import { eq, and, gte, lt, desc, inArray, SQL } from 'drizzle-orm'
import {
IOrderDbService,
@ -26,7 +26,7 @@ import {
OrderWithRelations,
OrderWithStatus,
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 {
async updateOrderNotes(orderId: number, adminNotes: string | null): Promise<Order> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { productInfo, units, specialDeals, productSlots, productTags, productReviews, productGroupInfo, productGroupMembership, users } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { productInfo, units, specialDeals, productSlots, productTags, productReviews, productGroupInfo, productGroupMembership, users } from '../../db/schema'
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 {
async getAllProducts(): Promise<Product[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { refunds, orders, orderStatus, payments } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { refunds, orders, orderStatus, payments } from '../../db/schema'
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 {
async createRefund(data: NewRefund): Promise<Refund> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { productAvailabilitySchedules } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { productAvailabilitySchedules } from '../../db/schema'
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 {
async createSchedule(data: NewSchedule): Promise<Schedule> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { deliverySlotInfo, productSlots, vendorSnippets, productInfo, productGroupInfo } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { deliverySlotInfo, productSlots, vendorSnippets, productInfo, productGroupInfo } from '../../db/schema'
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 {
async getAllSlots(): Promise<SlotWithRelations[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { staffUsers, staffRoles, users, userDetails, orders } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { staffUsers, staffRoles, users, userDetails, orders } from '../../db/schema'
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 {
async getStaffUserByName(name: string): Promise<StaffUser | undefined> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite'
import { storeInfo, productInfo } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { storeInfo, productInfo } from '../../db/schema'
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 {
async getAllStores(): Promise<Store[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { productTagInfo } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { productTagInfo } from '../../db/schema'
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 {
async getAllTags(): Promise<Tag[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { users, userDetails, orders, orderItems, orderStatus, complaints, notifCreds, unloggedUserTokens, userIncidents } from '@/src/db/schema'
import { db } from '../../db/db_index'
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 { 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 {
async getUserById(id: number): Promise<User | undefined> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { vendorSnippets, deliverySlotInfo, orders, orderItems, productInfo } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { vendorSnippets, deliverySlotInfo, orders, orderItems, productInfo } from '../../db/schema'
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 {
async createSnippet(data: NewVendorSnippet): Promise<VendorSnippet> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { addresses, orders, orderStatus, deliverySlotInfo } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { addresses, orders, orderStatus, deliverySlotInfo } from '../../db/schema'
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 {
async getDefaultAddress(userId: number): Promise<Address | undefined> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/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 { db } from '../../db/db_index'
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 { 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 {
async getUserByEmail(email: string): Promise<User | undefined> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite'
import { homeBanners } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { homeBanners } from '../../db/schema'
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 {
async getActiveBanners(): Promise<UserBanner[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { cartItems, productInfo, units } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { cartItems, productInfo, units } from '../../db/schema'
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 {
async getCartItemsWithProducts(userId: number) {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { complaints } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { complaints } from '../../db/schema'
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 {
async getComplaintsByUserId(userId: number) {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite'
import { coupons, couponUsage, couponApplicableUsers, couponApplicableProducts, reservedCoupons } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { coupons, couponUsage, couponApplicableUsers, couponApplicableProducts, reservedCoupons } from '../../db/schema'
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 {
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 {
orders,
orderItems,
@ -12,12 +12,12 @@ import {
refunds,
units,
userDetails,
} from '@/src/db/schema'
} from '../../db/schema'
import { and, desc, eq, gte, inArray } from 'drizzle-orm'
import {
IUserOrderDbService,
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 {
async getUserDetailByUserId(userId: number) {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { productInfo, units, storeInfo, productSlots, deliverySlotInfo, specialDeals, productReviews, users } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { productInfo, units, storeInfo, productSlots, deliverySlotInfo, specialDeals, productReviews, users } from '../../db/schema'
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 {
async getProductById(productId: number) {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { users, userDetails, userCreds, notifCreds, unloggedUserTokens } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { users, userDetails, userCreds, notifCreds, unloggedUserTokens } from '../../db/schema'
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 {
async getUserById(userId: number): Promise<User | undefined> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { deliverySlotInfo, productInfo } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { deliverySlotInfo, productInfo } from '../../db/schema'
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 {
async getActiveSlots(): Promise<Slot[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite'
import { storeInfo, productInfo, units } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { storeInfo, productInfo, units } from '../../db/schema'
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 {
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
*/
import { db } from '@/src/db/db_index'
import { db } from './db_index'
import {
userDetails,
productInfo,
productTagInfo,
complaints
} from '@/src/db/schema';
} from './schema';
import { eq, not, isNull } from 'drizzle-orm';
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 { db } from '@/src/db/db_index'
import { productInfo, productAvailabilitySchedules } from '@/src/db/schema'
import { db } from '../db/db_index'
import { productInfo, productAvailabilitySchedules } from '../db/schema'
import { inArray } from 'drizzle-orm';
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 { scaffoldBanners } from '@/src/trpc/apis/user-apis/apis/banners'
import { scaffoldStoreWithProducts } from '@/src/trpc/apis/user-apis/apis/stores'
import { storeInfo } from '@/src/db/schema'
import { db } from '@/src/db/db_index'
import { storeInfo } from '../db/schema'
import { db } from '../db/db_index'
import { imageUploadS3 } from '@/src/lib/s3-client'
import { apiCacheKey, cloudflareApiToken, cloudflareZoneId, assetsDomain } from '@/src/lib/env-exporter'
import { CACHE_FILENAMES } from '@packages/shared'

View file

@ -1,5 +1,5 @@
import { db } from '@/src/db/db_index'
import { keyValStore } from '@/src/db/schema'
import { db } from '../db/db_index'
import { keyValStore } from '../db/schema'
import redisClient from '@/src/lib/redis-client'
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 { orders, orderItems, orderStatus, payments, refunds, couponUsage, complaints } from '@/src/db/schema'
import { db } from '../db/db_index'
import { orders, orderItems, orderStatus, payments, refunds, couponUsage, complaints } from '../db/schema'
import { eq, inArray } from 'drizzle-orm';
/**

View file

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

View file

@ -1,7 +1,7 @@
import { Queue, Worker } from 'bullmq';
import { Expo } from 'expo-server-sdk';
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 {
NOTIFS_QUEUE,

View file

@ -1,5 +1,5 @@
import { db } from '@/src/db/db_index'
import { orders, orderStatus } from '@/src/db/schema'
import { db } from '../db/db_index'
import { orders, orderStatus } from '../db/schema'
import redisClient from '@/src/lib/redis-client'
import { sendTelegramMessage } from '@/src/lib/telegram-service'
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 { db } from '@/src/db/db_index'
import { staffUsers, userDetails } from '@/src/db/schema'
import { db } from '../db/db_index'
import { staffUsers, userDetails } from '../db/schema'
import { eq } from 'drizzle-orm'
import { ApiError } from '@/src/lib/api-error'
import { verifyToken, UserJWTPayload, StaffJWTPayload } from '@/src/lib/jwt-utils'

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
import { router, publicProcedure } from '@/src/trpc/trpc-index'
import { db } from '@/src/db/db_index'
import { productInfo, units, productSlots, deliverySlotInfo, storeInfo } from '@/src/db/schema'
import { db } from '../../../db/db_index'
import { productInfo, units, productSlots, deliverySlotInfo, storeInfo } from '../../../db/schema'
import { eq, gt, and, sql, inArray } from 'drizzle-orm';
import { generateSignedUrlsFromS3Urls, generateSignedUrlFromS3Url } from '@/src/lib/s3-client'
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(deliverySlotInfo.isActive, true),
eq(deliverySlotInfo.isCapacityFull, false),
gt(deliverySlotInfo.deliveryTime, sql`NOW()`)
gt(deliverySlotInfo.deliveryTime, new Date())
)
)
.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'
export default defineConfig({
out: './drizzle/sqlite',
schema: './src/db/schema-sqlite.ts',
out: './drizzle',
schema: './src/db/schema.ts',
dialect: 'sqlite',
dbCredentials: {
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 { homeBanners } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { homeBanners } from '../../db/schema'
import { eq, desc } from 'drizzle-orm'
import { IBannerDbService, Banner, NewBanner } from '@/src/trpc/apis/admin-apis/dataAccessors/interfaces/banner-db-service.interface'
import { toJsonString } from '@/src/db/sqlite-casts'
import { IBannerDbService, Banner, NewBanner } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/banner-db-service.interface'
import { toJsonString } from '../../db/sqlite-casts'
export class BannerDbService implements IBannerDbService {
async getAllBanners(): Promise<Banner[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { complaints, users } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { complaints, users } from '../../db/schema'
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 {
async getComplaints(

View file

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

View file

@ -1,8 +1,8 @@
import { db } from '@/src/db/db_index_sqlite'
import { coupons, couponApplicableUsers, couponApplicableProducts, reservedCoupons, users, orders, orderStatus } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { coupons, couponApplicableUsers, couponApplicableProducts, reservedCoupons, users, orders, orderStatus } from '../../db/schema'
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 { parseNumberArray, toJsonString } from '@/src/db/sqlite-casts'
import { ICouponDbService, Coupon, NewCoupon, ReservedCoupon, NewReservedCoupon, CouponWithRelations } from '../../../../backend/src/trpc/apis/admin-apis/dataAccessors/interfaces/coupon-db-service.interface'
import { parseNumberArray, toJsonString } from '../../db/sqlite-casts'
export class CouponDbService implements ICouponDbService {
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 {
orders,
orderItems,
@ -14,7 +14,7 @@ import {
productInfo,
units,
paymentInfoTable,
} from '@/src/db/schema'
} from '../../db/schema'
import { eq, and, gte, lt, desc, inArray, SQL } from 'drizzle-orm'
import {
IOrderDbService,
@ -26,7 +26,7 @@ import {
OrderWithRelations,
OrderWithStatus,
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 {
async updateOrderNotes(orderId: number, adminNotes: string | null): Promise<Order> {

View file

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

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite'
import { refunds, orders, orderStatus, payments } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { refunds, orders, orderStatus, payments } from '../../db/schema'
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 {
async createRefund(data: NewRefund): Promise<Refund> {

View file

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

View file

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

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite'
import { staffUsers, staffRoles, users, userDetails, orders } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { staffUsers, staffRoles, users, userDetails, orders } from '../../db/schema'
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 {
async getStaffUserByName(name: string): Promise<StaffUser | undefined> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { storeInfo, productInfo } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { storeInfo, productInfo } from '../../db/schema'
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 {
async getAllStores(): Promise<Store[]> {

View file

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

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite'
import { users, userDetails, orders, orderItems, orderStatus, complaints, notifCreds, unloggedUserTokens, userIncidents } from '@/src/db/schema'
import { db } from '../../db/db_index'
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 { 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 {
async getUserById(id: number): Promise<User | undefined> {

View file

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

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite'
import { addresses, orders, orderStatus, deliverySlotInfo } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { addresses, orders, orderStatus, deliverySlotInfo } from '../../db/schema'
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 {
async getDefaultAddress(userId: number): Promise<Address | undefined> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite'
import { users, userCreds, userDetails, addresses, cartItems, complaints, couponApplicableUsers, couponUsage, notifCreds, notifications, orderItems, orderStatus, orders, payments, refunds, productReviews, reservedCoupons } from '@/src/db/schema'
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 '../../db/schema'
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 {
async getUserByEmail(email: string): Promise<User | undefined> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index'
import { homeBanners } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { homeBanners } from '../../db/schema'
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 {
async getActiveBanners(): Promise<UserBanner[]> {

View file

@ -1,7 +1,7 @@
import { db } from '@/src/db/db_index_sqlite'
import { cartItems, productInfo, units } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { cartItems, productInfo, units } from '../../db/schema'
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 {
async getCartItemsWithProducts(userId: number) {

View file

@ -1,7 +1,8 @@
import { db } from '@/src/db/db_index_sqlite'
import { complaints } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { complaints } from '../../db/schema'
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 {
async getComplaintsByUserId(userId: number) {
@ -20,8 +21,12 @@ export class UserComplaintDbService implements IUserComplaintDbService {
.orderBy(asc(complaints.createdAt))
}
async createComplaint(data: { userId: number; orderId?: number | null; complaintBody: string; images: string[] }) {
await db.insert(complaints).values(data)
async createComplaint(data: NewComplaint) {
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 { coupons, couponUsage, couponApplicableUsers, couponApplicableProducts, reservedCoupons } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { coupons, couponUsage, couponApplicableUsers, couponApplicableProducts, reservedCoupons } from '../../db/schema'
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 {
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 {
orders,
orderItems,
@ -12,12 +12,12 @@ import {
refunds,
units,
userDetails,
} from '@/src/db/schema'
} from '../../db/schema'
import { and, desc, eq, gte, inArray } from 'drizzle-orm'
import {
IUserOrderDbService,
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 {
async getUserDetailByUserId(userId: number) {

View file

@ -1,7 +1,8 @@
import { db } from '@/src/db/db_index_sqlite'
import { productInfo, units, storeInfo, productSlots, deliverySlotInfo, specialDeals, productReviews, users } from '@/src/db/schema'
import { db } from '../../db/db_index'
import { productInfo, units, storeInfo, productSlots, deliverySlotInfo, specialDeals, productReviews, users } from '../../db/schema'
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 {
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> {
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
}
}

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