Skip to main content
Version: 0.0.1

Set up your app for Hypertill DB

The current recommendation is to keep your database code in a dedicated db/ folder and make the file layout obvious:

src/
db/
schema.ts
models.ts
database.ts
App.tsx

The examples below use TypeScript and a simple book-reader domain because that matches the shipped Expo reference app.

1. Define your schema

Create src/db/schema.ts:

import { appSchema, tableSchema } from '@hypertill/db'

export const schema = appSchema({
version: 1,
tables: [
tableSchema({
name: 'books',
columns: [
{ name: 'title', type: 'string' },
{ name: 'author', type: 'string' },
{ name: 'status', type: 'string' },
{ name: 'updated_at', type: 'number' },
],
}),
tableSchema({
name: 'chapters',
columns: [
{ name: 'book_id', type: 'string', isIndexed: true },
{ name: 'title', type: 'string' },
{ name: 'position', type: 'number' },
{ name: 'updated_at', type: 'number' },
],
}),
],
})

If you need migrations, add them in a separate migrations.ts file and pass them to the adapter later.

2. Define models

Create src/db/models.ts:

import { Model, Query, Relation } from '@hypertill/db'
import { children, field, relation, text } from '@hypertill/db/decorators'

export class Book extends Model {
static table = 'books'
static associations = {
chapters: { type: 'has_many', foreignKey: 'book_id' },
} as const

@text('title') title!: string
@text('author') author!: string
@text('status') status!: string
@field('updated_at') updatedAt!: number
@children('chapters') chapters!: Query<Chapter>
}

export class Chapter extends Model {
static table = 'chapters'
static associations = {
books: { type: 'belongs_to', key: 'book_id' },
} as const

@field('book_id') bookId!: string
@text('title') title!: string
@field('position') position!: number
@field('updated_at') updatedAt!: number
@relation('books', 'book_id') book!: Relation<Book>
}

export const modelClasses = [Book, Chapter]

3. Create the database

Create src/db/database.ts:

import { Database } from '@hypertill/db'
import SQLiteAdapter from '@hypertill/db/adapters/sqlite'
import { modelClasses } from './models'
import { schema } from './schema'

const adapter = new SQLiteAdapter({
schema,
jsi: true,
onSetUpError: (error) => {
console.error('Hypertill DB setup failed', error)
},
})

export const database = new Database({
adapter,
modelClasses,
})

For web targets, swap SQLiteAdapter for LokiJSAdapter and keep the rest of the bootstrap pattern the same.

4. Provide the database to React

Wrap your app once in DatabaseProvider:

import { DatabaseProvider } from '@hypertill/db/react'
import { database } from './src/db/database'
import { BookReaderScreen } from './src/BookReaderScreen'

export default function App() {
return (
<DatabaseProvider database={database}>
<BookReaderScreen />
</DatabaseProvider>
)
}

5. Keep reads and writes separate

At this point, your app is ready for:

  • reactive reads via withObservables
  • writes and imperative lookups via useDatabase

That split is the current recommended React pattern for 0.0.1. Continue with Connecting Components.