Database Destination

Insert or update records in a relational database using parameterized SQL statements.

Overview

The Database destination writes processed messages directly to a relational database using parameterized SQL statements. It supports PostgreSQL, MySQL, and Microsoft SQL Server. This destination is commonly used to persist normalized clinical data, store lab results, maintain audit logs, or populate analytics tables from healthcare message streams.

Configuration

Define a Database destination in your root intu.yaml under the destinations key:

yaml
# intu.yaml
destinations:
  lab-results-db:
    type: database
    database:
      driver: postgres
      dsn: "postgres://${DB_USER}:${DB_PASS}@db.hospital.internal:5432/clinical?sslmode=require"
      statement: |
        INSERT INTO lab_results (
          patient_id, order_id, test_code, test_name,
          result_value, units, reference_range, abnormal_flag,
          collection_date, received_at
        ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, NOW())
        ON CONFLICT (order_id, test_code) DO UPDATE SET
          result_value = EXCLUDED.result_value,
          received_at = NOW()
      max_conns: 10

Properties

driver string required
Database driver. One of: postgres, mysql, mssql.
dsn string required
Data source name (connection string). Format varies by driver. Supports environment variable interpolation with ${VAR} syntax. Always use environment variables for credentials.
statement string required
Parameterized SQL statement to execute for each message. Use positional placeholders ($1, $2, ... for PostgreSQL; ? for MySQL/MSSQL). The transformer must return parameters in the matching order.
max_conns int optional
Maximum number of open database connections in the pool. Defaults to 5.
max_idle_conns int optional
Maximum number of idle connections retained in the pool. Defaults to 2.
conn_max_lifetime_ms int optional
Maximum lifetime of a connection in milliseconds before it is closed and replaced. Defaults to 0 (no limit).

DSN Format by Driver

Driver DSN Format
postgres postgres://user:pass@host:5432/dbname?sslmode=require
mysql user:pass@tcp(host:3306)/dbname?tls=true
mssql sqlserver://user:pass@host:1433?database=dbname&encrypt=true

Full Example

Receive HL7v2 ORU lab result messages via MLLP, extract individual test results, and store them in a PostgreSQL table.

Root Configuration

yaml
# intu.yaml
destinations:
  clinical-db:
    type: database
    database:
      driver: postgres
      dsn: "postgres://${DB_USER}:${DB_PASS}@db.hospital.internal:5432/clinical?sslmode=require"
      statement: |
        INSERT INTO lab_results (
          patient_id, order_id, test_code, test_name,
          result_value, units, reference_range, abnormal_flag,
          collection_date
        ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
      max_conns: 10

Channel Configuration

yaml
# channels/lab-to-db/channel.yaml
name: lab-to-db
description: Persist HL7v2 lab results to PostgreSQL

source:
  type: tcp
  tcp:
    port: 6664
    mode: mllp

destinations:
  - clinical-db

Destination Transformer

typescript
// channels/lab-to-db/transformer.ts
import { Message, Context } from "@intu/sdk";

export default function transform(msg: Message, ctx: Context): Message[] {
  const hl7 = msg.body;
  const pid = hl7.segments?.find((s: any) => s.name === "PID");
  const obr = hl7.segments?.find((s: any) => s.name === "OBR");
  const obxSegments = hl7.segments?.filter((s: any) => s.name === "OBX") ?? [];

  const patientId = pid?.fields[3]?.components[0] ?? "";
  const orderId = obr?.fields[2]?.components[0] ?? "";
  const collectionDate = obr?.fields[7]?.components[0] ?? "";

  return obxSegments.map((obx: any) => ({
    ...msg,
    body: {
      params: [
        patientId,
        orderId,
        obx.fields[3]?.components[0] ?? "",
        obx.fields[3]?.components[1] ?? "",
        obx.fields[5]?.components[0] ?? "",
        obx.fields[6]?.components[0] ?? "",
        obx.fields[7]?.components[0] ?? "",
        obx.fields[8]?.components[0] ?? "",
        collectionDate,
      ],
    },
  }));
}
Security Never embed database credentials directly in YAML files. Always use environment variable references (${DB_USER}, ${DB_PASS}) and define the actual values in your .env file, which should be excluded from version control.
Note The transformer must return a body.params array whose elements correspond positionally to the placeholders in the SQL statement. For fan-out scenarios (e.g. one HL7 message producing multiple OBX rows), the transformer can return an array of messages.