Vista (intefaz y bd), esquema y endpoints de store agregados
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
ALTER TABLE "products" ALTER COLUMN "user_id" SET NOT NULL;--> statement-breakpoint
|
||||
CREATE VIEW "public"."v_product_store" AS (
|
||||
select p.id as product_id, p.title, p.description, p.price, p.stock, p.url_img, p.user_id, u.fullname
|
||||
from products p
|
||||
left join auth.users as u on u.id = p.user_id);
|
||||
1498
apps/api/src/database/migrations/meta/0003_snapshot.json
Normal file
1498
apps/api/src/database/migrations/meta/0003_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,13 @@
|
||||
"when": 1750442271575,
|
||||
"tag": "0002_polite_franklin_richards",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 3,
|
||||
"version": "7",
|
||||
"when": 1751482400155,
|
||||
"tag": "0003_icy_gertrude_yorkes",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as t from 'drizzle-orm/pg-core';
|
||||
import { timestamps } from '../timestamps';
|
||||
import { users } from './auth';
|
||||
import { sql } from 'drizzle-orm';
|
||||
|
||||
export const products = t.pgTable(
|
||||
'products',
|
||||
@@ -11,7 +12,21 @@ export const products = t.pgTable(
|
||||
price: t.numeric('price').notNull(),
|
||||
stock: t.integer('stock').notNull(),
|
||||
urlImg: t.text('url_img').notNull(),
|
||||
userId: t.integer('user_id').references(() => users.id, { onDelete: 'cascade' }),
|
||||
userId: t.integer('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
|
||||
...timestamps,
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
export const viewProductsStore = t.pgView('v_product_store', {
|
||||
id: t.integer('product_id'),
|
||||
title: t.text('title'),
|
||||
description: t.text('description'),
|
||||
price: t.numeric('price'),
|
||||
stock: t.integer('stock'),
|
||||
urlImg: t.text('url_img'),
|
||||
userId: t.integer('user_id'),
|
||||
fullname: t.text('fullname')
|
||||
}).as(sql`
|
||||
select p.id as product_id, p.title, p.description, p.price, p.stock, p.url_img, p.user_id, u.fullname
|
||||
from products p
|
||||
left join auth.users as u on u.id = p.user_id`);
|
||||
@@ -1,19 +1,39 @@
|
||||
export class Product {
|
||||
id?: number;
|
||||
title: string;
|
||||
description: string;
|
||||
price: string;
|
||||
stock: number;
|
||||
urlImg: string;
|
||||
UserId?: number;
|
||||
id?: number | null;
|
||||
title: string | null;
|
||||
description: string | null;
|
||||
price: string | null;
|
||||
stock: number | null;
|
||||
urlImg: string | null;
|
||||
userId?: number | null;
|
||||
}
|
||||
|
||||
export class CreateProduct {
|
||||
id: number;
|
||||
title: string;
|
||||
description: string;
|
||||
price: string;
|
||||
stock: string;
|
||||
urlImg: string;
|
||||
UserId: number;
|
||||
}
|
||||
export class Inventory {
|
||||
id: number | null;
|
||||
title: string | null;
|
||||
description: string | null;
|
||||
price: string | null;
|
||||
stock: number | null;
|
||||
urlImg: string | null;
|
||||
}
|
||||
|
||||
export class Store {
|
||||
id: number | null;
|
||||
title: string | null;
|
||||
description: string | null;
|
||||
price: string | null;
|
||||
stock: number | null;
|
||||
urlImg: string | null;
|
||||
userId: number | null;
|
||||
fullname?: string | null;
|
||||
}
|
||||
|
||||
// export class CreateProduct {
|
||||
// id: number;
|
||||
// title: string;
|
||||
// description: string;
|
||||
// price: string;
|
||||
// stock: string;
|
||||
// urlImg: string;
|
||||
// UserId: number;
|
||||
// }
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Controller, Get, Post, Body, Patch, Param, Delete, Query } from '@nestjs/common';
|
||||
import { Controller, Get, Post, Body, Patch, Param, Delete, Query, Req } from '@nestjs/common';
|
||||
import { InventoryService } from './inventory.service';
|
||||
import { CreateProductDto } from './dto/create-product.dto';
|
||||
import { UpdateProductDto } from './dto/update-product.dto';
|
||||
@@ -6,12 +6,12 @@ import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||
// import { Roles } from '../../common/decorators/roles.decorator';
|
||||
import { PaginationDto } from '../../common/dto/pagination.dto';
|
||||
|
||||
@ApiTags('inventory')
|
||||
@Controller('inventory')
|
||||
@ApiTags('products')
|
||||
@Controller('products')
|
||||
export class UsersController {
|
||||
constructor(private readonly inventoryService: InventoryService) {}
|
||||
|
||||
@Get()
|
||||
@Get('/store')
|
||||
// @Roles('admin')
|
||||
@ApiOperation({ summary: 'Get all products with pagination and filters' })
|
||||
@ApiResponse({ status: 200, description: 'Return paginated products.' })
|
||||
@@ -24,6 +24,22 @@ export class UsersController {
|
||||
};
|
||||
}
|
||||
|
||||
@Get('/inventory')
|
||||
// @Roles('admin')
|
||||
@ApiOperation({ summary: 'Get all products with pagination and filters' })
|
||||
@ApiResponse({ status: 200, description: 'Return paginated products.' })
|
||||
async findAllByUserId(@Req() req: Request, @Query() paginationDto: PaginationDto) {
|
||||
console.log(req['user'].id)
|
||||
const id = 1
|
||||
// const id = Number(req['user'].id);
|
||||
const result = await this.inventoryService.findAllByUserId(id,paginationDto);
|
||||
return {
|
||||
message: 'products fetched successfully',
|
||||
data: result.data,
|
||||
meta: result.meta
|
||||
};
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
// @Roles('admin')
|
||||
@ApiOperation({ summary: 'Get a product by ID' })
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { DRIZZLE_PROVIDER } from 'src/database/drizzle-provider';
|
||||
import { Inject, Injectable, HttpException, HttpStatus, NotFoundException, UnauthorizedException } from '@nestjs/common';
|
||||
import { Inject, Injectable, HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
|
||||
import * as schema from 'src/database/index';
|
||||
import { products } from 'src/database/index';
|
||||
import { products, viewProductsStore } from 'src/database/index';
|
||||
import { eq, like, or, SQL, sql, and, not } from 'drizzle-orm';
|
||||
import { CreateProductDto } from './dto/create-product.dto';
|
||||
import { UpdateProductDto } from './dto/update-product.dto';
|
||||
import { Product, CreateProduct } from './entities/inventory.entity';
|
||||
import { Product, Store, Inventory } from './entities/inventory.entity';
|
||||
import { PaginationDto } from '../../common/dto/pagination.dto';
|
||||
|
||||
@Injectable()
|
||||
@@ -15,7 +15,7 @@ export class InventoryService {
|
||||
@Inject(DRIZZLE_PROVIDER) private drizzle: NodePgDatabase<typeof schema>,
|
||||
) { }
|
||||
|
||||
async findAll(paginationDto?: PaginationDto): Promise<{ data: Product[], meta: any }> {
|
||||
async findAllByUserId(id: number, paginationDto?: PaginationDto): Promise<{ data: Inventory[], meta: any }> {
|
||||
const { page = 1, limit = 10, search = '', sortBy = 'id', sortOrder = 'asc' } = paginationDto || {};
|
||||
|
||||
// Calculate offset
|
||||
@@ -23,12 +23,14 @@ export class InventoryService {
|
||||
|
||||
// Build search condition
|
||||
let searchCondition: SQL<unknown> | undefined;
|
||||
|
||||
if (search) {
|
||||
searchCondition = or(
|
||||
searchCondition = and(or(
|
||||
like(products.title, `%${search}%`),
|
||||
like(products.description, `%${search}%`),
|
||||
// like(users.fullname, `%${search}%`)
|
||||
);
|
||||
), eq(products.userId, id));
|
||||
}else{
|
||||
searchCondition = eq(products.userId, id);
|
||||
}
|
||||
|
||||
// Build sort condition
|
||||
@@ -52,8 +54,8 @@ export class InventoryService {
|
||||
title: products.title,
|
||||
description: products.description,
|
||||
price: products.price,
|
||||
urlImg: products.urlImg,
|
||||
stock: products.stock,
|
||||
urlImg: products.urlImg
|
||||
})
|
||||
.from(products)
|
||||
.where(searchCondition)
|
||||
@@ -75,6 +77,67 @@ export class InventoryService {
|
||||
return { data, meta };
|
||||
}
|
||||
|
||||
async findAll(paginationDto?: PaginationDto): Promise<{ data: Store[], meta: any }> {
|
||||
const { page = 1, limit = 10, search = '', sortBy = 'id', sortOrder = 'asc' } = paginationDto || {};
|
||||
|
||||
// Calculate offset
|
||||
const offset = (page - 1) * limit;
|
||||
|
||||
// Build search condition
|
||||
let searchCondition: SQL<unknown> | undefined;
|
||||
if (search) {
|
||||
searchCondition = or(
|
||||
like(viewProductsStore.title, `%${search}%`),
|
||||
like(viewProductsStore.description, `%${search}%`),
|
||||
);
|
||||
}
|
||||
|
||||
// Build sort condition
|
||||
const orderBy = sortOrder === 'asc'
|
||||
? sql`${viewProductsStore[sortBy as keyof typeof viewProductsStore]} asc`
|
||||
: sql`${viewProductsStore[sortBy as keyof typeof viewProductsStore]} desc`;
|
||||
|
||||
// Get total count for pagination
|
||||
const totalCountResult = await this.drizzle
|
||||
.select({ count: sql<number>`count(*)` })
|
||||
.from(viewProductsStore)
|
||||
.where(searchCondition);
|
||||
|
||||
const totalCount = Number(totalCountResult[0].count);
|
||||
const totalPages = Math.ceil(totalCount / limit);
|
||||
|
||||
// Get paginated data
|
||||
const data = await this.drizzle
|
||||
.select({
|
||||
id: viewProductsStore.id,
|
||||
title: viewProductsStore.title,
|
||||
description: viewProductsStore.description,
|
||||
price: viewProductsStore.price,
|
||||
urlImg: viewProductsStore.urlImg,
|
||||
stock: viewProductsStore.stock,
|
||||
userId: viewProductsStore.userId,
|
||||
fullname: viewProductsStore.fullname
|
||||
})
|
||||
.from(viewProductsStore)
|
||||
.where(searchCondition)
|
||||
.orderBy(orderBy)
|
||||
.limit(limit)
|
||||
.offset(offset);
|
||||
|
||||
// Build pagination metadata
|
||||
const meta = {
|
||||
page,
|
||||
limit,
|
||||
totalCount,
|
||||
totalPages,
|
||||
hasNextPage: page < totalPages,
|
||||
hasPreviousPage: page > 1,
|
||||
nextPage: page < totalPages ? page + 1 : null,
|
||||
previousPage: page > 1 ? page - 1 : null,
|
||||
};
|
||||
return { data, meta };
|
||||
}
|
||||
|
||||
async findOne(id: string): Promise<Product> {
|
||||
const find = await this.drizzle
|
||||
.select({
|
||||
|
||||
Reference in New Issue
Block a user