Skip to content

Database layer for Atscript

Atscript DB

Your schema is your entire backend

Tables, relations, views, sync, and REST — from a single .as file. No ORM configuration. No migration files. No boilerplate.

Atscript DB

Define your tables

Stop scattering your data definitions across ORM configs, migration scripts, and validation layers. One .as file holds your table name, columns, types, indexes, defaults, and constraints. Nothing else to maintain.

Tables & FieldsIndexes & Constraints
product.as
schema/product.as
atscript
@db.table 'products'
export interface Product {
  @meta.id
  @db.default.increment
  id: number

  @db.index.fulltext 'search_idx', 3
  name: string

  description?: string

  @db.index.unique 'sku_idx'
  sku: string

  price: number

  @db.default 'active'
  status: 'active' | 'archived' | 'draft'

  createdAt: number.timestamp.created
}

Declare relations in the model

Foreign keys, navigation properties, and cascade rules belong with the data they describe — not in a separate config file you have to keep in sync by hand.

Foreign KeysNavigation Properties
order.as
schema/order.as
atscript
import { Customer } from './customer'
import { OrderItem } from './order-item'

@db.table 'orders'
export interface Order {
  @meta.id
  @db.default.uuid
  id: string

  @db.rel.FK
  @db.rel.onDelete 'cascade'
  customerId: Customer.id

  // navigate to parent
  @db.rel.to Customer 'customerId'
  customer: Customer

  // navigate to children
  @db.rel.from OrderItem.orderId
  items: OrderItem[]

  total: number
  createdAt: number.timestamp.created
}

Views without raw SQL

JOINs, filters, and GROUP BY aggregations — declared in your schema, not buried in SQL strings or query builder chains. Schema sync generates the CREATE VIEW for you.

Defining ViewsAggregation Views
order-stats.as
schema/order-stats.as
atscript
import { Order } from './order'
import { Customer } from './customer'

@db.view 'order_stats'
@db.view.for Order
@db.view.joins Customer, `Customer.id = Order.customerId`
@db.view.filter `Order.status = 'completed'`
export interface OrderStats {
  // GROUP BY column
  region: Customer.region

  @db.agg.sum "total"
  revenue: number

  @db.agg.count
  orderCount: number

  @db.agg.avg "total"
  avgOrder: number
}

Type-safe CRUD out of the box

Insert, query, update, and delete with a clean API that knows your schema. Filters, sorting, pagination, and full-text search — all type-checked against your model.

CRUD OperationsQueries & Filters
usage.ts
usage.ts
typescript
import { Product } from "./schema/product.as";

const products = db.getTable(Product);

// insert
await products.insertOne({
  name: "Wireless Keyboard",
  sku: "KB-200",
  price: 79.99,
});

// query with filters and pagination
const results = await products.findMany({
  filter: { status: "active", price: { $lte: 100 } },
  controls: { $sort: { price: 1 }, $limit: 20 },
});

// full-text search
const matches = await products.search("wireless keyboard");

Sync, not migrate

Migration files accumulate, drift, and break. Schema sync compares your .as definitions against the live database and applies the difference. Hash-gated — zero cost when nothing changed. Safe mode blocks destructive changes in production.

$ asc db sync
Compiling .as files...
Schema hash: a7f3c912 (changed)
Acquiring lock...
+ CREATE TABLE products (id, name, sku, ...)
+ CREATE INDEX search_idx ON products (name)
+ CREATE INDEX sku_idx ON products (sku)
+ CREATE TABLE orders (id, customerId, ...)
+ CREATE VIEW order_stats AS SELECT ...
Schema synced. 5 changes applied.
How Sync WorksCI/CD Integration

REST API from one class

Writing CRUD controllers by hand is work that adds no value. Extend AsDbController, point it at a table, and get filtering, sorting, pagination, and search endpoints with zero boilerplate.

HTTP SetupURL Query Syntax
controller.ts
controller.ts
typescript
import { AsDbController, TableController } from "@atscript/moost-db";
import { productsTable } from "./db";
import { Product } from "./schema/product.as";

@TableController(productsTable)
export class ProductController extends AsDbController<typeof Product> {}
// GET, POST, PUT, PATCH, DELETE — ready.
endpoints
bash
GET    /products          # list, filter, sort, paginate
GET    /products/:id      # read one
POST   /products          # create
PUT    /products/:id      # replace
PATCH  /products/:id      # partial update
DELETE /products/:id      # delete
GET    /products/search   # full-text search

Any database. Same code.

Prototype with SQLite. Ship with PostgreSQL. Switch to MongoDB. Your schema, queries, and controllers stay the same — only the adapter changes.

Compare adaptersBuild your own

Released under the MIT License.