Skip to content

Commit 2abca3b

Browse files
committed
feat: improve doc
1 parent 9d03976 commit 2abca3b

19 files changed

Lines changed: 272 additions & 314 deletions

File tree

README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ differs.
1818

1919
It was built to fix the things that hurt when you reach for Redux or MobX or other state management libs in a local-first app:
2020

21-
- **Cheap inserts into sorted data.** Every table is backed by a real B+tree, so
21+
- **Cheap inserts into sorted data.** Every table index is backed by a real B-tree, so
2222
inserting into a sorted collection stays `O(log n)` instead of the `O(n)` you
2323
pay rebuilding (Redux) or shifting (MobX) an array. Ideal for fractional
24-
indexing.
24+
indexing for local-first apps.
2525
- **Fine-grained reactivity.** Selectors record exactly which index ranges they
2626
scanned, so a mutation only re-runs the selectors that overlap it, without
2727
proxies or `observer()`.
28-
- **Run the same logic on the backend.** Because a table is just a B-tree, the
28+
- **Run the same logic on the backend.** Because a table index is just a B-tree, the
2929
same schema, selectors, and actions run against a persistent store on the
3030
server (SQLite today). The runtime reads only the rows a selector touches; it
3131
never loads the whole dataset into memory.
@@ -123,8 +123,6 @@ db.loadTables([tasksTable]);
123123
```
124124

125125
```tsx
126-
// 5. Use it in React. The list re-renders only when a mutation
127-
// touches the range it read.
128126
import {
129127
DBProvider,
130128
useSyncSelector,

TODO.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ Github:
44
Codesandbox:
55
1. Add demo
66

7+
Devtool:
8+
1. resetcss
9+
710
Doc:
811
1. Fix npm install/doc links
912
1. Add performance compare doc

packages/hyperdb-doc/src/content/docs/database/data-types.md

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ sidebar:
55
order: 2
66
---
77

8-
HyperDB stores a fixed set of value types. Every value you write is **normalized**
8+
HyperDB stores a fixed set of value types. Every value you write is normalized
99
against its validator before it reaches the storage driver, which guarantees that
1010
what comes back out matches your schema.
1111

@@ -14,7 +14,7 @@ what comes back out matches your schema.
1414
| Validator | TypeScript type | Notes |
1515
| ---------------------- | ---------------- | --------------------------------------------------------------------- |
1616
| `v.string()` | `string` | |
17-
| `v.number()` | `number` | **Finite only**`NaN`/`Infinity` are rejected |
17+
| `v.number()` | `number` | Finite only; `NaN`/`Infinity` are rejected |
1818
| `v.bigint()` | `bigint` | |
1919
| `v.boolean()` | `boolean` | |
2020
| `v.null()` | `null` | |
@@ -30,30 +30,30 @@ what comes back out matches your schema.
3030

3131
### Composite helpers
3232

33-
- `v.partial(objectValidator)` every field becomes optional.
34-
- `v.required(objectValidator, keys)` make listed optional fields required.
35-
- `v.lazy(() => validator)` defer resolution, useful for recursion.
33+
- `v.partial(objectValidator)`: every field becomes optional.
34+
- `v.required(objectValidator, keys)`: make listed optional fields required.
35+
- `v.lazy(() => validator)`: defer resolution, useful for recursion.
3636

3737
## Binary data
3838

3939
`v.arrayBuffer()` accepts an `ArrayBuffer` directly, and also accepts any typed
40-
array or `DataView` — these are copied into a fresh `ArrayBuffer` during
40+
array or `DataView`, which are copied into a fresh `ArrayBuffer` during
4141
normalization. Storage drivers encode binary data appropriately:
4242

43-
- The **SQLite** drivers encode `bigint`, `ArrayBuffer`, and typed-array/data-view
43+
- The SQLite drivers encode `bigint`, `ArrayBuffer`, and typed-array/data-view
4444
values around JSON storage.
45-
- The **IndexedDB** driver uses the same storage encoding and sort-key ordering
45+
- The IndexedDB driver uses the same storage encoding and sort-key ordering
4646
as SQLite.
47-
- The **in-memory** driver stores normalized JS values directly.
47+
- The in-memory driver stores normalized JS values directly.
4848

4949
## Indexable values
5050

51-
Not every value can appear in an index. **Indexable** value types are:
51+
Not every value can appear in an index. Indexable value types are:
5252

5353
- `string`, finite `number`, `bigint`, `boolean`, `null`
5454
- `ArrayBuffer` and typed-array / `DataView` values
5555
- `v.literal(...)` of an indexable primitive
56-
- `v.union(...)` where **every** variant is indexable
56+
- `v.union(...)` where every variant is indexable
5757
- `v.optional(...)` of an indexable value
5858

5959
If you try to build an index on a non-indexable column (an `array`, `object`,
@@ -63,18 +63,18 @@ If you try to build an index on a non-indexable column (an `array`, `object`,
6363

6464
`v.any()` accepts arbitrary JSON-like structures but still enforces HyperDB's
6565
storage rules: numbers must be finite, object keys cannot be empty or start with
66-
`$`, and `undefined` is rejected inside arrays. Use it sparingly you lose the
66+
`$`, and `undefined` is rejected inside arrays. Use it sparingly, since you lose the
6767
type information and the index-ability that explicit validators give you.
6868

6969
## Working with `undefined`
7070

71-
`undefined` is **not a storable value**. The rules:
71+
`undefined` is not a storable value. The rules:
7272

73-
- An **optional object field** may be omitted. Writing `{ note: undefined }` is
74-
normalized to the field being absent it round-trips as missing, not as
73+
- An optional object field may be omitted. Writing `{ note: undefined }` is
74+
normalized to the field being absent, so it round-trips as missing, not as
7575
`undefined`.
76-
- `undefined` is **not allowed inside an array** (`[1, undefined]` is rejected).
77-
- `undefined` is **not allowed as a record value**.
76+
- `undefined` is not allowed inside an array (`[1, undefined]` is rejected).
77+
- `undefined` is not allowed as a record value.
7878

7979
If you need to represent "explicitly empty", model it with `v.null()` instead of
8080
relying on `undefined`.

packages/hyperdb-doc/src/content/docs/database/indexes.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ sidebar:
55
order: 4
66
---
77

8-
Every query runs **through an index** HyperDB never does a full table scan.
8+
Every query runs through an index, so HyperDB never does a full table scan.
99
Indexes are declared on the table and determine which filters and orderings are
1010
possible.
1111

@@ -22,7 +22,7 @@ defineTable("tasks", {
2222
.index("byState", ["state"], { type: "hash" }); // single-column hash
2323
```
2424

25-
The built-in `byId` hash index on `id` is always present you never declare it.
25+
The built-in `byId` hash index on `id` is always present, so you never declare it.
2626

2727
### B-tree vs. hash
2828

@@ -33,8 +33,8 @@ The built-in `byId` hash index on `id` is always present — you never declare i
3333
| `order("asc" \| "desc")` |||
3434
| Composite (multi-column) || ❌ (exactly one column) |
3535

36-
Reach for a **hash** index when you only ever look up a column by exact value;
37-
use a **btree** index when you need ranges, ordering, or multi-column keys.
36+
Reach for a hash index when you only ever look up a column by exact value;
37+
use a btree index when you need ranges, ordering, or multi-column keys.
3838

3939
### What can be indexed
4040

@@ -48,9 +48,9 @@ A composite B-tree index stores rows ordered by its columns left to right, like
4848
phone book ordered by `(lastName, firstName)`. That ordering dictates which
4949
filters are valid. Two rules:
5050

51-
1. **Equality prefix.** You may constrain a column only if **every** column
51+
1. Equality prefix. You may constrain a column only if every column
5252
before it in the index is constrained by equality (`eq`).
53-
2. **One trailing range.** After the equality prefix, you may apply a single
53+
2. One trailing range. After the equality prefix, you may apply a single
5454
range (`gt`/`gte`/`lt`/`lte`) on the next column. You cannot range on a column
5555
and then constrain a later one.
5656

@@ -75,19 +75,19 @@ For `byProjectOrder` = `["projectId", "orderToken"]`:
7575
The query builder validates bounds when the query is constructed and will throw
7676
for:
7777

78-
- **A non-prefix column** using a column without `eq` on all preceding columns
78+
- A non-prefix column, using a column without `eq` on all preceding columns
7979
(`Cannot use column 'X' without specifying eq conditions for all preceding
8080
columns`).
81-
- **`eq` mixed with a range on the same column** e.g. `eq("c", 1).gt("c", 0)`
81+
- `eq` mixed with a range on the same column, e.g. `eq("c", 1).gt("c", 0)`
8282
(`Conflicting conditions for column 'c'`).
83-
- **Two equality conditions on one column** (`Multiple equality conditions`).
84-
- **A column that isn't in the index** (`Column 'X' not found in index`).
85-
- **No usable conditions** at all.
83+
- Two equality conditions on one column (`Multiple equality conditions`).
84+
- A column that isn't in the index (`Column 'X' not found in index`).
85+
- No usable conditions at all.
8686

8787
## Ordering with indexes
8888

8989
Because a B-tree index is physically ordered, `order("asc")` returns rows in the
90-
index's key order and `order("desc")` returns them reversed no separate sort
90+
index's key order and `order("desc")` returns them reversed, with no separate sort
9191
step. Choose your index column order to match how you want to read the data. For
9292
the `byProjectOrder` index, tasks come back ordered by `orderToken` within a
9393
project for free.

packages/hyperdb-doc/src/content/docs/database/reading-data.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
---
22
title: Reading Data
3-
description: Query data with selectors and the selectFrom builder filters, ordering, limits, and first results.
3+
description: Query data with selectors and the selectFrom builder, covering filters, ordering, limits, and first results.
44
sidebar:
55
order: 3
66
---
77

8-
You read data through **selectors** generator functions that describe what to
8+
You read data through selectors, generator functions that describe what to
99
read. Inside a selector you build queries with `selectFrom` and `yield*` them.
1010
Selectors can call other selectors but can never write; the runtime rejects any
1111
mutation emitted from a read.
@@ -36,14 +36,14 @@ Object-form selectors accept:
3636
| `args` | Validator map for the single args object |
3737
| `handler` | Generator function that does the reading |
3838
| `skipTrace` | `true`, or `{ rootTrace, childTrace }` to skip tracing |
39-
| `memoization` | `{ root?, selfChild? }` cache controls see [Selectors & Reactivity](/database/selectors-reactivity/) |
39+
| `memoization` | `{ root?, selfChild? }` cache controls (see [Selectors & Reactivity](/database/selectors-reactivity/)) |
4040

4141
You can also wrap a bare generator function instead of using the object form.
4242

4343
## The query builder
4444

45-
`selectFrom(table, indexName)` returns a builder. You always query **through an
46-
index** there are no table scans. The builder is immutable: each method returns
45+
`selectFrom(table, indexName)` returns a builder. You always query through an
46+
index, so there are no table scans. The builder is immutable: each method returns
4747
a new builder.
4848

4949
```ts
@@ -73,13 +73,13 @@ Available comparisons:
7373
| `q.lt(col, val)` | less than |
7474
| `q.lte(col, val)` | less than or equal |
7575

76-
Comparisons apply to **index columns**, and which combinations are legal depends
76+
Comparisons apply to index columns, and which combinations are legal depends
7777
on the column order of the index. The rules (equality prefix + one trailing
7878
range) are explained in detail in [Indexes](/database/indexes/).
7979

8080
### OR queries
8181

82-
To express an OR, return an **array** of query branches from `where`, or use the
82+
To express an OR, return an array of query branches from `where`, or use the
8383
`or(...)` helper. Each branch is scanned and the results are combined.
8484

8585
```ts
@@ -96,7 +96,7 @@ selectFrom(tasksTable, "byProjectState").where((q) => [
9696
]);
9797
```
9898

99-
This is the idiom for batched lookups for example fetching many rows by id in
99+
This is the idiom for batched lookups, for example fetching many rows by id in
100100
one query:
101101

102102
```ts
@@ -106,7 +106,7 @@ selectFrom(tasksTable, "byId").where((q) => ids.map((id) => q.eq("id", id)));
106106
### `order` and `limit`
107107

108108
```ts
109-
.order("asc") // or "desc" follows the index's key order
109+
.order("asc") // or "desc"; follows the index's key order
110110
.limit(50) // cap the number of returned rows
111111
```
112112

@@ -117,7 +117,7 @@ reverse. Hash indexes are for equality lookups and do not provide ordering.
117117

118118
### Many rows
119119

120-
`yield*`-ing a query returns an **array** of rows:
120+
`yield*`-ing a query returns an array of rows:
121121

122122
```ts
123123
const tasks =

packages/hyperdb-doc/src/content/docs/database/schemas.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ sidebar:
55
order: 1
66
---
77

8-
A schema describes the **shape of your rows** and the **indexes** you can query
8+
A schema describes the shape of your rows and the indexes you can query
99
by. Schemas are defined with `defineTable` and the `v` validator library, and
1010
they double as the source of truth for TypeScript types.
1111

1212
## Defining a table
1313

14-
Every table has a name and a set of fields. A table **must** have a string `id`
14+
Every table has a name and a set of fields. A table must have a string `id`
1515
field. HyperDB automatically creates a built-in hash index named `byId` on `id`.
1616

1717
```ts
@@ -31,7 +31,7 @@ export const tasksTable = defineTable("tasks", {
3131
export type Task = ExtractSchema<typeof tasksTable>;
3232
```
3333

34-
`ExtractSchema<typeof table>` gives you the row type — here, `Task` is:
34+
`ExtractSchema<typeof table>` gives you the row type. Here, `Task` is:
3535

3636
```ts
3737
type Task = {
@@ -72,15 +72,15 @@ v.any();
7272

7373
There are also helpers for deriving object validators:
7474

75-
- `v.partial(objectValidator)` make every field optional.
76-
- `v.required(objectValidator, ["a", "b"])` make the listed optional fields
75+
- `v.partial(objectValidator)`: make every field optional.
76+
- `v.required(objectValidator, ["a", "b"])`: make the listed optional fields
7777
required again.
78-
- `v.lazy(() => validator)` defer evaluation, for recursive shapes.
79-
- `v.pass<T>()` accept any value as type `T` without normalizing it.
78+
- `v.lazy(() => validator)`: defer evaluation, for recursive shapes.
79+
- `v.pass<T>()`: accept any value as type `T` without normalizing it.
8080

8181
## Standalone validators and types
8282

83-
Validators are useful beyond tables for example to type selector/action
83+
Validators are useful beyond tables, for example to type selector/action
8484
arguments or intermediate data. Use `Infer` to get the TypeScript type of any
8585
validator.
8686

@@ -99,7 +99,7 @@ type Filter = Infer<typeof filterSchema>;
9999
## Tagged unions
100100

101101
`defineTable` also accepts a standalone object or union validator instead of a
102-
field map. This is how you model a table whose rows are a **tagged union** of
102+
field map. This is how you model a table whose rows are a tagged union of
103103
several shapes:
104104

105105
```ts
@@ -129,14 +129,14 @@ defineTable("tasks", {
129129
.index("byTitle", ["title"], { type: "hash" }); // hash
130130
```
131131

132-
- **`btree`** (the default) supports equality _and_ range queries, ordering, and
132+
- `btree` (the default) supports equality _and_ range queries, ordering, and
133133
composite (multi-column) keys.
134-
- **`hash`** supports equality lookups only and must have **exactly one column**.
134+
- `hash` supports equality lookups only and must have exactly one column.
135135

136136
Index columns must:
137137

138138
- exist in the table schema, and
139-
- be **indexable** value types (`string`, finite `number`, `bigint`, `boolean`,
139+
- be indexable value types (`string`, finite `number`, `bigint`, `boolean`,
140140
`null`, `ArrayBuffer`/typed-array, and compatible literals, unions, and
141141
optionals of those).
142142

@@ -146,7 +146,7 @@ immediately. For how composite indexes are queried, see
146146

147147
## The `undefined` rule
148148

149-
Stored values can never contain `undefined`. Optional **object fields** may be
149+
Stored values can never contain `undefined`. Optional object fields may be
150150
omitted entirely, and `{ field: undefined }` is normalized to "missing". But
151151
`undefined` is not allowed inside arrays or as a record value. See
152152
[Data Types](/database/data-types/#working-with-undefined) for the details.

0 commit comments

Comments
 (0)