Skip to content

Commit a183aaa

Browse files
author
Ivan Buryak
committed
Add readme
1 parent e62df3d commit a183aaa

File tree

3 files changed

+140
-41
lines changed

3 files changed

+140
-41
lines changed

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023 Ivan Buryak
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+117-37
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,101 @@
1-
# jotai-minidb - Simple jotai interface for IndexedDB key-value storage
1+
# jotai-minidb - Jotai atoms factory for IndexedDb key-value storage
22

3-
Simple but fully functional way to persist your Jotai atoms in IndexedDB. Analogues to [atomWithStorage](https://jotai.org/docs/utils/atom-with-storage) but when localStorage is not enough.
3+
Simple but fully functional way to persist key-value data in IndexedDb for Jotai. Analogues to [atomWithStorage](https://jotai.org/docs/utils/atom-with-storage) but when localStorage is not enough.
44

5-
> ⚠️ IMPORTANT: This package was implemented to experiment with [Jotai v2 API](https://jotai.org/docs/guides/migrating-to-v2-api) and currently doesn't support v1. It is not hard to part it though. Please open an issue if you are interested to use it in v1.
5+
⚠️ IMPORTANT: This package was initially created to experiment with [Jotai v2 API](https://jotai.org/docs/guides/migrating-to-v2-api) and currently doesn't support v1. Please open an issue if you are interested to use it with v1.
66

77
# Features
88

99
- IndexedDB persistency
10+
- TypeScript support
1011
- Cross-tab sync (changes in one browser tab are automatically synced to other tabs)
11-
- Versioning and migrations (if you have some local data you will have to migrate it sooner or later)
12+
- Data migrations (if you have some local data you will have to migrate it sooner or later)
1213

13-
# Examples
14+
# Usage
15+
First, you need to create instance of a `MiniDb` class:
16+
17+
```js
18+
import { MiniDb } from 'jotai-minidb'
19+
const myDb = new MiniDb()
20+
```
21+
22+
## Read
23+
- `useAtomValue(myDb.keys)` - get all keys in the storage
24+
- `useAtomValue(myDb.values)` - get all values in the storage
25+
- `useAtomValue(myDb.items)` - get key-value storage
26+
- `useAtomValue(myDb.entries)` - get all [key, value] entries
27+
28+
## Read/write item
29+
```js
30+
const [item, setItem] = useAtom(myDb.item(key))
31+
```
32+
33+
## Write
34+
### set value of the item by the key `key`
35+
```js
36+
const set = useSetAtom(myDb.set)
37+
set(key, value)
38+
```
1439

40+
### update may items in the storage with an array of entries
41+
```js
42+
const setMany = useSetAtom(myDb.setMany)
43+
setMany([
44+
['key-1', 1],
45+
['key-2', 33],
46+
...
47+
])
48+
```
49+
50+
### Delete by key
51+
```js
52+
const delete = useSetAtom(myDb.delete)
53+
delete(key)
54+
```
55+
56+
### Clear all
57+
```js
58+
const clear = useSetAtom(myDb.clear)
59+
clear()
60+
```
61+
62+
# Examples
1563
```js
1664
// Jotai V2 API!
1765
import { useAtom, useAtomValue, useSetAtom } from "jotai/react";
18-
1966
import { MiniDb } from "jotai-minidb";
2067

21-
// Items in a store can be typed
68+
// Type of an item in key-value store
2269
type Item = {
2370
name: string;
2471
};
2572

26-
// Create a store (with default database name)
73+
// Create a minidb class with set of atoms to access to IndexedDb
2774
const myDb = new MiniDb<Item>();
2875

29-
// Multiple stores connected to different databases can be created
30-
const myOtherDb = new MiniDb<string>({ name: "myOtherDb" })
31-
3276
// 1. Get all keys, values or entries
3377
export function Entries() {
34-
const keys = useAtomValue(myDb.keys);
35-
const values = useAtomValue(myDb.values);
36-
const entries = useAtomValue(myDb.entries);
78+
const keys = useAtomValue(myDb.keys);
79+
const values = useAtomValue(myDb.values);
80+
const entries = useAtomValue(myDb.entries);
3781

38-
return entries.map(([key, entry]) => <li>{entry.name}</li>)
82+
return entries.map(([key, entry]) => (<li>{entry.name}</li>))
3983
}
4084

4185
// 2. Get, or set item in a store
4286
export function Entry() {
43-
const [item, setItem] = useAtom(myDb.item('some-item-key'));
44-
45-
if (!item) {
46-
return null
47-
}
48-
49-
return (
50-
<input
51-
value={item.name}
52-
onChange={(e) => setItem({ ...item, name: e.target.value })}
53-
/>
54-
)
87+
const [item, setItem] = useAtom(myDb.item('some-item-key'));
88+
89+
if (!item) {
90+
return null
91+
}
92+
93+
return (
94+
<input
95+
value={item.name}
96+
onChange={(e) => setItem({ ...item, name: e.target.value })}
97+
/>
98+
)
5599
}
56100

57101
// 3. Create new item or delete item
@@ -61,26 +105,62 @@ export function CreateUpdateOrDelete() {
61105

62106
return (
63107
<>
64-
<Button onClick={() => set('some-key', { name: 'new value' })}>Create</button>
65-
<Button onClick={() => delete('some-key')}>Delete</button>
108+
<button onClick={() => set('some-key', { name: 'new value' })}>Create</button>
109+
<button onClick={() => delete('some-key')}>Delete</button>
66110
</>
67111
)
68112
}
113+
```
69114

70-
// 4. Migrate schema
71-
// In a new version of the Item we want to add an age property with some default value
72-
type Item = {
73-
name: string;
74-
age: number;
75-
};
115+
# Configuration
116+
117+
MiniDb constructor takes an optional configuration object with the following parameters:
118+
119+
## **name**
120+
default: `jotai-minidb`
121+
Database name. If you need multiple collections you can simply define multiple storages with different names:
122+
123+
```
124+
const books = new MiniDb({ name: 'books' })
125+
const authors = new MiniDb({ name: 'authors' })
126+
```
127+
128+
## **version**
129+
default: 0
130+
131+
Schema version is used to introduce breaking change to a shape of the data stored in a database. If data in IndexedDb has a version lower than **version** then it is migrated with set of **migrations**. If **version** is lower than version of the data in IndexedDb then exception is thrown and `onVersionMissmatch` handler is called
132+
133+
## **migrations**
134+
default: {}
135+
136+
If **version** is greater than 0 you should provide a migration function for each version in **migrations** object where a key is `version` and value is a migration function
76137

138+
139+
```
77140
const myDb = new MiniDb<Item>({
78-
version: 1,
141+
version: 2,
79142
migrations: {
80143
1: (item) => {
81144
item.age = 18
82145
return item
146+
},
147+
2: (item) => {
148+
// migrate from 1 => 2
83149
}
84-
}
150+
},
85151
});
86152
```
153+
154+
## **onMigrationCompleted**
155+
default: () => {
156+
alert("Data has been migrated. Page will be reloaded");
157+
window.location.reload();
158+
}
159+
160+
Callback that is called when migration is completed in _other browser tab or window_. For instance when user opens a new tab with the new version of the app.
161+
In simple cases the easiest way is to refresh the page because the old code likely can not work with migrated data anyway
162+
163+
## **onVersionMissmatch**
164+
deafult: () => {}
165+
166+
Callback that is called when version of the data in IndexedDb is _higher_ than the **version**. Should not happen in normal situations

src/lib/jotai-minidb.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
/**
22
* Experiment with jotai v2 api and simple key-value store (no types, no collections)
33
* TODO:
4-
* - Write README
5-
* - Publish
6-
*
74
* - Refactor
5+
* - More test
86
* - Clean atom family when delete
97
* - Migrations: validate correct migrations are provided, decide what to do if migration doesn't return item
108
*/
@@ -53,7 +51,7 @@ const DEFAULT_CONFIG: Config = {
5351
version: 0,
5452
migrations: {},
5553
onMigrationCompleted: () => {
56-
alert("Data has been migrated. Page should be reloaded");
54+
alert("Data has been migrated. Page will be reloaded");
5755
window.location.reload();
5856
},
5957
onVersionMissmatch: () => {},

0 commit comments

Comments
 (0)