Skip to content

SQL Server Database Adapter

The @zintrust/db-sqlserver package provides a Microsoft SQL Server driver for ZinTrust's database system, enabling robust SQL Server database operations.

Installation

bash
zin add  @zintrust/db-sqlserver

Configuration

Add the SQL Server database configuration to your environment:

typescript
// config/database.ts
import { DatabaseConfig } from '@zintrust/core';

export const database: DatabaseConfig = {
  driver: 'sqlserver',
  sqlserver: {
    server: process.env.SQLSERVER_SERVER || 'localhost',
    port: parseInt(process.env.SQLSERVER_PORT || '1433'),
    user: process.env.SQLSERVER_USER,
    password: process.env.SQLSERVER_PASSWORD,
    database: process.env.SQLSERVER_DATABASE,
    domain: process.env.SQLSERVER_DOMAIN,
    encrypt: process.env.SQLSERVER_ENCRYPT === 'true',
    trustServerCertificate: process.env.SQLSERVER_TRUST_CERT === 'true',
    connectionTimeout: 60000,
    requestTimeout: 60000,
    pool: {
      max: 10,
      min: 0,
      idleTimeoutMillis: 30000,
    },
  },
};

Environment Variables

bash
SQLSERVER_SERVER=localhost
SQLSERVER_PORT=1433
SQLSERVER_USER=your_username
SQLSERVER_PASSWORD=your_password
SQLSERVER_DATABASE=your_database
SQLSERVER_ENCRYPT=false
SQLSERVER_TRUST_CERT=false

Usage

typescript
import { Model } from '@zintrust/core';

// Define a model
const User = Model.define({
  tableName: 'users',
  schema: {
    id: { type: 'number', primary: true, autoIncrement: true },
    name: { type: 'string', required: true, maxLength: 255 },
    email: { type: 'string', required: true, unique: true, maxLength: 255 },
    created_at: { type: 'datetime', default: () => new Date() },
    metadata: { type: 'json' }, // JSON support via NVARCHAR(MAX)
  },
});

// Create operations
const user = await User.create({
  name: 'John Doe',
  email: 'john@example.com',
  metadata: { preferences: { theme: 'dark' } },
});

// Query operations
const users = await User.where('name', 'John').get();
const user = await User.find(1);

// Update operations
await User.where('id', 1).update({ name: 'Jane Doe' });

// Delete operations
await User.where('id', 1).delete();

// Raw queries with SQL Server-specific features
const results = await Model.raw(`
  SELECT *, JSON_VALUE(metadata, '$.theme') as theme
  FROM users
  WHERE JSON_VALUE(metadata, '$.status') = 'active'
`);

Features

  • Connection Pooling: Efficient connection management
  • Transactions: ACID transaction support
  • Prepared Statements: SQL injection protection
  • Type Safety: Full TypeScript support
  • JSON Support: SQL Server JSON functions
  • Full-Text Search: SQL Server Full-Text Search
  • Migrations: Database migration support
  • Windows Authentication: Integrated Windows auth support

Options

OptionTypeDefaultDescription
serverstringrequiredSQL Server host
portnumber1433SQL Server port
userstringrequiredSQL Server username
passwordstringrequiredSQL Server password
databasestringrequiredDatabase name
domainstringundefinedWindows domain
encryptbooleanfalseEnable encryption
trustServerCertificatebooleanfalseTrust server certificate
connectionTimeoutnumber60000Connection timeout
requestTimeoutnumber60000Request timeout

Advanced Configuration

Windows Authentication

typescript
export const database: DatabaseConfig = {
  driver: 'sqlserver',
  sqlserver: {
    server: 'localhost',
    domain: 'CORP',
    authentication: {
      type: 'ntlm',
      options: {
        domain: 'CORP',
        userName: 'user',
        password: 'pass',
      },
    },
  },
};

Azure SQL Database

typescript
export const database: DatabaseConfig = {
  driver: 'sqlserver',
  sqlserver: {
    server: 'your-server.database.windows.net',
    database: 'your-database',
    user: 'your-user@your-server',
    password: 'your-password',
    encrypt: true,
    trustServerCertificate: false,
  },
};

Connection String

typescript
export const database: DatabaseConfig = {
  driver: 'sqlserver',
  sqlserver: {
    connectionString: process.env.SQLSERVER_CONNECTION_STRING,
  },
};

SQL Server-Specific Features

JSON Operations

typescript
// JSON queries using SQL Server JSON functions
const usersWithPreferences = await Model.raw(`
  SELECT * FROM users
  WHERE JSON_VALUE(metadata, '$.theme') = 'dark'
`);

// JSON path queries
const nestedData = await Model.raw(`
  SELECT JSON_VALUE(metadata, '$.preferences.theme') as theme
  FROM users
`);

// Update JSON fields
await Model.raw(
  `
  UPDATE users
  SET metadata = JSON_MODIFY(metadata, '$.last_login', ?)
  WHERE id = ?
`,
  [new Date().toISOString(), 1]
);

// JSON array operations
const usersWithTags = await Model.raw(`
  SELECT * FROM users
  WHERE EXISTS (
    SELECT 1 FROM OPENJSON(metadata, '$.tags')
    WHERE value = 'admin'
  )
`);
typescript
// Create full-text catalog and index
await Model.raw(`
  CREATE FULLTEXT CATALOG ft_catalog AS DEFAULT;
  CREATE FULLTEXT INDEX ON users(name, email) KEY INDEX PK_users;
`);

// Search with ranking
const searchResults = await Model.raw(
  `
  SELECT *, FT_RANK as rank
  FROM users
  WHERE CONTAINS((name, email), ?)
  ORDER BY FT_RANK DESC
`,
  ['john']
);

// FREETEXT search
const fuzzyResults = await Model.raw(
  `
  SELECT * FROM users
  WHERE FREETEXT((name, email), ?)
`,
  ['john doe']
);

Table-Valued Parameters

typescript
// Bulk insert using TVP
const userData = [
  { name: 'John', email: 'john@example.com' },
  { name: 'Jane', email: 'jane@example.com' },
];

await Model.raw(
  `
  INSERT INTO users (name, email)
  SELECT name, email FROM @userData
`,
  {
    userData: userData,
  }
);

Transactions

typescript
import { Database } from '@zintrust/core';

// Simple transaction
await Database.transaction(async (trx) => {
  await User.create({ name: 'John' }, { transaction: trx });
  await User.create({ name: 'Jane' }, { transaction: trx });
});

// Savepoints
await Database.transaction(async (trx) => {
  await trx.savepoint('user_created');

  try {
    await User.create({ name: 'Bob' }, { transaction: trx });
    await trx.release('user_created');
  } catch (error) {
    await trx.rollbackToSavepoint('user_created');
  }
});

// Transaction isolation levels
await Database.transaction(async (trx) => {
  await trx.raw('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE');
  // ... operations
});

Migrations

typescript
// migrations/001_create_users_table.ts
export const up = async (db) => {
  await db.schema.createTable('users', (table) => {
    table.increments('id').primary();
    table.string('name', 255).notNullable();
    table.string('email', 255).unique().notNullable();
    table.text('metadata'); // JSON stored as NVARCHAR(MAX)
    table.timestamps(true, true);

    // Indexes
    table.index(['email'], 'idx_email');
  });

  // Create full-text index
  await db.raw(`
    CREATE FULLTEXT INDEX ON users(name, email) KEY INDEX PK_users
  `);
};

export const down = async (db) => {
  await db.schema.dropTable('users');
};

Performance Optimization

  1. Connection Pooling: Configure appropriate pool size
  2. Indexing: Use appropriate indexes (clustered, non-clustered)
  3. Query Optimization: Use execution plans
  4. Batch Operations: Use table-valued parameters
  5. Statistics: Keep statistics up to date
  6. Partitioning: Consider table partitioning for large datasets

Error Handling

The SQL Server adapter handles:

  • Connection failures
  • Deadlock detection
  • Timeout errors
  • Constraint violations
  • Syntax errors
  • Network issues
  • Authentication errors

Security Features

  • SQL Injection Prevention: Prepared statements
  • Connection Encryption: SSL/TLS support
  • Authentication: Windows and SQL Server authentication
  • Row-Level Security: SQL Server RLS support
  • Audit Logging: SQL Server Audit capabilities

Monitoring and Diagnostics

typescript
// Query performance analysis
await Model.raw(`
  SET STATISTICS IO ON;
  SET STATISTICS TIME ON;
  SELECT * FROM users WHERE name = 'John';
`);

// Deadlock monitoring
await Model.raw(`
  SELECT * FROM sys.dm_tran_locks
  WHERE request_session_id = @@SPID
`);

Limitations

  • JSON Functions: Limited to SQL Server 2016+
  • Full-Text Search: Requires full-text catalog setup
  • Row Size: 8KB row size limit
  • Concurrent Connections: Limited by licensing

Released under the MIT License.