speedrun-cli 2.6.12 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/package.json +1 -1
- package/src/generator.js +1 -16
- package/src/moduleGenerator.js +597 -121
- package/src/postSetup.js +423 -402
- package/src/prompts.js +25 -3
- package/templates/orm/drizzle/package.json +2 -1
- package/templates/orm/mongoose/package.json +2 -1
- package/templates/orm/prisma/package.json +1 -0
- package/templates/base-crud/src/modules/products/dto/create-product.dto.ts +0 -34
- package/templates/base-crud/src/modules/products/dto/product.dto.ts +0 -36
- package/templates/base-crud/src/modules/products/dto/update-product.dto.ts +0 -4
- package/templates/base-crud/src/modules/products/products.controller.ts +0 -78
- package/templates/base-crud-drizzle/src/modules/products/dto/create-product.dto.ts +0 -34
- package/templates/base-crud-drizzle/src/modules/products/dto/product.dto.ts +0 -36
- package/templates/base-crud-drizzle/src/modules/products/dto/update-product.dto.ts +0 -4
- package/templates/base-crud-drizzle/src/modules/products/products.controller.ts +0 -78
- package/templates/base-crud-drizzle/src/modules/products/products.module.ts +0 -24
- package/templates/base-crud-drizzle/src/modules/products/products.service.ts +0 -140
- package/templates/base-crud-drizzle/src/modules/products/schema/products.schema.ts +0 -39
- package/templates/base-crud-mongoose/src/modules/products/dto/create-product.dto.ts +0 -34
- package/templates/base-crud-mongoose/src/modules/products/dto/product.dto.ts +0 -36
- package/templates/base-crud-mongoose/src/modules/products/dto/update-product.dto.ts +0 -4
- package/templates/base-crud-mongoose/src/modules/products/products.controller.ts +0 -78
- package/templates/base-crud-mongoose/src/modules/products/products.module.ts +0 -26
- package/templates/base-crud-mongoose/src/modules/products/products.service.ts +0 -133
- package/templates/base-crud-mongoose/src/modules/products/schemas/product.schema.ts +0 -67
- package/templates/base-crud-prisma/src/modules/products/dto/create-product.dto.ts +0 -34
- package/templates/base-crud-prisma/src/modules/products/dto/product.dto.ts +0 -36
- package/templates/base-crud-prisma/src/modules/products/dto/update-product.dto.ts +0 -4
- package/templates/base-crud-prisma/src/modules/products/products.controller.ts +0 -78
- package/templates/base-crud-prisma/src/modules/products/products.module.ts +0 -12
- package/templates/base-crud-prisma/src/modules/products/products.service.ts +0 -100
- package/templates/base-crud-typeorm/src/modules/products/dto/create-product.dto.ts +0 -34
- package/templates/base-crud-typeorm/src/modules/products/dto/product.dto.ts +0 -36
- package/templates/base-crud-typeorm/src/modules/products/dto/update-product.dto.ts +0 -4
- package/templates/base-crud-typeorm/src/modules/products/entities/product.entity.ts +0 -58
- package/templates/base-crud-typeorm/src/modules/products/products.controller.ts +0 -78
- package/templates/base-crud-typeorm/src/modules/products/products.module.ts +0 -25
- package/templates/base-crud-typeorm/src/modules/products/products.service.ts +0 -102
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Entity,
|
|
3
|
-
PrimaryGeneratedColumn,
|
|
4
|
-
Column,
|
|
5
|
-
CreateDateColumn,
|
|
6
|
-
UpdateDateColumn,
|
|
7
|
-
DeleteDateColumn,
|
|
8
|
-
Index,
|
|
9
|
-
} from 'typeorm';
|
|
10
|
-
|
|
11
|
-
export enum ProductStatus {
|
|
12
|
-
ACTIVE = 'ACTIVE',
|
|
13
|
-
INACTIVE = 'INACTIVE',
|
|
14
|
-
OUT_OF_STOCK = 'OUT_OF_STOCK',
|
|
15
|
-
DISCONTINUED = 'DISCONTINUED',
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
@Entity('products')
|
|
19
|
-
export class Product {
|
|
20
|
-
@PrimaryGeneratedColumn('uuid')
|
|
21
|
-
id: string;
|
|
22
|
-
|
|
23
|
-
@Column({ length: 150 })
|
|
24
|
-
name: string;
|
|
25
|
-
|
|
26
|
-
@Column({ type: 'text', nullable: true })
|
|
27
|
-
description: string | null;
|
|
28
|
-
|
|
29
|
-
@Column({ length: 50, unique: true })
|
|
30
|
-
@Index()
|
|
31
|
-
sku: string;
|
|
32
|
-
|
|
33
|
-
@Column({ type: 'decimal', precision: 10, scale: 2 })
|
|
34
|
-
price: number;
|
|
35
|
-
|
|
36
|
-
@Column({ default: 0 })
|
|
37
|
-
stock: number;
|
|
38
|
-
|
|
39
|
-
@Column({ length: 100, nullable: true })
|
|
40
|
-
category: string | null;
|
|
41
|
-
|
|
42
|
-
@Column({
|
|
43
|
-
type: 'enum',
|
|
44
|
-
enum: ProductStatus,
|
|
45
|
-
default: ProductStatus.ACTIVE,
|
|
46
|
-
})
|
|
47
|
-
status: ProductStatus;
|
|
48
|
-
|
|
49
|
-
@CreateDateColumn({ name: 'created_at' })
|
|
50
|
-
createdAt: Date;
|
|
51
|
-
|
|
52
|
-
@UpdateDateColumn({ name: 'updated_at' })
|
|
53
|
-
updatedAt: Date;
|
|
54
|
-
|
|
55
|
-
/** Soft-delete column — null means the record is active */
|
|
56
|
-
@DeleteDateColumn({ name: 'deleted_at', nullable: true })
|
|
57
|
-
deletedAt: Date | null;
|
|
58
|
-
}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Controller,
|
|
3
|
-
Get,
|
|
4
|
-
Param,
|
|
5
|
-
Query,
|
|
6
|
-
ParseUUIDPipe,
|
|
7
|
-
HttpStatus,
|
|
8
|
-
Type,
|
|
9
|
-
} from '@nestjs/common';
|
|
10
|
-
import {
|
|
11
|
-
ApiTags,
|
|
12
|
-
ApiOperation,
|
|
13
|
-
ApiResponse,
|
|
14
|
-
ApiBearerAuth,
|
|
15
|
-
ApiExtraModels,
|
|
16
|
-
ApiParam,
|
|
17
|
-
} from '@nestjs/swagger';
|
|
18
|
-
import { BaseController } from '../../common/base/base.controller';
|
|
19
|
-
import {
|
|
20
|
-
ApiResponseDto,
|
|
21
|
-
ApiResponseSchema,
|
|
22
|
-
PaginatedResponseDto,
|
|
23
|
-
PaginatedResponseSchema,
|
|
24
|
-
PaginationQueryDto,
|
|
25
|
-
} from '../../common/base';
|
|
26
|
-
import { ProductsService, ProductEntity } from './products.service';
|
|
27
|
-
import { CreateProductDto } from './dto/create-product.dto';
|
|
28
|
-
import { UpdateProductDto } from './dto/update-product.dto';
|
|
29
|
-
import { ProductDto } from './dto/product.dto';
|
|
30
|
-
|
|
31
|
-
@ApiTags('Products')
|
|
32
|
-
@ApiBearerAuth('bearer')
|
|
33
|
-
@ApiExtraModels(ApiResponseDto, PaginatedResponseDto, ProductDto)
|
|
34
|
-
@Controller('products')
|
|
35
|
-
export class ProductsController extends BaseController<
|
|
36
|
-
ProductEntity,
|
|
37
|
-
CreateProductDto,
|
|
38
|
-
UpdateProductDto
|
|
39
|
-
> {
|
|
40
|
-
constructor(private readonly productsService: ProductsService) {
|
|
41
|
-
super(productsService);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
protected getDtoClass(): Type<ProductEntity> {
|
|
45
|
-
return ProductDto as unknown as Type<ProductEntity>;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
@Get()
|
|
49
|
-
@ApiOperation({ summary: 'Get all products (paginated)' })
|
|
50
|
-
@ApiResponse({ status: HttpStatus.OK, schema: PaginatedResponseSchema(ProductDto) })
|
|
51
|
-
@ApiResponse({ status: HttpStatus.UNAUTHORIZED, description: 'Unauthorized' })
|
|
52
|
-
override async findAll(@Query() pagination: PaginationQueryDto): Promise<PaginatedResponseDto<ProductEntity>> {
|
|
53
|
-
return super.findAll(pagination);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
@Get('by-sku/:sku')
|
|
57
|
-
@ApiOperation({ summary: 'Get a product by SKU' })
|
|
58
|
-
@ApiParam({ name: 'sku', example: 'KB-WL-MEC-001' })
|
|
59
|
-
@ApiResponse({ status: HttpStatus.OK, schema: ApiResponseSchema(ProductDto) })
|
|
60
|
-
@ApiResponse({ status: HttpStatus.NOT_FOUND, description: 'Product not found' })
|
|
61
|
-
async findBySku(@Param('sku') sku: string): Promise<ApiResponseDto<ProductEntity>> {
|
|
62
|
-
const data = await this.productsService.findBySku(sku);
|
|
63
|
-
return { success: true, data, meta: { correlationId: '', timestamp: new Date().toISOString() } };
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
@Get(':id')
|
|
67
|
-
@ApiOperation({ summary: 'Get a product by ID' })
|
|
68
|
-
@ApiParam({ name: 'id', format: 'uuid', example: '123e4567-e89b-12d3-a456-426614174000' })
|
|
69
|
-
@ApiResponse({ status: HttpStatus.OK, schema: ApiResponseSchema(ProductDto) })
|
|
70
|
-
@ApiResponse({ status: HttpStatus.NOT_FOUND, description: 'Product not found' })
|
|
71
|
-
@ApiResponse({ status: HttpStatus.BAD_REQUEST, description: 'Invalid UUID' })
|
|
72
|
-
override async findOne(
|
|
73
|
-
@Param('id', new ParseUUIDPipe({ version: '4', errorHttpStatusCode: HttpStatus.BAD_REQUEST }))
|
|
74
|
-
id: string,
|
|
75
|
-
): Promise<ApiResponseDto<ProductEntity>> {
|
|
76
|
-
return super.findOne(id);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { Module } from '@nestjs/common';
|
|
2
|
-
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
3
|
-
import { ProductsController } from './products.controller';
|
|
4
|
-
import { ProductsService } from './products.service';
|
|
5
|
-
import { Product } from './entities/product.entity';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Products Module (TypeORM)
|
|
9
|
-
*
|
|
10
|
-
* Registers Product entity with TypeORM and wires the controller & service.
|
|
11
|
-
* The Product entity must also be added to the DatabaseModule's entities array.
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* // In app.module.ts:
|
|
15
|
-
* import { ProductsModule } from './modules/products/products.module';
|
|
16
|
-
* @Module({ imports: [ProductsModule] })
|
|
17
|
-
* export class AppModule {}
|
|
18
|
-
*/
|
|
19
|
-
@Module({
|
|
20
|
-
imports: [TypeOrmModule.forFeature([Product])],
|
|
21
|
-
controllers: [ProductsController],
|
|
22
|
-
providers: [ProductsService],
|
|
23
|
-
exports: [ProductsService],
|
|
24
|
-
})
|
|
25
|
-
export class ProductsModule {}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { Injectable, NotFoundException } from '@nestjs/common';
|
|
2
|
-
import { InjectRepository } from '@nestjs/typeorm';
|
|
3
|
-
import { Repository, IsNull } from 'typeorm';
|
|
4
|
-
import { BaseService, IBaseRepository, PaginationQueryDto } from '../../common/base';
|
|
5
|
-
import { CreateProductDto } from './dto/create-product.dto';
|
|
6
|
-
import { UpdateProductDto } from './dto/update-product.dto';
|
|
7
|
-
import { Product } from './entities/product.entity';
|
|
8
|
-
|
|
9
|
-
/** Uniform entity alias used by the shared ProductsController */
|
|
10
|
-
export type ProductEntity = Product;
|
|
11
|
-
|
|
12
|
-
// ─────────────────────────────────────────────────────────────
|
|
13
|
-
// TypeORM Product Repository
|
|
14
|
-
//
|
|
15
|
-
// Implements IBaseRepository using TypeORM's Repository<Product>.
|
|
16
|
-
// Soft-delete via deletedAt column (TypeORM also supports @DeleteDateColumn).
|
|
17
|
-
// ─────────────────────────────────────────────────────────────
|
|
18
|
-
class TypeOrmProductRepository
|
|
19
|
-
implements IBaseRepository<Product, CreateProductDto, UpdateProductDto>
|
|
20
|
-
{
|
|
21
|
-
constructor(private readonly repo: Repository<Product>) {}
|
|
22
|
-
|
|
23
|
-
async create(dto: CreateProductDto): Promise<Product> {
|
|
24
|
-
const product = this.repo.create(dto);
|
|
25
|
-
return this.repo.save(product);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async findAll(
|
|
29
|
-
pagination: PaginationQueryDto,
|
|
30
|
-
): Promise<{ data: Product[]; total: number }> {
|
|
31
|
-
const { page = 1, limit = 10 } = pagination;
|
|
32
|
-
const skip = (page - 1) * limit;
|
|
33
|
-
|
|
34
|
-
const [data, total] = await this.repo.findAndCount({
|
|
35
|
-
where: { deletedAt: IsNull() },
|
|
36
|
-
skip,
|
|
37
|
-
take: limit,
|
|
38
|
-
order: { createdAt: 'DESC' },
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
return { data, total };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async findOne(id: string): Promise<Product | null> {
|
|
45
|
-
return this.repo.findOne({
|
|
46
|
-
where: { id, deletedAt: IsNull() },
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async update(id: string, dto: UpdateProductDto): Promise<Product> {
|
|
51
|
-
await this.repo.update(id, dto as Partial<Product>);
|
|
52
|
-
return this.repo.findOneOrFail({ where: { id } });
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async remove(id: string): Promise<Product> {
|
|
56
|
-
const product = await this.repo.findOneOrFail({ where: { id } });
|
|
57
|
-
product.deletedAt = new Date();
|
|
58
|
-
return this.repo.save(product);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// ─────────────────────────────────────────────────────────────
|
|
63
|
-
// Products Service (TypeORM)
|
|
64
|
-
// ─────────────────────────────────────────────────────────────
|
|
65
|
-
@Injectable()
|
|
66
|
-
export class ProductsService extends BaseService<
|
|
67
|
-
Product,
|
|
68
|
-
CreateProductDto,
|
|
69
|
-
UpdateProductDto
|
|
70
|
-
> {
|
|
71
|
-
private readonly repository: TypeOrmProductRepository;
|
|
72
|
-
|
|
73
|
-
constructor(
|
|
74
|
-
@InjectRepository(Product)
|
|
75
|
-
private readonly productRepo: Repository<Product>,
|
|
76
|
-
) {
|
|
77
|
-
super();
|
|
78
|
-
this.repository = new TypeOrmProductRepository(this.productRepo);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
protected getRepository(): IBaseRepository<Product, CreateProductDto, UpdateProductDto> {
|
|
82
|
-
return this.repository;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/** Find by SKU — domain-specific method */
|
|
86
|
-
async findBySku(sku: string): Promise<Product> {
|
|
87
|
-
const product = await this.productRepo.findOne({
|
|
88
|
-
where: { sku, deletedAt: IsNull() },
|
|
89
|
-
});
|
|
90
|
-
if (!product) {
|
|
91
|
-
throw new NotFoundException(`Product with SKU "${sku}" was not found`);
|
|
92
|
-
}
|
|
93
|
-
return product;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/** Adjust stock delta */
|
|
97
|
-
async adjustStock(id: string, delta: number): Promise<Product> {
|
|
98
|
-
await this.findOne(id);
|
|
99
|
-
await this.productRepo.increment({ id }, 'stock', delta);
|
|
100
|
-
return this.productRepo.findOneOrFail({ where: { id } });
|
|
101
|
-
}
|
|
102
|
-
}
|