UNPKG

@starbemtech/star-db-query-builder

Version:

A query builder to be used with mysql or postgres

537 lines (443 loc) 11 kB
# insert Inserts a single record into a database table and returns the inserted record. ## Signature ```typescript insert<P, R>({ tableName: string, dbClient: IDatabaseClient, data: P, returning?: string[] }): Promise<R> ``` ## Parameters | Parameter | Type | Required | Description | | ----------- | ----------------- | -------- | ---------------------------------------------- | | `tableName` | `string` | ✅ | Name of the database table | | `dbClient` | `IDatabaseClient` | ✅ | Database client instance | | `data` | `P` | ✅ | Object containing the data to insert | | `returning` | `string[]` | ❌ | Array of field names to return after insertion | ## Return Value - **Type**: `Promise<R>` - **Description**: Returns the inserted record with all fields (including auto-generated ones like `id`, `created_at`, `updated_at`) ## Auto-Generated Fields The `insert` method automatically adds the following fields to every record: - **`id`**: A UUID v4 string - **`updated_at`**: Current timestamp ## Examples ### Basic Usage ```typescript import { insert } from '@starbemtech/star-db-query-builder' // Insert a new user const user = await insert({ tableName: 'users', dbClient, data: { name: 'John Doe', email: 'john@example.com', age: 30, }, }) console.log(user) // { // id: '550e8400-e29b-41d4-a716-446655440000', // name: 'John Doe', // email: 'john@example.com', // age: 30, // created_at: '2023-12-01T10:00:00.000Z', // updated_at: '2023-12-01T10:00:00.000Z' // } ``` ### With Specific Returning Fields ```typescript // Return only specific fields after insertion const user = await insert({ tableName: 'users', dbClient, data: { name: 'Jane Doe', email: 'jane@example.com', age: 25, }, returning: ['id', 'name', 'email', 'created_at'], }) console.log(user) // { // id: '550e8400-e29b-41d4-a716-446655440001', // name: 'Jane Doe', // email: 'jane@example.com', // created_at: '2023-12-01T10:00:00.000Z' // } ``` ### TypeScript Usage ```typescript interface UserData { name: string email: string age: number bio?: string } interface User { id: string name: string email: string age: number bio?: string created_at: Date updated_at: Date } // Typed usage const userData: UserData = { name: 'John Doe', email: 'john@example.com', age: 30, bio: 'Software developer', } const user: User = await insert<UserData, User>({ tableName: 'users', dbClient, data: userData, }) console.log(`Created user with ID: ${user.id}`) ``` ### Inserting with Optional Fields ```typescript // Insert with some optional fields const user = await insert({ tableName: 'users', dbClient, data: { name: 'John Doe', email: 'john@example.com', age: 30, bio: 'Software developer', phone: '+1234567890', website: 'https://johndoe.com', }, }) ``` ### Inserting with Date Fields ```typescript // Insert with custom date const user = await insert({ tableName: 'users', dbClient, data: { name: 'John Doe', email: 'john@example.com', birth_date: new Date('1990-01-01'), last_login: new Date(), }, }) ``` ### Inserting with Boolean Fields ```typescript // Insert with boolean values const user = await insert({ tableName: 'users', dbClient, data: { name: 'John Doe', email: 'john@example.com', is_active: true, is_verified: false, newsletter_subscribed: true, }, }) ``` ### Inserting with JSON Fields ```typescript // Insert with JSON data const user = await insert({ tableName: 'users', dbClient, data: { name: 'John Doe', email: 'john@example.com', preferences: { theme: 'dark', language: 'en', notifications: { email: true, push: false, }, }, metadata: { source: 'web', campaign: 'summer2023', }, }, }) ``` ### Error Handling ```typescript try { const user = await insert({ tableName: 'users', dbClient, data: { name: 'John Doe', email: 'john@example.com', }, }) console.log('User created successfully:', user.id) } catch (error) { if (error.message.includes('duplicate key')) { console.error('User with this email already exists') } else { console.error('Failed to create user:', error.message) } } ``` ## Generated SQL Examples ### PostgreSQL ```sql INSERT INTO users (id, name, email, age, updated_at) VALUES ($1, $2, $3, $4, $5) RETURNING * ``` ### MySQL ```sql INSERT INTO users (id, name, email, age, updated_at) VALUES (?, ?, ?, ?, ?) SELECT * FROM users WHERE id = ? ``` ### With Specific Returning Fields (PostgreSQL) ```sql INSERT INTO users (id, name, email, age, updated_at) VALUES ($1, $2, $3, $4, $5) RETURNING id, name, email, created_at ``` ## Best Practices ### 1. Use TypeScript for Type Safety ```typescript interface CreateUserRequest { name: string email: string age: number bio?: string } interface User { id: string name: string email: string age: number bio?: string created_at: Date updated_at: Date } const createUser = async (userData: CreateUserRequest): Promise<User> => { return insert<CreateUserRequest, User>({ tableName: 'users', dbClient, data: userData, }) } ``` ### 2. Validate Data Before Insertion ```typescript const createUser = async (userData: any) => { // Validate required fields if (!userData.name || !userData.email) { throw new Error('Name and email are required') } // Validate email format const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ if (!emailRegex.test(userData.email)) { throw new Error('Invalid email format') } // Validate age if (userData.age && (userData.age < 0 || userData.age > 150)) { throw new Error('Age must be between 0 and 150') } return insert({ tableName: 'users', dbClient, data: userData, }) } ``` ### 3. Handle Duplicate Key Errors ```typescript const createUser = async (userData: any) => { try { return await insert({ tableName: 'users', dbClient, data: userData, }) } catch (error) { if ( error.message.includes('duplicate key') || error.message.includes('UNIQUE constraint') ) { throw new Error('User with this email already exists') } throw error } } ``` ### 4. Use Specific Returning Fields ```typescript // Good: Return only needed fields const user = await insert({ tableName: 'users', dbClient, data: userData, returning: ['id', 'name', 'email', 'created_at'], }) // Avoid: Returning all fields when not needed const user = await insert({ tableName: 'users', dbClient, data: userData, }) ``` ### 5. Sanitize Input Data ```typescript const sanitizeUserData = (data: any) => { return { name: data.name?.trim(), email: data.email?.toLowerCase().trim(), age: data.age ? parseInt(data.age) : undefined, bio: data.bio?.trim(), } } const createUser = async (rawData: any) => { const sanitizedData = sanitizeUserData(rawData) return insert({ tableName: 'users', dbClient, data: sanitizedData, }) } ``` ## Common Use Cases ### 1. User Registration ```typescript const registerUser = async (registrationData: { name: string email: string password: string age?: number }) => { // Hash password before storing const hashedPassword = await hashPassword(registrationData.password) const user = await insert({ tableName: 'users', dbClient, data: { name: registrationData.name, email: registrationData.email, password: hashedPassword, age: registrationData.age, status: 'pending', verification_token: generateVerificationToken(), }, returning: ['id', 'name', 'email', 'status', 'created_at'], }) // Send verification email await sendVerificationEmail(user.email, user.verification_token) return user } ``` ### 2. Creating Related Records ```typescript const createUserWithProfile = async (userData: any, profileData: any) => { // Create user first const user = await insert({ tableName: 'users', dbClient, data: userData, returning: ['id'], }) // Create user profile const profile = await insert({ tableName: 'user_profiles', dbClient, data: { ...profileData, user_id: user.id, }, }) return { user, profile } } ``` ### 3. Audit Trail ```typescript const createAuditLog = async (action: string, userId: string, details: any) => { return insert({ tableName: 'audit_logs', dbClient, data: { action, user_id: userId, details: JSON.stringify(details), ip_address: details.ipAddress, user_agent: details.userAgent, timestamp: new Date(), }, }) } ``` ### 4. Configuration Management ```typescript const createConfiguration = async ( key: string, value: any, description?: string ) => { return insert({ tableName: 'configurations', dbClient, data: { key, value: JSON.stringify(value), description, is_active: true, }, }) } ``` ## Database-Specific Considerations ### PostgreSQL - Uses `RETURNING` clause for efficient data retrieval - Supports complex data types (JSON, arrays, etc.) - Better performance with `RETURNING` clause ### MySQL - Requires separate `SELECT` query after `INSERT` - Good performance for simple inserts - Limited support for complex data types ## Performance Considerations ### 1. Index Impact ```sql -- Ensure proper indexes exist for unique constraints CREATE UNIQUE INDEX idx_users_email ON users(email); CREATE INDEX idx_users_created_at ON users(created_at); ``` ### 2. Batch Operations For multiple inserts, consider using `insertMany` instead: ```typescript // Good: Use insertMany for multiple records const users = await insertMany({ tableName: 'users', dbClient, data: [ { name: 'John', email: 'john@example.com' }, { name: 'Jane', email: 'jane@example.com' }, ], }) // Avoid: Multiple individual inserts for (const userData of usersData) { await insert({ tableName: 'users', dbClient, data: userData }) } ``` ### 3. Connection Pooling Ensure your database client is properly configured with connection pooling for better performance in high-traffic applications. ## Error Messages Common error messages you might encounter: - `Table name is required` - The `tableName` parameter is missing - `DB client is required` - The `dbClient` parameter is missing - `Data object is required` - The `data` parameter is missing - `duplicate key value violates unique constraint` - Attempting to insert duplicate unique values - `column "field_name" of relation "table_name" does not exist` - Invalid field name - `null value in column "field_name" violates not-null constraint` - Required field is missing