# Getting Started

# Getting Started

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [.devin/skills/dal-usage/SKILL.md](.devin/skills/dal-usage/SKILL.md)
- [.github/workflows/ci.yml](.github/workflows/ci.yml)
- [README.md](README.md)
- [package.json](package.json)
- [src/dal/dal.ts](src/dal/dal.ts)

</details>



This page provides a step-by-step guide for integrating `@primebrick/dal-pg` into a TypeScript project. It covers installation, environment configuration, entity definition, and basic database operations using the `Dal` gateway.

## Installation

The package is managed via `pnpm` and requires `reflect-metadata` to support decorator-based entity definitions.

```bash
pnpm install @primebrick/dal-pg reflect-metadata
```

### TypeScript Configuration
Ensure your `tsconfig.json` includes the following settings to support the metadata system used by the DAL:

```json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "module": "NodeNext",
    "target": "ES2022"
  }
}
```

**Sources:**
- [package.json:44-49]()
- [README.md:20-20]()

---

## Environment Configuration

The DAL requires a valid PostgreSQL connection string. By convention, this is stored in a `.env` file or provided via the `DATABASE_URL` environment variable.

```env
DATABASE_URL=postgresql://user:password@localhost:5432/dbname?sslmode=disable
```

The `Dal` gateway uses this string to initialize the internal `pg.Pool` [src/dal/dal.ts:131-137]().

**Sources:**
- [src/dal/dal.ts:55-56]()
- [.devin/skills/dal-usage/SKILL.md:41-41]()

---

## Initializing the Dal Gateway

The `Dal` class serves as the process-wide entry point. It manages the connection pool, registers type parsers (such as `INT8` to `bigint` conversion), and enforces best-practice defaults like `statement_timeout` to prevent pool starvation [src/dal/dal.ts:4-22]().

### Setup Example

```typescript
import "reflect-metadata"; // Must be imported at the entry point
import { getDal } from "@primebrick/dal-pg";

const dal = getDal({
  connectionString: process.env.DATABASE_URL!,
  schema: "public",
  max: 10,                 // Max pool size
  statementTimeoutMs: 30000, // 30s timeout per query
  applicationName: "my-service"
});

// Graceful shutdown
process.on("SIGTERM", async () => {
  await dal.close();
  process.exit(0);
});
```

### Gateway Lifecycle and Data Flow

The following diagram illustrates how the `Dal` gateway initializes the system and bridges the application to the PostgreSQL database.

**Diagram: Dal Initialization and Connection Flow**
```mermaid
graph TD
    subgraph "Application Space"
        App["App Entry"] -- "calls" --> getDal["getDal(config)"]
        getDal -- "creates" --> DalInstance["class Dal"]
    end

    subgraph "Dal Gateway (Internal)"
        DalInstance -- "1. register" --> TypeParsers["ensureTypeParsers()"]
        DalInstance -- "2. create" --> Pool["pg.Pool"]
        DalInstance -- "3. instantiate" --> Repo["class Repository"]
        
        Pool -- "onConnect hook" --> SessionConfig["SET statement_timeout<br/>SET search_path"]
    end

    subgraph "Database Space"
        SessionConfig -- "executes on" --> PG["PostgreSQL Instance"]
    end

    TypeParsers -- "modifies" --> PG_Types["pg.types.setTypeParser"]
```

**Sources:**
- [src/dal/dal.ts:101-170]()
- [src/dal/dal.ts:128-128]()
- [src/dal/dal.ts:147-163]()
- [.devin/skills/dal-usage/SKILL.md:36-52]()

---

## Defining an Entity

Entities are plain TypeScript classes decorated with metadata. The DAL uses these decorators to map class properties to database columns and handle specialized logic like auditing and soft-deletion.

```typescript
import { Entity, Column, Key, Unique, AuditableField, DeletableField, AuditableFieldType, DeletableFieldType } from "@primebrick/dal-pg";

@Entity("user_account")
export class UserAccount {
  @Key() 
  id!: number;

  @Unique() 
  uuid!: string;

  @Column({ length: 255, nullable: false }) 
  email!: string;

  @AuditableField(AuditableFieldType.VERSION) 
  version!: number;

  @DeletableField(DeletableFieldType.DELETED_AT) 
  deleted_at?: Date;
}
```

**Sources:**
- [README.md:7-7]()
- [.devin/skills/dal-usage/SKILL.md:59-78]()

---

## Running the First Query

The `Dal` instance provides high-level methods for CRUD operations. All write operations utilize `RETURNING *` to ensure the returned object reflects the database state [README.md:43-43]().

### Basic CRUD Operations

```typescript
// 1. Create (Add)
const newUser = await dal.add(UserAccount, {
  email: "hello@primebrick.io"
}, { actor: "system-init" });

// 2. Read (Find)
const user = await dal.findByUUID(UserAccount, newUser.uuid);

// 3. Filtered Search
import { Filter, field } from "@primebrick/dal-pg";

const results = await dal.findAll(UserAccount, null, {
  filters: [
    Filter.fieldValue(field(UserAccount, "email"), "=", "hello@primebrick.io")
  ]
});
```

### Entity to SQL Mapping

The following diagram bridges the "Natural Language Space" (Entity definitions) to the "Code Entity Space" (SQL Generation).

**Diagram: Entity Metadata to SQL Execution**
```mermaid
graph LR
    subgraph "Code Entity Space"
        UserClass["@Entity('user_account')<br/>class UserAccount"]
        DalAdd["dal.add(UserAccount, data)"]
    end

    subgraph "Metadata Engine"
        Meta["getEntityPersistenceMeta"]
        SQLBuilder["buildInsertQuery"]
    end

    subgraph "Execution Space"
        Pool["pg.Pool.query()"]
        SQL["INSERT INTO user_account (...)<br/>RETURNING *"]
    end

    UserClass -- "scanned by" --> Meta
    DalAdd -- "triggers" --> SQLBuilder
    Meta -- "provides table/columns to" --> SQLBuilder
    SQLBuilder -- "generates" --> SQL
    SQL -- "sent via" --> Pool
```

**Sources:**
- [README.md:7-9]()
- [src/dal/dal.ts:172-180]()
- [.devin/skills/dal-usage/SKILL.md:83-106]()

---

## Error Handling

The DAL throws specific error classes defined in `@primebrick/dal-pg/errors`. By default, finder methods like `findById` or `findByUUID` throw a `NotFoundError` if the record does not exist [README.md:44-44]().

```typescript
import { NotFoundError } from "@primebrick/dal-pg";

try {
  await dal.findByUUID(UserAccount, "some-uuid");
} catch (err) {
  if (err instanceof NotFoundError) {
    console.error("User not found in database.");
  }
}
```

**Sources:**
- [package.json:23-27]()
- [.devin/skills/dal-usage/SKILL.md:168-176]()

---
