Skip to content
Download

SQL Module

Bunstone provides a built-in SQL module that wraps Bun's native SQL client. It is designed to be globally available once registered.

Installation

The SQL module is part of the core @grupodiariodaregiao/bunstone package.

Registration

To use the SQL module, you must register it in your root AppModule using the SqlModule.register() method.

Example Registration

typescript
import { Module, SqlModule } from "@grupodiariodaregiao/bunstone";
import { AppController } from "./app.controller";

@Module({
  imports: [
    SqlModule.register({
      host: "localhost",
      port: 5432,
      username: "user",
      password: "password",
      database: "my_db",
      provider: "postgresql",
    }),
  ],
  controllers: [AppController],
})
export class AppModule {}

OR using a connection string:

typescript
@Module({
  imports: [
    SqlModule.register("postgresql://user:password@localhost:5432/my_db"),
  ],
})
export class AppModule {}

Connection options

You can pass a second argument with pool and client settings. Bunstone forwards only the supported options to Bun.SQL:

typescript
@Module({
  imports: [
    SqlModule.register("mysql://user:pass@host:3306/db", {
      maxLifetime: 25200,
      connectionTimeout: 30,
      max: 10,
      timezone: "UTC",
    }),
  ],
})
export class AppModule {}

The same options can be combined with the object-style registration:

typescript
SqlModule.register({
  provider: "postgresql",
  host: "localhost",
  port: 5432,
  username: "user",
  password: "password",
  database: "my_db",
  max: 20,
  idleTimeout: 30,
});

For backward compatibility, the second argument may still be a timezone string:

typescript
SqlModule.register("mysql://user:pass@host/db", "UTC");

Supported options (SqlModuleOptions)

OptionDescription
timezoneBunstone helper for date/time handling. Defaults to UTC. Mapped to driver connection settings.
maxMaximum connections in the pool
maxLifetimeMaximum connection lifetime in seconds
connectionTimeoutTimeout when establishing a connection (seconds)
idleTimeoutClose idle connections after N seconds
connectionDriver-specific runtime settings (e.g. PostgreSQL TimeZone)
tlsTLS/SSL configuration
prepareEnable automatic prepared statements
bigintReturn out-of-range integers as BigInt
onconnectCallback when a connection attempt completes
oncloseCallback when a connection closes
pathUnix domain socket path
readonlySQLite read-only mode
createSQLite create-if-missing behavior
safeIntegersSQLite safe integer handling
strictSQLite strict mode

Only the options listed above are accepted. Invalid keys are rejected by TypeScript and also throw DatabaseError (BNS-DB-003) at runtime.

Usage

Once registered, the SqlService is globally available. You can inject it into any controller or provider without needing to import SqlModule into subsequent modules.

Injecting SqlService

typescript
import { Injectable, SqlService } from "@grupodiariodaregiao/bunstone";

@Injectable()
export class UserService {
  constructor(private readonly sqlService: SqlService) {}

  async getUsers() {
    // Basic query
    return await this.sqlService.query("SELECT * FROM users");
  }

  async getUserById(id: number) {
    // Parameterized query for security
    return await this.sqlService.query("SELECT * FROM users WHERE id = ?", [
      id,
    ]);
  }
}

Global Availability

Because SqlModule is configured with global: true, any provider within it (like SqlService) is available application-wide. You only need to register it once in your root module.

Practical Example

See how to register and use the SQL module in a controller:

ts
import {
  Module,
  Controller,
  Get,
  Post,
  Body,
  AppStartup,
  SqlModule,
  SqlService,
} from "../../index";

@Controller("users")
class UserController {
  constructor(private readonly sql: SqlService) {}

  @Get()
  async getUsers() {
    // Example query using SqlService (requires a running database)
    // return await this.sql.query('SELECT * FROM users');
    return [{ id: 1, name: "Database User" }];
  }

  @Post()
  async createUser(@Body() body: { name: string }) {
    // Example insertion
    // await this.sql.query('INSERT INTO users (name) VALUES (?)', [body.name]);
    return { success: true, user: body.name };
  }
}

@Module({
  imports: [
    SqlModule.register({
      provider: "postgresql",
      host: "localhost",
      port: 5432,
      username: "user",
      password: "password",
      database: "mydb",
    }),
  ],
  controllers: [UserController],
})
class AppModule {}

const app = await AppStartup.create(AppModule);
// app.listen(3000); // Commented out to prevent actual startup without DB
console.log("SQL Database example configured.");

See it on GitHub

Released under the MIT License.