Skip to content

Quick Start

Experimental

The DB integrations layer is experimental. APIs and annotations described in this section may change in future releases.

This guide builds on the TypeScript Quick Start — you will use the same .as model-driven workflow to create a SQLite-backed application with typed CRUD operations.

What You Will Build

A Todo app backed by a single SQLite table. At the end, a brief two-table example shows how relations work.

Recommended Reading

If you are new to Atscript, start with the TypeScript Quick Start first. This guide assumes you are familiar with .as syntax and the compilation workflow.

1. Install Dependencies

bash
pnpm add @atscript/core @atscript/typescript @atscript/utils-db @atscript/db-sqlite better-sqlite3

2. Configure Atscript

Create atscript.config.mts in your project root:

typescript
import { defineConfig } from '@atscript/core'
import ts from '@atscript/typescript'

export default defineConfig({
  rootDir: 'src',
  plugins: [ts()],
  format: 'dts',
  db: {
    adapter: '@atscript/db-sqlite',
    connection: './myapp.db',
  },
})

The db section tells the CLI which adapter to use for schema sync and where to find your database file.

3. Define Your Schema

Create src/schema/todo.as:

atscript
@db.table 'todos'
export interface Todo {
    @meta.id
    @db.default.fn 'increment'
    id: number

    title: string

    description?: string

    @db.default 'false'
    completed: boolean

    @db.default.fn 'now'
    createdAt?: number.timestamp
}

This defines a todos table with an auto-incrementing primary key, a required title, an optional description, a completed flag that defaults to false, and a createdAt timestamp set automatically on insert.

4. Compile

bash
npx asc

This generates TypeScript types (.as.d.ts) and runtime metadata (.as.js) from your .as files.

5. Sync Your Schema

bash
npx asc db sync

Schema sync inspects your @db.* annotations, compares them against the live database, and applies any changes — creating tables, adding columns, and syncing indexes. See Schema Sync for details.

6. Use in Your Application

typescript
import { DbSpace } from '@atscript/utils-db'
import { SqliteAdapter, BetterSqlite3Driver } from '@atscript/db-sqlite'
import { Todo } from './schema/todo.as'

// Create a database space with a SQLite adapter
const driver = new BetterSqlite3Driver('./myapp.db')
const db = new DbSpace(() => new SqliteAdapter(driver))

// Get a typed table
const todos = db.getTable(Todo)

// Insert
await todos.insertOne({ title: 'Learn Atscript' })

// Query with filter and sort
const pending = await todos.findMany({
  filter: { completed: false },
  controls: { $sort: { createdAt: -1 } },
})

// Update
await todos.updateOne({ id: 1, completed: true })

// Delete
await todos.deleteOne(1)

Every operation is fully typed — insertOne requires title (the only non-optional, non-defaulted field), and findMany returns Todo[] with the correct shape.

7. Bonus: Adding Relations

Suppose each todo belongs to a category. Add a second .as file:

atscript
@db.table 'categories'
export interface Category {
    @meta.id
    @db.default.fn 'increment'
    id: number

    name: string
}

Then update todo.as to reference it:

atscript
import { Category } from './category.as'

@db.table 'todos'
export interface Todo {
    @meta.id
    @db.default.fn 'increment'
    id: number

    title: string
    description?: string

    @db.default 'false'
    completed: boolean

    @db.default.fn 'now'
    createdAt?: number.timestamp

    @db.rel.FK
    categoryId?: Category.id

    @db.rel.to
    category?: Category
}

Now you can load todos with their category in a single query:

typescript
const todosWithCategory = await todos.findMany({
  controls: { $with: [{ name: 'category' }] },
})
// todosWithCategory[0].category?.name → 'Work'

See Relations for the full guide on TO, FROM, and VIA relation types.

Next Steps

Released under the MIT License.