amateras 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -5
- package/ext/html/node/$Anchor.ts +1 -1
- package/ext/html/node/$Input.ts +26 -2
- package/ext/html/node/$Label.ts +10 -1
- package/ext/i18n/src/structure/I18nDictionary.ts +2 -2
- package/ext/idb/README.md +127 -0
- package/ext/idb/package.json +13 -0
- package/ext/idb/src/core.ts +6 -0
- package/ext/idb/src/index.ts +17 -0
- package/ext/idb/src/lib/$IDBRequest.ts +8 -0
- package/ext/idb/src/structure/$IDB.ts +63 -0
- package/ext/idb/src/structure/$IDBCursor.ts +34 -0
- package/ext/idb/src/structure/$IDBIndex.ts +48 -0
- package/ext/idb/src/structure/$IDBStore.ts +103 -0
- package/ext/idb/src/structure/$IDBStoreBase.ts +30 -0
- package/ext/idb/src/structure/$IDBTransaction.ts +38 -0
- package/ext/idb/src/structure/builder/$IDBBuilder.ts +230 -0
- package/ext/idb/src/structure/builder/$IDBStoreBuilder.ts +100 -0
- package/ext/markdown/index.ts +121 -0
- package/ext/markdown/package.json +8 -0
- package/ext/router/index.ts +1 -1
- package/ext/router/node/Route.ts +2 -2
- package/ext/router/node/RouterAnchor.ts +6 -1
- package/package.json +5 -2
- package/src/core.ts +5 -3
- package/src/global.ts +3 -0
- package/src/lib/native.ts +9 -4
- package/src/lib/sleep.ts +3 -1
- package/src/lib/toArray.ts +9 -0
- package/src/lib/trycatch.ts +17 -0
- package/src/node/$Element.ts +2 -14
- package/src/node/$Node.ts +21 -8
- package/src/structure/Signal.ts +2 -2
package/README.md
CHANGED
|
@@ -99,11 +99,13 @@ $(document.body).content([
|
|
|
99
99
|
```
|
|
100
100
|
|
|
101
101
|
## Packages
|
|
102
|
-
The packages size result using Vite 7.0 with default bundle settings, polyfills code
|
|
102
|
+
The packages size result using Vite 7.0 with default bundle settings, polyfills code included.
|
|
103
103
|
| Package name | Size | Size(gzip) | Description |
|
|
104
104
|
| --- | --- | --- | --- |
|
|
105
|
-
| amateras | 5.
|
|
106
|
-
| amateras/html | 0.
|
|
105
|
+
| amateras | 5.67 kB | 2.52 kB | Core |
|
|
106
|
+
| amateras/html | 0.99 kB | 0.26 kB | Import HTMLElement types and methods |
|
|
107
107
|
| [amateras/css](./ext/css/README.md) | 3.65 kB | 1.41 kB | Style in JS |
|
|
108
|
-
| [amateras/router](./ext/router/README.md) | 3.
|
|
109
|
-
| [amateras/i18n](./ext/i18n/README.md) | 1.
|
|
108
|
+
| [amateras/router](./ext/router/README.md) | 3.79 kB | 1.71 kB | Amateras Router |
|
|
109
|
+
| [amateras/i18n](./ext/i18n/README.md) | 1.48 kB | 0.58 kB | I18n translations |
|
|
110
|
+
| [amateras/idb](./ext/idb/README.md) | 5.35 kB | 2.03 kB | IndexedDB Builder and API Wrapper |
|
|
111
|
+
| amateras/markdown | 1.89 kB | 0.67 kB | Markdown Converter |
|
package/ext/html/node/$Anchor.ts
CHANGED
|
@@ -40,7 +40,7 @@ export interface $Anchor extends $HTMLElement<HTMLAnchorElement> {
|
|
|
40
40
|
type(): string;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
export type AnchorTarget = '_self' | '_blank' | '_parent' | '_top' | '_unfenced_top' | '';
|
|
43
|
+
export type AnchorTarget = '_self' | '_blank' | '_parent' | '_top' | '_unfenced_top' | '' | '_replace';
|
|
44
44
|
|
|
45
45
|
declare module '#core' {
|
|
46
46
|
export function $(nodeName: 'a'): $Anchor
|
package/ext/html/node/$Input.ts
CHANGED
|
@@ -143,8 +143,8 @@ export interface $Input extends $HTMLElement<HTMLInputElement> {
|
|
|
143
143
|
step(step: $Parameter<string>): this;
|
|
144
144
|
step(): string;
|
|
145
145
|
/** {@link HTMLInputElement.type} */
|
|
146
|
-
type(type: $Parameter<
|
|
147
|
-
type():
|
|
146
|
+
type(type: $Parameter<InputType>): this;
|
|
147
|
+
type(): InputType;
|
|
148
148
|
/** {@link HTMLInputElement.value} */
|
|
149
149
|
value(value: $Parameter<string>): this;
|
|
150
150
|
value(): string;
|
|
@@ -162,6 +162,30 @@ export interface $Input extends $HTMLElement<HTMLInputElement> {
|
|
|
162
162
|
width(): number;
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
export type InputType =
|
|
166
|
+
| 'button'
|
|
167
|
+
| 'checkbox'
|
|
168
|
+
| 'color'
|
|
169
|
+
| 'date'
|
|
170
|
+
| 'datetime-local'
|
|
171
|
+
| 'email'
|
|
172
|
+
| 'file'
|
|
173
|
+
| 'hidden'
|
|
174
|
+
| 'image'
|
|
175
|
+
| 'month'
|
|
176
|
+
| 'number'
|
|
177
|
+
| 'password'
|
|
178
|
+
| 'radio'
|
|
179
|
+
| 'range'
|
|
180
|
+
| 'reset'
|
|
181
|
+
| 'search'
|
|
182
|
+
| 'submit'
|
|
183
|
+
| 'tel'
|
|
184
|
+
| 'text'
|
|
185
|
+
| 'time'
|
|
186
|
+
| 'url'
|
|
187
|
+
| 'week';
|
|
188
|
+
|
|
165
189
|
assignHelper(HTMLInputElement, $Input, 'input');
|
|
166
190
|
|
|
167
191
|
declare module '#core' {
|
package/ext/html/node/$Label.ts
CHANGED
|
@@ -7,7 +7,16 @@ export class $Label extends $HTMLElement<HTMLLabelElement> {
|
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export interface $Label extends $HTMLElement<HTMLLabelElement> {
|
|
10
|
+
export interface $Label extends $HTMLElement<HTMLLabelElement> {
|
|
11
|
+
/** {@link HTMLLabelElement.control} */
|
|
12
|
+
readonly control: HTMLElement | null;
|
|
13
|
+
/** {@link HTMLLabelElement.form} */
|
|
14
|
+
readonly form: HTMLFormElement | null;
|
|
15
|
+
|
|
16
|
+
/** {@link HTMLLabelElement.htmlFor} */
|
|
17
|
+
htmlFor(htmlFor: $Parameter<string>): this;
|
|
18
|
+
htmlFor(): string;
|
|
19
|
+
}
|
|
11
20
|
|
|
12
21
|
assignHelper(HTMLLabelElement, $Label, 'label');
|
|
13
22
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { _instanceof, isObject } from "amateras/lib/native";
|
|
1
|
+
import { _instanceof, isFunction, isObject } from "amateras/lib/native";
|
|
2
2
|
|
|
3
3
|
export class I18nDictionary {
|
|
4
4
|
#context: I18nDictionaryContext | Promise<I18nDictionaryContext> | null = null;
|
|
5
5
|
#fetch: I18nDictionaryContextImporter | null = null;
|
|
6
6
|
constructor(resolver: I18nDictionaryContext | I18nDictionaryContextImporter) {
|
|
7
|
-
if (
|
|
7
|
+
if (isFunction(resolver)) this.#fetch = resolver;
|
|
8
8
|
else this.#context = resolver;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# amateras/idb
|
|
2
|
+
|
|
3
|
+
## Usage
|
|
4
|
+
```ts
|
|
5
|
+
import 'amateras';
|
|
6
|
+
import 'amateras/idb';
|
|
7
|
+
|
|
8
|
+
// configure indexedDB
|
|
9
|
+
const idb = await $.idb('MyDB', 1)
|
|
10
|
+
// add store
|
|
11
|
+
.store('userStore', store => store
|
|
12
|
+
.keyPath('id')
|
|
13
|
+
.autoIncrement(true)
|
|
14
|
+
// define store object type
|
|
15
|
+
.schema<{
|
|
16
|
+
id: number,
|
|
17
|
+
name: string,
|
|
18
|
+
age: number
|
|
19
|
+
}>()
|
|
20
|
+
.index('by_age', { keyPath: 'age' })
|
|
21
|
+
)
|
|
22
|
+
// open idb
|
|
23
|
+
.open();
|
|
24
|
+
|
|
25
|
+
// open `readwrite` transaction with `userStore`
|
|
26
|
+
const result = await idb.store('userStore', true, async store => {
|
|
27
|
+
store.put({name: 'Amateras', age: 16});
|
|
28
|
+
return store.getAll();
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
console.log(result); // [ { name: 'Amateras', age: 16, id: 1 } ]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick Examples
|
|
35
|
+
|
|
36
|
+
### Get object from store
|
|
37
|
+
```ts
|
|
38
|
+
await idb.store('userStore', store => store.get(1))
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Get all object from store
|
|
42
|
+
```ts
|
|
43
|
+
await idb.store('userStore', store => store.getAll())
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Add object to store
|
|
47
|
+
Any changes to database without `readwrite` mode is resisted, pass `true` value to `writable` argument to enable `readwrite` mode.
|
|
48
|
+
``` ts
|
|
49
|
+
await idb.store('userStore', true, store => store.add({name: 'Tsukimi', age: 16}))
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Put object to store
|
|
53
|
+
The `.put()` method is different with `.add()` method, put object will replace the object of existed key.
|
|
54
|
+
``` ts
|
|
55
|
+
await idb.store('userStore', true, store => store.put({name: 'Amateras', age: 17}))
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Use index
|
|
59
|
+
```ts
|
|
60
|
+
await idb.store('userStore', true, store => store.index('by_age').getAll(16))
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Operating multiple stores in one transaction
|
|
64
|
+
```ts
|
|
65
|
+
await idb.transaction(['userStore', 'itemStore'], true, async transaction => {
|
|
66
|
+
transaction.store('itemStore').put({id: 2, name: 'Item 2'})
|
|
67
|
+
return {
|
|
68
|
+
users: await transaction.store('userStore').getAll(),
|
|
69
|
+
items: await transaction.store('itemStore').getAll()
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Open cursor for advance operations
|
|
75
|
+
```ts
|
|
76
|
+
await idb.store('userStore', true, async store => {
|
|
77
|
+
const teenagers = []
|
|
78
|
+
await store.cursor(cursor => {
|
|
79
|
+
if (cursor.value.age < 18) teenagers.push(cursor.value);
|
|
80
|
+
cursor.continue();
|
|
81
|
+
})
|
|
82
|
+
return teenagers;
|
|
83
|
+
})
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Upgrade Database
|
|
87
|
+
Using `.upgrade()` in `$IDBStoreBuilder` can set the store upgrade handle function to list. The store upgrade function is used for change object structure when the store is upgrading.
|
|
88
|
+
|
|
89
|
+
For example, in version 10:
|
|
90
|
+
```ts
|
|
91
|
+
{
|
|
92
|
+
id: number,
|
|
93
|
+
name: string
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
After version 11, we want to change the object structure:
|
|
98
|
+
```ts
|
|
99
|
+
{
|
|
100
|
+
id: string,
|
|
101
|
+
name: string,
|
|
102
|
+
intro: string
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
You see the `id` is change to `string` type, and come with the new property `intro`. In the following example, we will upgrade this object structure, and this upgrade is only executed when client IDB version is lower than argument `version`.
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
store.upgrade(11, (objects) => {
|
|
110
|
+
return objects.map({key, value} => {
|
|
111
|
+
// since we didn't defined the object type in every different version,
|
|
112
|
+
// the object is any type, please handle the upgrade carefully
|
|
113
|
+
return { key,
|
|
114
|
+
value: {
|
|
115
|
+
...value,
|
|
116
|
+
id: value.id.toString(), // convert to string
|
|
117
|
+
intro: `Hi, my name is ${object.name}` // add new intro property
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The upgrade function is set, this will be executed on `$IDBBuilder.open()`.
|
|
125
|
+
|
|
126
|
+
> [!NOTE]
|
|
127
|
+
> You should leave all the upgrade function in your codebase, unless you are sure the client database version is larger than this upgrade function.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { _Object_assign } from "amateras/lib/native"
|
|
2
|
+
import { $IDBBuilder } from "#structure/builder/$IDBBuilder"
|
|
3
|
+
|
|
4
|
+
declare module 'amateras/core' {
|
|
5
|
+
export namespace $ {
|
|
6
|
+
/**
|
|
7
|
+
* Create {@link $IDBBuilder} with IDB name and version number.
|
|
8
|
+
* @param name - Database name
|
|
9
|
+
* @param version - Version number
|
|
10
|
+
*/
|
|
11
|
+
export function idb<N extends string, V extends number>(name: N, version: V): $IDBBuilder<{name: N, version: V, stores: {}}>;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
_Object_assign($, {
|
|
16
|
+
idb: (name: string, version: number) => new $IDBBuilder({name, version, stores: {}})
|
|
17
|
+
})
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { _Promise } from "../../../../src/lib/native";
|
|
2
|
+
|
|
3
|
+
export const $IDBRequest = <T>(req: IDBRequest<T>, handle?: (req: IDBRequest<T>, resolve: (value: T) => void) => void) => {
|
|
4
|
+
return new _Promise<T>((resolve, reject) => {
|
|
5
|
+
req.onsuccess = _ => handle ? handle(req, resolve) : resolve(req.result);
|
|
6
|
+
req.onerror = _ => reject(req.error);
|
|
7
|
+
})
|
|
8
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { _Array_from, _null, _Object_assign, _Object_fromEntries, _Promise, isBoolean } from "amateras/lib/native";
|
|
2
|
+
import { $IDBStore, type $IDBStoreConfig } from "./$IDBStore";
|
|
3
|
+
import { $IDBTransaction } from "./$IDBTransaction";
|
|
4
|
+
|
|
5
|
+
export interface $IDB<Config extends $IDBConfig = any> {
|
|
6
|
+
/** Object with store name key and `$IDBStoreConfig` value. */
|
|
7
|
+
readonly stores: Config['stores'];
|
|
8
|
+
}
|
|
9
|
+
export class $IDB<Config extends $IDBConfig = any> {
|
|
10
|
+
/** {@link IDBDatabase} instance. */
|
|
11
|
+
readonly idb: IDBDatabase;
|
|
12
|
+
/** IndexedDB database name. */
|
|
13
|
+
readonly name: Config['name'];
|
|
14
|
+
/** IndexedDB database version. */
|
|
15
|
+
readonly version: Config['version'];
|
|
16
|
+
constructor(idb: IDBDatabase, config: Omit<Config, 'name' | 'version'>) {
|
|
17
|
+
this.idb = idb;
|
|
18
|
+
this.name = idb.name;
|
|
19
|
+
this.version = idb.version;
|
|
20
|
+
_Object_assign(this, config);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Create new transaction with the store name, you can directly operating the target store with `handle` function. This method will return a `Promise` with the `handle` return type value.
|
|
25
|
+
* @param name - Store name
|
|
26
|
+
* @param writable - Enable readwrite mode
|
|
27
|
+
* @param handle - Function execute on transaction opened
|
|
28
|
+
* @returns The handle function return type
|
|
29
|
+
*/
|
|
30
|
+
async store<K extends keyof Config['stores'] & string, T>(name: K, handle: (store: $IDBStore<Config['stores'][K]>) => T): Promise<T>
|
|
31
|
+
async store<K extends keyof Config['stores'] & string, T>(name: K, writable: boolean, handle: (store: $IDBStore<Config['stores'][K]>) => T): Promise<T>
|
|
32
|
+
async store<K extends keyof Config['stores'] & string, T>(name: K, resolver: boolean | Function, handle?: Function) {
|
|
33
|
+
if (isBoolean(resolver)) return this.transaction(name, resolver, $tx => handle!($tx.store(name)));
|
|
34
|
+
else return this.transaction(name, $tx => resolver($tx.store(name)))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Create new transaction with the store name, you can pass multiple store name into `storeName` argument for operating multiple store in one transaction.
|
|
39
|
+
* @param store - Store name, allow string array
|
|
40
|
+
* @param writable - Enable readwrite mode
|
|
41
|
+
* @param handle - Function execute on transaction opened
|
|
42
|
+
* @returns The handle function return type
|
|
43
|
+
*/
|
|
44
|
+
async transaction<K extends keyof Config['stores'] & string, T>(store: K | K[], handle: (transaction: $IDBTransaction<{ stores: Pick<Config['stores'], K> }>) => T): Promise<T>
|
|
45
|
+
async transaction<K extends keyof Config['stores'] & string, T>(store: K | K[], writable: boolean, handle: (transaction: $IDBTransaction<{ stores: Pick<Config['stores'], K> }>) => T): Promise<T>
|
|
46
|
+
async transaction<K extends keyof Config['stores'] & string, T>(store: K | K[], resolver?: boolean | Function, handle?: Function) {
|
|
47
|
+
handle = isBoolean(resolver) ? handle : resolver;
|
|
48
|
+
resolver = isBoolean(resolver) ? resolver : false;
|
|
49
|
+
const tx = this.idb.transaction(store, resolver ? 'readwrite' : 'readonly');
|
|
50
|
+
const $tx = new $IDBTransaction(this, tx);
|
|
51
|
+
const result = handle!($tx);
|
|
52
|
+
return new _Promise<T>((resolve, reject) => {
|
|
53
|
+
tx.oncomplete = _ => resolve(result);
|
|
54
|
+
tx.onerror = tx.onabort = _ => tx.error && reject(tx.error);
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type $IDBConfig = {
|
|
60
|
+
name: string;
|
|
61
|
+
version: number;
|
|
62
|
+
stores: { [key: string]: $IDBStoreConfig }
|
|
63
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { _instanceof, _Object_assign, _Promise } from "amateras/lib/native";
|
|
2
|
+
import { $IDBRequest } from "#lib/$IDBRequest";
|
|
3
|
+
import { $IDBStore, type $IDBStoreConfig } from "./$IDBStore";
|
|
4
|
+
import { $IDBIndex } from "./$IDBIndex";
|
|
5
|
+
import type { $IDBStoreBase } from "./$IDBStoreBase";
|
|
6
|
+
|
|
7
|
+
export interface $IDBCursor {}
|
|
8
|
+
export class $IDBCursor<StoreConfig extends $IDBStoreConfig = any> {
|
|
9
|
+
#cursor: IDBCursorWithValue;
|
|
10
|
+
readonly store: $IDBStore<StoreConfig>;
|
|
11
|
+
readonly direction;
|
|
12
|
+
constructor(store: $IDBStoreBase, cursor: IDBCursorWithValue) {
|
|
13
|
+
this.#cursor = cursor;
|
|
14
|
+
this.store = _instanceof(store, $IDBIndex<StoreConfig>) ? store.store : store as $IDBStore;
|
|
15
|
+
this.direction = cursor.direction;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get value() { return this.#cursor.value }
|
|
19
|
+
get key() { return this.#cursor.key }
|
|
20
|
+
get primaryKey() { return this.#cursor.primaryKey }
|
|
21
|
+
|
|
22
|
+
async update<T>(value: T) {
|
|
23
|
+
return $IDBRequest(this.#cursor.update(value))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async delete() {
|
|
27
|
+
return $IDBRequest(this.#cursor.delete())
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
continue(key?: IDBValidKey) { this.#cursor.continue(key) }
|
|
31
|
+
continuePrimaryKey(key: IDBValidKey, primaryKey: IDBValidKey) { this.#cursor.continuePrimaryKey(key, primaryKey) }
|
|
32
|
+
advance(count: number) { this.#cursor.advance(count) }
|
|
33
|
+
abort() { this.#cursor.request.transaction?.abort() }
|
|
34
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { _Object_assign } from "amateras/lib/native";
|
|
2
|
+
import type { $IDBStore, $IDBStoreConfig, QueryMultipleKeyPath } from "./$IDBStore";
|
|
3
|
+
import { $IDBStoreBase } from "./$IDBStoreBase";
|
|
4
|
+
import type { $IDBCursor } from "./$IDBCursor";
|
|
5
|
+
|
|
6
|
+
export class $IDBIndex<StoreConfig extends $IDBStoreConfig = any, Config extends $IDBIndexConfig = any> extends $IDBStoreBase{
|
|
7
|
+
readonly store: $IDBStore;
|
|
8
|
+
constructor(store: $IDBStore, index: IDBIndex, config: Config) {
|
|
9
|
+
super(index);
|
|
10
|
+
this.store = store;
|
|
11
|
+
_Object_assign(this, config);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface $IDBIndex<StoreConfig extends $IDBStoreConfig, Config extends $IDBIndexConfig = any> {
|
|
16
|
+
readonly unique: Config['unique'];
|
|
17
|
+
readonly multiEntry: Config['multiEntry'];
|
|
18
|
+
readonly keyPath: Config['keyPath'];
|
|
19
|
+
|
|
20
|
+
/** {@link IDBIndex.cursor} */
|
|
21
|
+
cursor(handle: (cursor: $IDBCursor) => void, query?: IDBValidKey | IDBKeyRange | null, direction?: IDBCursorDirection): Promise<null>
|
|
22
|
+
|
|
23
|
+
/** {@link IDBIndex.keyCursor} */
|
|
24
|
+
keyCursor(handle: (cursor: $IDBCursor) => void, query?: IDBValidKey | IDBKeyRange | null, direction?: IDBCursorDirection): Promise<null>
|
|
25
|
+
|
|
26
|
+
/** {@link IDBIndex.count} */
|
|
27
|
+
count(query?: $IDBIndexKey<StoreConfig, Config> | IDBKeyRange): Promise<number>;
|
|
28
|
+
|
|
29
|
+
/** {@link IDBIndex.get} */
|
|
30
|
+
get(query: $IDBIndexKey<StoreConfig, Config> | IDBKeyRange): Promise<StoreConfig['schema']>
|
|
31
|
+
|
|
32
|
+
/** {@link IDBIndex.getAll} */
|
|
33
|
+
getAll(query?: $IDBIndexKey<StoreConfig, Config> | IDBKeyRange): Promise<StoreConfig['schema'][]>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type $IDBIndexConfig = {
|
|
37
|
+
unique: boolean;
|
|
38
|
+
multiEntry: boolean;
|
|
39
|
+
keyPath: string | string[];
|
|
40
|
+
name: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type $IDBIndexKey<StoreConfig extends $IDBStoreConfig, Config extends $IDBIndexConfig> =
|
|
44
|
+
Config['keyPath'] extends string
|
|
45
|
+
? StoreConfig['schema'][Config['keyPath']]
|
|
46
|
+
: Config['keyPath'] extends string[]
|
|
47
|
+
? QueryMultipleKeyPath<Config['keyPath'], StoreConfig>
|
|
48
|
+
: IDBValidKey;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { _instanceof, _Object_assign, _Promise } from "amateras/lib/native";
|
|
2
|
+
import { $IDBIndex, type $IDBIndexConfig } from "./$IDBIndex";
|
|
3
|
+
import { $IDBRequest } from "#lib/$IDBRequest";
|
|
4
|
+
import { $IDBStoreBase } from "./$IDBStoreBase";
|
|
5
|
+
import type { $IDBCursor } from "./$IDBCursor";
|
|
6
|
+
|
|
7
|
+
export class $IDBStore<Config extends $IDBStoreConfig = any> extends $IDBStoreBase {
|
|
8
|
+
#store: IDBObjectStore;
|
|
9
|
+
constructor(store: IDBObjectStore, config: Config) {
|
|
10
|
+
super(store);
|
|
11
|
+
this.#store = store;
|
|
12
|
+
_Object_assign(this, config);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** {@link IDBObjectStore.put} */
|
|
16
|
+
put<V extends $IDBStoreValueResolver<Config>>(...value: V): Promise<$IDBStoreKey<Config>>
|
|
17
|
+
put(value: any, key?: any) {
|
|
18
|
+
return $IDBRequest(this.#store.put(value, key));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** {@link IDBObjectStore.add} */
|
|
22
|
+
add<V extends $IDBStoreValueResolver<Config>>(value: V): Promise<$IDBStoreKey<Config>>
|
|
23
|
+
add(value: any, key?: any) {
|
|
24
|
+
return $IDBRequest(this.#store.add(value, key));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** {@link IDBObjectStore.delete} */
|
|
28
|
+
delete(query: $IDBStoreKey<Config> | IDBKeyRange): Promise<undefined>;
|
|
29
|
+
delete(query: IDBValidKey | IDBKeyRange) {
|
|
30
|
+
return $IDBRequest(this.#store.delete(query));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** {@link IDBObjectStore.clear} */
|
|
34
|
+
clear() {
|
|
35
|
+
return $IDBRequest(this.#store.clear())
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Get and return {@link $IDBIndex} */
|
|
39
|
+
index<K extends keyof Config['indexes'] & string>(name: K): $IDBIndex<Config, Config['indexes'][K]>
|
|
40
|
+
index(name: keyof Config['indexes'] & string) {
|
|
41
|
+
return new $IDBIndex(this, this.#store.index(name), this.indexes[name]!)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface $IDBStore<Config extends $IDBStoreConfig = any> {
|
|
46
|
+
readonly name: Config['name'];
|
|
47
|
+
readonly indexes: Config['indexes'];
|
|
48
|
+
readonly schema: Config['schema'];
|
|
49
|
+
readonly keyPath: Config['keyPath'];
|
|
50
|
+
readonly autoIncrement: Config['autoIncrement'];
|
|
51
|
+
|
|
52
|
+
/** {@link IDBObjectStore.cursor} */
|
|
53
|
+
cursor(handle: (cursor: $IDBCursor) => void, query?: IDBValidKey | IDBKeyRange | null, direction?: IDBCursorDirection): Promise<null>
|
|
54
|
+
|
|
55
|
+
/** {@link IDBObjectStore.keyCursor} */
|
|
56
|
+
keyCursor(handle: (cursor: $IDBCursor) => void, query?: IDBValidKey | IDBKeyRange | null, direction?: IDBCursorDirection): Promise<null>
|
|
57
|
+
|
|
58
|
+
/** {@link IDBObjectStore.count} */
|
|
59
|
+
count(query?: $IDBStoreKey<Config> | IDBKeyRange): Promise<number>;
|
|
60
|
+
|
|
61
|
+
/** {@link IDBObjectStore.get} */
|
|
62
|
+
get(query: $IDBStoreKey<Config> | IDBKeyRange): Promise<Config['schema']>
|
|
63
|
+
|
|
64
|
+
/** {@link IDBObjectStore.getAll} */
|
|
65
|
+
getAll(query?: $IDBStoreKey<Config> | IDBKeyRange): Promise<Config['schema'][]>
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type $IDBStoreConfig = {
|
|
69
|
+
name: string;
|
|
70
|
+
indexes: { [key: string]: $IDBIndexConfig };
|
|
71
|
+
schema: any;
|
|
72
|
+
keyPath: string | string[] | null;
|
|
73
|
+
autoIncrement: boolean;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export type $IDBStoreValueResolver<Config extends $IDBStoreConfig> =
|
|
77
|
+
Config['keyPath'] extends string
|
|
78
|
+
? Config['autoIncrement'] extends true
|
|
79
|
+
? [Omit<Config['schema'], Config['keyPath']> & {[key in Config['keyPath']]?: Config['schema'][key]}]
|
|
80
|
+
: [Config['schema']]
|
|
81
|
+
: Config['keyPath'] extends string[]
|
|
82
|
+
? [Config['schema']]
|
|
83
|
+
: Config['autoIncrement'] extends true
|
|
84
|
+
? [Config['schema']]
|
|
85
|
+
: [Config['schema'], IDBValidKey];
|
|
86
|
+
|
|
87
|
+
export type $IDBStoreKey<Config extends $IDBStoreConfig> =
|
|
88
|
+
Config['keyPath'] extends string
|
|
89
|
+
? Config['schema'][Config['keyPath']]
|
|
90
|
+
: Config['keyPath'] extends string[]
|
|
91
|
+
? QueryMultipleKeyPath<Config['keyPath'], Config>
|
|
92
|
+
: Config['autoIncrement'] extends true
|
|
93
|
+
? number
|
|
94
|
+
: IDBValidKey;
|
|
95
|
+
|
|
96
|
+
export type QueryMultipleKeyPath<T extends string[], Config extends { schema: {} }> =
|
|
97
|
+
T extends [infer A, ...infer Rest]
|
|
98
|
+
? A extends keyof Config['schema']
|
|
99
|
+
? Rest extends string[]
|
|
100
|
+
? [Config['schema'][A], ...QueryMultipleKeyPath<Rest, Config>]
|
|
101
|
+
: [Config['schema'][A]]
|
|
102
|
+
: never
|
|
103
|
+
: []
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { _Array_from, _instanceof, _null, _Promise } from "amateras/lib/native";
|
|
2
|
+
import { $IDBRequest } from "#lib/$IDBRequest";
|
|
3
|
+
import { $IDBCursor } from "./$IDBCursor";
|
|
4
|
+
|
|
5
|
+
export abstract class $IDBStoreBase {
|
|
6
|
+
readonly #instance;
|
|
7
|
+
constructor(instance: IDBObjectStore | IDBIndex) {
|
|
8
|
+
this.#instance = instance;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
cursor(handle: (cursor: $IDBCursor) => void, query?: IDBValidKey | IDBKeyRange | null, direction?: IDBCursorDirection) {
|
|
12
|
+
return $IDBRequest(this.#instance.openCursor(query, direction), (req , resolve) => req.result ? handle(new $IDBCursor(this, req.result)) : resolve(null))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
keyCursor(handle: (cursor: $IDBCursor) => void, query?: IDBValidKey | IDBKeyRange | null, direction?: IDBCursorDirection) {
|
|
16
|
+
return $IDBRequest(this.#instance.openCursor(query, direction), (req , resolve) => req.result ? handle(new $IDBCursor(this, req.result)) : resolve(null))
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
count(query?: IDBValidKey | IDBKeyRange) {
|
|
20
|
+
return $IDBRequest(this.#instance.count(query));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get(query: IDBValidKey | IDBKeyRange) {
|
|
24
|
+
return $IDBRequest(this.#instance.get(query))
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
getAll(query?: IDBValidKey | IDBKeyRange) {
|
|
28
|
+
return $IDBRequest(this.#instance.getAll(query))
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { _Array_from, _Object_assign, forEach } from "../../../../src/lib/native";
|
|
2
|
+
import type { $IDB } from "./$IDB";
|
|
3
|
+
import { $IDBStore, type $IDBStoreConfig } from "./$IDBStore";
|
|
4
|
+
|
|
5
|
+
export interface $IDBTransaction {}
|
|
6
|
+
export class $IDBTransaction<Config extends $IDBTransactionConfig = any> {
|
|
7
|
+
#transaction: IDBTransaction;
|
|
8
|
+
#$idb: $IDB
|
|
9
|
+
readonly writable: boolean;
|
|
10
|
+
readonly stores: Config['stores'] = {};
|
|
11
|
+
readonly durability: string;
|
|
12
|
+
constructor($idb: $IDB, transaction: IDBTransaction) {
|
|
13
|
+
this.#transaction = transaction;
|
|
14
|
+
this.#$idb = $idb;
|
|
15
|
+
this.writable = transaction.mode !== 'readonly';
|
|
16
|
+
this.durability = transaction.durability;
|
|
17
|
+
forEach(_Array_from(transaction.objectStoreNames), name => {
|
|
18
|
+
_Object_assign(this.stores, { [name]: $idb.stores[name] })
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
store<N extends keyof Config['stores'] & string>(name: N): $IDBStore<Config['stores'][N]>
|
|
23
|
+
store(name: string) {
|
|
24
|
+
return new $IDBStore(this.#transaction.objectStore(name), this.#$idb.stores[name]);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
commit() {
|
|
28
|
+
return this.#transaction.commit();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
abort() {
|
|
32
|
+
return this.#transaction.abort();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type $IDBTransactionConfig = {
|
|
37
|
+
stores: { [key: string]: $IDBStoreConfig }
|
|
38
|
+
}
|