Skip to main content

typeorm

Guidelines for developing with TypeORM, a full-featured ORM for TypeScript and JavaScript supporting multiple databases

来源信息

仓库
rolling-scopes/rsschool-app
最近来源活动
2026年3月12日 22:23
检测到的 SKILL.md 语言
英语
星标
10,392
分支
224

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
typeorm
description
Guidelines for developing with TypeORM, a full-featured ORM for TypeScript and JavaScript supporting multiple databases
# TypeORM Development Guidelines You are an expert in TypeORM, TypeScript, and database design with a focus on the Data Mapper pattern and enterprise application architecture. ## Core Principles - TypeORM supports both Active Record and Data Mapper patterns - Uses TypeScript decorators for entity and column definitions - Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, and more - Works in Node.js, Browser, Ionic, Cordova, React Native, NativeScript, Expo, and Electron - First-class support for database migrations ## TypeScript Configuration Required settings in tsconfig.json: ```json { "compilerOptions": { "experimentalDecorators": true, "emitDecoratorMetadata": true, "strict": true, "target": "ES2020", "module": "commonjs", "moduleResolution": "node" } } ``` ## Entity Definition ### Basic Entity ```typescript import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm'; @Entity('users') export class User { @PrimaryGeneratedColumn() id: number; @Column({ type: 'varchar', length: 255, unique: true }) email: string; @Column({ type: 'varchar', length: 255, nullable: true }) name: string | null; @Column({ type: 'boolean', default: true }) isActive: boolean; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; } ``` ### Primary Key Options ```typescript // Auto-increment @PrimaryGeneratedColumn() id: number; // UUID @PrimaryGeneratedColumn("uuid") id: string; // Custom primary key @PrimaryColumn() id: string; // Composite primary key @Entity() export class OrderItem { @PrimaryColumn() orderId: number; @PrimaryColumn() productId: number; } ``` ### Column Decorators ```typescript @Entity() export class Product { @PrimaryGeneratedColumn() id: number; // String columns @Column({ type: 'varchar', length: 255 }) name: string; @Column({ type: 'text', nullable: true }) description: string | null; // Numeric columns @Column({ type: 'decimal', precision: 10, scale: 2 }) price: number; @Column({ type: 'int', default: 0 }) stock: number; // Boolean @Column({ type: 'boolean', default: true }) isAvailable: boolean; // JSON @Column({ type: 'jsonb', nullable: true }) metadata: Record<string, any> | null; // Enum @Column({ type: 'enum', enum: ['active', 'inactive', 'pending'], default: 'pending', }) status: 'active' | 'inactive' | 'pending'; // Timestamps @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; @DeleteDateColumn() deletedAt: Date | null; // For soft deletes // Version column for optimistic locking @VersionColumn() version: number; } ``` ## Relationships ### One-to-One ```typescript @Entity() export class User { @PrimaryGeneratedColumn() id: number; @OneToOne(() => Profile, profile => profile.user, { cascade: true }) @JoinColumn() profile: Profile; } @Entity() export class Profile { @PrimaryGeneratedColumn() id: number; @Column() bio: string; @OneToOne(() => User, user => user.profile) user: User; } ``` ### One-to-Many / Many-to-One ```typescript @Entity() export class User { @PrimaryGeneratedColumn() id: number; @Column() name: string; @OneToMany(() => Post, post => post.author) posts: Post[]; } @Entity() export class Post { @PrimaryGeneratedColumn() id: number; @Column() title: string; @ManyToOne(() => User, user => user.posts, { onDelete: 'CASCADE' }) @JoinColumn({ name: 'author_id' }) author: User; @Column() authorId: number; // Explicit foreign key column } ``` ### Many-to-Many ```typescript @Entity() export class Post { @PrimaryGeneratedColumn() id: number; @Column() title: string; @ManyToMany(() => Tag, tag => tag.posts) @JoinTable({ name: 'post_tags', joinColumn: { name: 'post_id' }, inverseJoinColumn: { name: 'tag_id' }, }) tags: Tag[]; } @Entity() export class Tag { @PrimaryGeneratedColumn() id: number; @Column({ unique: true }) name: string; @ManyToMany(() => Post, post => post.tags) posts: Post[]; } ``` ## Repository Pattern ### Basic Repository Usage ```typescript import { AppDataSource } from './data-source'; import { User } from './entities/User'; const userRepository = AppDataSource.getRepository(User); // Find all const users = await userRepository.find(); // Find with conditions const activeUsers = await userRepository.find({ where: { isActive: true }, }); // Find one const user = await userRepository.findOne({ where: { id: 1 }, }); // Find or fail const user = await userRepository.findOneOrFail({ where: { id: 1 }, }); // Save const newUser = userRepository.create({ email: 'user@example.com', name: 'John Doe', }); await userRepository.save(newUser); // Update await userRepository.update({ id: 1 }, { name: 'Jane Doe' }); // Delete await userRepository.delete({ id: 1 }); // Soft delete (requires @DeleteDateColumn) await userRepository.softDelete({ id: 1 }); ``` ### Custom Repository ```typescript import { Repository, DataSource } from 'typeorm'; import { User } from './entities/User'; export class UserRepository extends Repository<User> { constructor(private dataSource: DataSource) { super(User, dataSource.createEntityManager()); } async findByEmail(email: string): Promise<User | null> { return this.findOne({ where: { email } }); } async findActiveUsers(): Promise<User[]> { return this.find({ where: { isActive: true }, order: { createdAt: 'DESC' }, }); } async findWithPosts(userId: number): Promise<User | null> { return this.findOne({ where: { id: userId }, relations: ['posts'], }); } } ``` ### Query Builder ```typescript const users = await userRepository .createQueryBuilder('user') .leftJoinAndSelect('user.posts', 'post') .where('user.isActive = :isActive', { isActive: true }) .andWhere('post.publishedAt IS NOT NULL') .orderBy('user.createdAt', 'DESC') .skip(0) .take(10) .getMany(); // With raw results const result = await userRepository .createQueryBuilder('user') .select('COUNT(*)', 'count') .where('user.isActive = :isActive', { isActive: true }) .getRawOne(); // Insert with query builder await userRepository .createQueryBuilder() .insert() .into(User) .values([ { email: 'user1@example.com', name: 'User 1' }, { email: 'user2@example.com', name: 'User 2' }, ]) .execute(); ``` ## Data Source Configuration ```typescript // data-source.ts import { DataSource } from 'typeorm'; import { User } from './entities/User'; import { Post } from './entities/Post'; export const AppDataSource = new DataSource({ type: 'postgres', host: process.env.DB_HOST || 'localhost', port: parseInt(process.env.DB_PORT || '5432'), username: process.env.DB_USERNAME, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, // Entity configuration entities: [User, Post], // Or use glob pattern: entities: ["src/entities/**/*.ts"] // Migrations migrations: ['src/migrations/**/*.ts'], // Synchronize - NEVER use in production synchronize: false, // Logging logging: process.env.NODE_ENV === 'development', // Connection pool poolSize: 10, // SSL (for production) ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false, }); // Initialize connection AppDataSource.initialize() .then(() => console.log('Data Source initialized')) .catch(error => console.error('Error initializing Data Source:', error)); ``` ## Migrations ### Creating Migrations ```bash # Generate migration from entity changes npx typeorm migration:generate src/migrations/CreateUsers -d src/data-source.ts # Create empty migration npx typeorm migration:create src/migrations/SeedUsers # Run migrations npx typeorm migration:run -d src/data-source.ts # Revert last migration npx typeorm migration:revert -d src/data-source.ts ``` ### Migration File Structure ```typescript import { MigrationInterface, QueryRunner, Table, TableIndex } from 'typeorm'; export class CreateUsers1234567890 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise<void> { await queryRunner.createTable( new Table({ name: 'users', columns: [ { name: 'id', type: 'int', isPrimary: true, isGenerated: true, generationStrategy: 'increment', }, { name: 'email', type: 'varchar', length: '255', isUnique: true, }, { name: 'name', type: 'varchar', length: '255', isNullable: true, }, { name: 'is_active', type: 'boolean', default: true, }, { name: 'created_at', type: 'timestamp', default: 'CURRENT_TIMESTAMP', }, { name: 'updated_at', type: 'timestamp', default: 'CURRENT_TIMESTAMP', onUpdate: 'CURRENT_TIMESTAMP', }, ], }), true, ); await queryRunner.createIndex( 'users', new TableIndex({ name: 'IDX_USERS_EMAIL', columnNames: ['email'], }), ); } public async down(queryRunner: QueryRunner): Promise<void> { await queryRunner.dropIndex('users', 'IDX_USERS_EMAIL'); await queryRunner.dropTable('users'); } } ``` ## Transactions ```typescript // Using QueryRunner const queryRunner = AppDataSource.createQueryRunner(); await queryRunner.connect(); await queryRunner.startTransaction(); try { const user = queryRunner.manager.create(User, { email: 'user@example.com', name: 'User', }); await queryRunner.manager.save(user); const post = queryRunner.manager.create(Post, { title: 'First Post', author: user, });
在 GitHub 查看
这个 SKILL.md 很大,SkillsMP 这里只预览前一段内容。 在 GitHub 查看