Skip to main content

Store adapters overview

Store adapters provide pluggable backends for data persistence. Reqon includes several built-in adapters and supports custom implementations.

Available adapters

AdapterDescriptionBest For
memoryIn-memory hash mapTesting, temporary data
fileJSON file storageLocal development
sqlSQL database (via PostgREST)Production with PostgreSQL
nosqlNoSQL databaseMongoDB, DynamoDB

Quick start

mission DataSync {
// Define stores
store cache: memory("cache")
store data: file("my-data")
store production: sql("items_table")

action Process {
get "/items"

// Write to store
store response -> data { key: .id }
}
}

Store interface

All adapters implement this interface:

interface StoreAdapter {
// Read
get(key: string): Promise<Record | null>
list(filter?: FilterOptions): Promise<Record[]>

// Write
set(key: string, value: Record): Promise<void>
update(key: string, partial: Record): Promise<void>

// Delete
delete(key: string): Promise<void>
clear(): Promise<void>
}

Writing data

Basic store

store response -> myStore

With key

store response -> myStore { key: .id }

Upsert mode

Insert or update based on key:

store response -> myStore { key: .id, upsert: true }

Partial update

Update only specified fields:

store response -> myStore { key: .id, partial: true }

Reading data

In for loops

for item in myStore {
// Process each item
}

With filtering

for item in myStore where .status == "active" {
// Process active items
}

Multiple conditions

for item in myStore where .status == "pending" and .priority > 5 {
// Process high-priority pending items
}

Store operations

Check existence

match myStore {
[] -> abort "Store is empty",
_ -> continue
}

Count items

validate {
assume length(myStore) > 0
}

Cross-store operations

for order in orders {
for customer in customers where .id == order.customerId {
// Join data from multiple stores
}
}

Choosing an adapter

Development

// Use file for local development
store data: file("my-data")

Testing

// Use memory for tests
store testData: memory("test")

Production

// Use SQL/NoSQL for production
store data: sql("items")

Environment-based selection

mission AdaptiveSync {
// Choose adapter based on environment
store data: match env("NODE_ENV") {
"production" => sql("items"),
"staging" => sql("items_staging"),
_ => file("items-dev")
}
}

Store configuration

Via CLI

reqon mission.vague --store-config ./stores.json

Configuration file

{
"sql": {
"type": "postgrest",
"url": "https://project.supabase.co/rest/v1",
"apiKey": "your-anon-key"
},
"nosql": {
"type": "mongodb",
"url": "mongodb://localhost:27017",
"database": "reqon"
}
}

Exporting data

Via CLI

reqon mission.vague --output ./exports/

Creates JSON files:

exports/
├── customers.json
├── orders.json
└── products.json

Programmatically

import { execute } from 'reqon';

const result = await execute(source);

for (const [name, store] of result.stores) {
const items = await store.list();
console.log(`${name}: ${items.length} items`);
}

Best practices

Use descriptive names

// Good
store activeCustomers: file("active-customers")
store pendingInvoices: file("pending-invoices")

// Avoid
store data1: file("data1")
store temp: file("temp")

Always specify keys

// Good: explicit key
store response -> items { key: .id }

// Risky: auto-generated keys
store response -> items

Use upsert for syncs

// For incremental syncs
store response -> items { key: .id, upsert: true }

Match adapter to use case

Use CaseRecommended
Unit testsmemory
Local devfile
CI/CDfile or memory
Stagingsql (separate DB)
Productionsql or nosql

Custom adapters

See Custom Adapters for implementing your own store adapter.