Skip to content

Commit e45f868

Browse files
committed
(docs) Improve README
1 parent 44ad03a commit e45f868

1 file changed

Lines changed: 128 additions & 0 deletions

File tree

README.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,131 @@ await otherUser.remove()
7979
"experimentalDecorators": true
8080
}
8181
```
82+
83+
## Table definition
84+
85+
Tables are defined as classes extending the `Model` class and using the `Field` decorator:
86+
87+
```ts
88+
class User extends Model {
89+
// Primary key and generator function
90+
@Field({ primaryKey: true, default: () => crypto.randomUUID() })
91+
id!: string
92+
// Unique constraint
93+
@Field({ unique: true })
94+
username!: string
95+
// Static default (equivalent to `() => "guest"`)
96+
@Field({ default: "guest" })
97+
role!: string
98+
// nullable field, any other field will throw an error if not defined
99+
@Field({ nullable: true })
100+
email?: boolean
101+
}
102+
```
103+
104+
A `Field` has the following parameters:
105+
- `primaryKey`: Whether the field is the primary key of the model, if multiple fields are marked as primary key, their combination will be the key.
106+
> **Important note**: A limitation in IndexedDB makes it so the primary key can't be changed once the table is created and W-ORM will throw an error, a way to circumvent this is explained in [migrations](#migration-system).
107+
- `unique`: Whether the field has an unique constraint. This will be enforced by the database.
108+
- `nullable`: Whether the field can be `null`/`undefined`, primary keys cannot be nullable.
109+
- `default`: The default value of the field, it can be a value or a function that returns the value.
110+
- `index`: Whether the field should be indexed, it is recommended to keep it unless the type isn't indexable (eg. a Blob).
111+
112+
More info in the [API documentation](https://w-orm.d34d.one/dev/?page=W-ORM.Function.Field).
113+
114+
## Query system
115+
All queries start from your `Model` class:
116+
117+
```ts
118+
// Get with primary key
119+
const table = await User.get(1)
120+
// Get all
121+
const allTables = await User.all()
122+
// Get with filter
123+
const tables = await User.filter({ name: 'John' }).first()
124+
// Get with advanced filter (user provided function)
125+
const tables2 = await User.filter({ name: (n) => n.includes('Ruiz') }).first()
126+
// Get with filter and order
127+
const tables3 = await User.filter({ name: 'John' }).orderBy('-name').first()
128+
// Create a new entry
129+
const newUser = await User.create({ name: 'John' })
130+
// Update an entry
131+
newUser.name = 'Jane'
132+
// or with typing support
133+
newUser.update({
134+
name: 'Jane'
135+
})
136+
// Commit changes
137+
await newUser.save()
138+
// Delete an entry
139+
await newUser.delete()
140+
```
141+
142+
More info in the [API documentation](https://w-orm.d34d.one/dev/?page=W-ORM.Class.Model).
143+
144+
## Transactions
145+
146+
Sometimes DB operations are meant to be executed as a "bundle", so that they either all pass or fail together.
147+
148+
Transactions allow us to implement this, with automatic rollbacks on error. And even if you don't need this, there are performance benefits to using transactions.
149+
150+
```ts
151+
await Transaction('readwrite', async (tx) => {
152+
const newUser = await User.create({ name: 'John Doe' }, tx)
153+
const getUser = await User.get(newUser.id, tx)
154+
155+
// Any error thrown in the callback will abort the transaction, this will rollback any changes made
156+
throw new Error('rollback')
157+
// If no error is thrown, the transaction will be committed
158+
})
159+
```
160+
161+
> **Important note**: Because of a limitation in the IndexedDB API, the transaction will be automatically committed if we wait for any non-transactional operation. (e.g. fetching some data from the network).
162+
163+
More info in the [API documentation](https://w-orm.d34d.one/dev/?page=W-ORM.Function.Transaction).
164+
165+
## Migration system
166+
167+
Sometimes, changes to the way existing data is stored are required for an update, to cope with this W-ORM provides an intuitive migration system.
168+
169+
Migrations are defined as list of functions to be executed, depending on the current and target DB versions.
170+
The key is the target version number, and the value is the migration callback.
171+
172+
Eg. `{ 2: (migration) => { ... } }` will execute the migration callback when the current database version is smaller than 2.
173+
174+
A migration callback receives a
175+
`MigrationContext` object as its only argument.
176+
This object contains a transaction to be used for the migration.
177+
178+
It is expected for the callback to create Model classes that represent the table's state in between these two versions.
179+
The fields aren't actually used by W-ORM in this scenario, and only serve to improve the typing within the migration.
180+
181+
The `Model` methods can be then used to manipulate the data.
182+
It is very important to use the transaction provided by the migration context, otherwise the migration will hang forever.
183+
184+
```ts
185+
const migrations: MigrationList = {
186+
2: async (migration) => {
187+
class User extends Model {
188+
id!: number
189+
name!: string
190+
}
191+
192+
const users = await User.all()
193+
for (const user of users) {
194+
user.name = `${user.id} name`
195+
await user.save(migration.tx)
196+
}
197+
// Or with the `forEach method`
198+
await User.forEach(async (instance, tx) => {
199+
instance.name = `${instance.id} name`
200+
await instance.save(tx)
201+
}, migration.tx)
202+
203+
const specificUser = await User.get(69, migration.tx)
204+
await specificUser?.delete(migration.tx)
205+
},
206+
}
207+
```
208+
209+
More info in the [API documentation](https://w-orm.d34d.one/dev/?page=Types.TypeAlias.MigrationList).

0 commit comments

Comments
 (0)