Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions learn/developers/harper-applications-in-depth.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,7 @@ function calculateHumanAge(dogAge) {
}

export class DogWithHumanAge extends tables.Dog {
static loadAsInstance = false;
async async get(target) {
static async get(target) {
const dogRecord = await super.get(target);

return {
Expand Down Expand Up @@ -433,8 +432,7 @@ Notably, did you see how we were able to use the `001` id with the new resource

```javascript
export class DogWithHumanAge extends tables.Dog {
static loadAsInstance = false;
async get(target) {
static async get(target) {
// ...
}
}
Expand All @@ -444,8 +442,7 @@ The `DogWithHumanAge` class extends from `tables.Dog`. The `tables` reference is

```javascript
export class DogWithHumanAge extends tables.Dog {
static loadAsInstance = false;
async get(target) {
static async get(target) {
const dogRecord = await super.get(target);

return {
Expand Down
123 changes: 123 additions & 0 deletions reference/database/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
title: Overview
---

<!-- Source: versioned_docs/version-4.7/reference/architecture.md (primary) -->
<!-- Source: versioned_docs/version-4.7/reference/dynamic-schema.md (databases/tables concepts) -->
<!-- Source: release-notes/v4-tucker/4.2.0.md (database structure changes) -->

# Database

Harper's database system is the foundation of its data storage and retrieval capabilities. Harper supports two storage enginers, [RocksDB](https://github.com/facebook/rocksdb/wiki/RocksDB-Overview) and [LMDB](https://www.symas.com/lmdb) (Lightning Memory-Mapped Database) and is designed to provide high performance, ACID-compliant storage with indexing and flexible schema support.

## How Harper Stores Data

Harper organizes data in a three-tier hierarchy:

- **Databases** — containers that group related tables together in a single transactional file
- **Tables** — collections of records with a common data pattern
- **Records** — individual data objects with a primary key and any number of attributes

All tables within a database share the same transaction context, meaning reads and writes across tables in the same database can be performed atomically.

### The Schema System and Auto-REST

The most common way to use Harper's database is through the **schema system**. By defining a [GraphQL schema](./schema.md), you can:

- Declare tables and their attribute types
- Control which attributes are indexed
- Define relationships between tables
- Automatically expose data via REST, MQTT, and other interfaces

You do not need to build custom application code to use the database. A schema definition alone is enough to create fully functional, queryable REST endpoints for your data.

For more advanced use cases, you can extend table behavior using the [Resource API](TODO:reference_versioned_docs/version-v4/resources/resource-api.md 'Custom resource logic layered on top of tables').

### Architecture Overview

```
┌──────────┐ ┌──────────┐
│ Clients │ │ Clients │
└────┬─────┘ └────┬─────┘
│ │
▼ ▼
┌────────────────────────────────────────┐
│ │
│ Socket routing/management │
├───────────────────────┬────────────────┤
│ │ │
│ Server Interfaces ─►│ Authentication │
│ RESTful HTTP, MQTT │ Authorization │
│ ◄─┤ │
│ ▲ └────────────────┤
│ │ │ │
├───┼──────────┼─────────────────────────┤
│ │ │ ▲ │
│ ▼ Resources ▲ │ ┌───────────┐ │
│ │ └─┤ │ │
├─────────────────┴────┐ │ App │ │
│ ├─►│ resources │ │
│ Database tables │ └───────────┘ │
│ │ ▲ │
├──────────────────────┘ │ │
│ ▲ ▼ │ │
│ ┌────────────────┐ │ │
│ │ External │ │ │
│ │ data sources ├────┘ │
│ │ │ │
│ └────────────────┘ │
│ │
└────────────────────────────────────────┘
```

## Databases

Harper databases hold a collection of tables in a single transactionally-consistent file. This means reads and writes can be performed atomically across all tables in the same database, and multi-table transactions are replicated as a single atomic unit.

The default database is named `data`. Most applications will use this default. Additional databases can be created for namespace separation — this is particularly useful for components designed for reuse across multiple applications, where a unique database name avoids naming collisions.

> **Note:** Transactions do not preserve atomicity across different databases, only across tables within the same database.

## Tables

Tables group records with a common data pattern. A table must have:

- **Table name** — used to identify the table
- **Primary key** — the unique identifier for each record (also referred to as `hash_attribute` in the Operations API)

Primary keys must be unique. If a primary key is not provided on insert, Harper auto-generates one:

- A **UUID string** for primary keys typed as `String` or `ID`
- An **auto-incrementing integer** for primary keys typed as `Int`, `Long`, or `Any`

Numeric primary keys are more efficient than UUIDs for large tables.

## Dynamic vs. Defined Schemas

Harper tables can operate in two modes:

**Defined schemas** (recommended): Tables with schemas explicitly declared using [GraphQL schema syntax](./schema.md). This provides predictable structure, precise control over indexing, and data integrity. Schemas are declared in a component's `schema.graphql` file.

**Dynamic schemas**: Tables created through the Operations API or Studio without a schema definition. Attributes are reflexively added as data is ingested. All top-level attributes are automatically indexed. Dynamic schema tables automatically maintain `__createdtime__` and `__updatedtime__` audit attributes on every record.

It is best practice to define schemas for production tables. Dynamic schemas are convenient for experimentation and prototyping.

## Key Concepts

For deeper coverage of each database feature, see the dedicated pages in this section:

- **[Schema](./schema.md)** — Defining table structure, types, indexes, relationships, and computed properties using GraphQL schema syntax
- **[API](./api.md)** — The `tables`, `databases`, `transaction()`, and `createBlob()` globals for interacting with the database from code
- **[Data Loader](./data-loader.md)** — Loading seed or initial data into tables as part of component deployment
- **[Storage Algorithm](./storage-algorithm.md)** — How Harper stores data using LMDB with universal indexing and ACID compliance
- **[Jobs](./jobs.md)** — Asynchronous bulk data operations (CSV import/export, S3 import/export)
- **[System Tables](./system-tables.md)** — Harper internal tables for analytics, data loader state, and other system features
- **[Compaction](./compaction.md)** — Reducing database file size by eliminating fragmentation and free space
- **[Transaction Logging](./transaction.md)** — Recording and querying a history of data changes via audit log and transaction log

## Related Documentation

- [REST](../rest/overview.md) — HTTP interface built on top of the database resource system
- [Resources](TODO:reference_versioned_docs/version-v4/resources/overview.md) — Custom application logic extending database tables
- [Operations API](TODO:reference_versioned_docs/version-v4/operations-api/overview.md) — Direct database management operations (create/drop databases and tables, insert/update/delete records)
- [Configuration](TODO:reference_versioned_docs/version-v4/configuration/overview.md) — Storage configuration options (compression, blob paths, compaction)
114 changes: 114 additions & 0 deletions reference/resources/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
---
title: Resources Overview
---

<!-- Source: versioned_docs/version-4.7/reference/resources/index.md (primary) -->
<!-- Source: release-notes/v4-tucker/4.2.0.md (Resource API introduction) -->

# Resources

Harper's Resource API is the foundation for building custom data access logic and connecting data sources. Resources are JavaScript classes that define how data is accessed, modified, subscribed to, and served over HTTP, MQTT, and WebSocket protocols.

## What Is a Resource?

A **Resource** is a class that provides a unified interface for a set of records or entities. Harper's built-in tables extend the base `Resource` class, and you can extend either `Resource` or a table class to implement custom behavior for any data source — internal or external.

Added in: v4.2.0

The Resource API is designed to mirror REST/HTTP semantics: methods map directly to HTTP verbs (`get`, `put`, `patch`, `post`, `delete`), making it straightforward to build API endpoints alongside custom data logic.

## Relationship to Other Features

- **Database tables** extend `Resource` automatically. You can use tables through the Resource API without writing any custom code.
- The **REST plugin** maps incoming HTTP requests to Resource methods. See [REST Overview](TODO:reference_versioned_docs/version-v4/rest/overview.md 'REST plugin reference').
- The **MQTT plugin** routes publish/subscribe messages to `publish` and `subscribe` Resource methods. See [MQTT Overview](TODO:reference_versioned_docs/version-v4/mqtt/overview.md 'MQTT plugin reference').
- **Global APIs** (`tables`, `databases`, `transaction`) provide access to resources from JavaScript code.
- The **`jsResource` plugin** (configured in `config.yaml`) registers a JavaScript file's exported Resource classes as endpoints.

## Extending a Table

The most common use case is extending an existing table to add custom logic.

Starting with a table definition in a `schema.graphql`:

```graphql
# Omit the `@export` directive
type MyTable @table {
id: Long @primaryKey
# ...
}
```

> For more info on the schema API see [`Database / Schema`]()

Then, in a `resources.js` extend from the `tables.MyTable` global:

```javascript
export class MyTable extends tables.MyTable {
static async get(target) {
// get the record from the database
const record = await super.get(target);
// add a computed property before returning
return { ...record, computedField: 'value' };
}

static async post(target, data) {
// custom action on POST
this.create({ ...(await data), status: 'pending' });
}
}
```

Finally, ensure everything is configured appropriately:

```yaml
rest: true
graphqlSchema:
files: schema.graphql
jsResource:
files: resources.js
```

## Custom External Data Source

You can also extend the base `Resource` class directly to implement custom endpoints, or even wrap an external API or service as a custom caching layer:

```javascript
export class CustomEndpoint extends Resource {
static get(target) {
return {
data: doSomething(),
};
}
}

export class MyExternalData extends Resource {
static async get(target) {
const response = await fetch(`https://api.example.com/${target.id}`);
return response.json();
}

static async put(target, data) {
return fetch(`https://api.example.com/${target.id}`, {
method: 'PUT',
body: JSON.stringify(await data),
});
}
}

// Use as a cache source for a local table
tables.MyCache.sourcedFrom(MyExternalData);
```

Resources are the true customization point for Harper. This is where the business logic of a Harper application really lives. There is a lot more to this API than these examples show. Ensure you fully review the [Resource API](./resource-api.md) documentation, and consider exploring the Learn guides for more information.

## Exporting Resources as Endpoints

Resources become HTTP/MQTT endpoints when they are exported. As the examples demonstrated if a Resource extends an existing table, make sure to not have conflicting exports between the schema and the JavaScript implementation. Alternatively, you can register resources programmatically using `server.resources.set()`. See [HTTP API](../http/api.md) for server extension documentation.

## Pages in This Section

| Page | Description |
| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| [Resource API](./resource-api.md) | Complete reference for instance methods, static methods, the Query object, RequestTarget, and response handling |
| [Query Optimization](./query-optimization.md) | How Harper executes queries and how to write performant conditions |
Loading