locality-idb 1.2.1 → 1.3.1
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 +561 -2
- package/dist/index.cjs +367 -74
- package/dist/index.d.cts +372 -189
- package/dist/index.d.mts +372 -189
- package/dist/index.iife.js +367 -74
- package/dist/index.mjs +356 -75
- package/dist/index.umd.js +367 -74
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,6 +41,8 @@
|
|
|
41
41
|
- [Select/Query Records](#selectquery-records)
|
|
42
42
|
- [Update Records](#update-records)
|
|
43
43
|
- [Delete Records](#delete-records)
|
|
44
|
+
- [Transactions](#transactions)
|
|
45
|
+
- [Export Database](#export-database)
|
|
44
46
|
- [API Reference](#-api-reference)
|
|
45
47
|
- [Locality Class](#locality-class)
|
|
46
48
|
- [Schema Functions](#schema-functions)
|
|
@@ -64,6 +66,8 @@
|
|
|
64
66
|
- 🛠️ **Rich Column Types**: Support for various data types including custom types
|
|
65
67
|
- ✅ **Built-in Validation**: Automatic data type validation for built-in column types during insert and update operations
|
|
66
68
|
- 🔧 **Custom Validators**: Define custom validation logic for columns to enforce complex rules
|
|
69
|
+
- 🔒 **Atomic Transactions**: Execute multiple operations across tables with automatic rollback on failure
|
|
70
|
+
- 📤 **Database Export**: Export database data as JSON for backup, migration, or debugging
|
|
67
71
|
|
|
68
72
|
---
|
|
69
73
|
|
|
@@ -205,6 +209,8 @@ Locality IDB supports a wide range of column types:
|
|
|
205
209
|
| `text()` / `string()` | Text strings | `column.text()` |
|
|
206
210
|
| `char(length?)` | Fixed-length string | `column.char(10)` |
|
|
207
211
|
| `varchar(length?)` | Variable-length string | `column.varchar(255)` |
|
|
212
|
+
| `email()` | Email strings | `column.email()` |
|
|
213
|
+
| `url()` | URL strings | `column.url()` |
|
|
208
214
|
| `bool()` / `boolean()` | Boolean values | `column.bool()` |
|
|
209
215
|
| `date()` | Date objects | `column.date()` |
|
|
210
216
|
| `timestamp()` | ISO 8601 timestamps ([auto-generated](#utility-functions)) | `column.timestamp()` |
|
|
@@ -251,7 +257,7 @@ const productId: ProductId = 2 as ProductId;
|
|
|
251
257
|
// userId = productId; // ❌ Type error!
|
|
252
258
|
```
|
|
253
259
|
|
|
254
|
-
##### String Types (`text`, `string`, `char`, `varchar`)
|
|
260
|
+
##### String Types (`text`, `string`, `char`, `varchar`, `email`, `url`)
|
|
255
261
|
|
|
256
262
|
```typescript
|
|
257
263
|
// Literal unions for enum-like behavior
|
|
@@ -277,8 +283,40 @@ const profileSchema = defineSchema({
|
|
|
277
283
|
website: column.varchar<URL>(500).optional(),
|
|
278
284
|
},
|
|
279
285
|
});
|
|
286
|
+
|
|
287
|
+
// or use specialized `email` & `url` methods + types with built-in validation
|
|
288
|
+
const advancedProfileSchema = defineSchema({
|
|
289
|
+
profiles: {
|
|
290
|
+
id: column.int().pk().auto(),
|
|
291
|
+
email: column.email().unique(), // Validates emails
|
|
292
|
+
website: column.url().optional(), // Validates URLs (internally uses URL constructor)
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
#### Auto-generated Types (`uuid`, `timestamp`)
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
const schema = defineSchema({
|
|
301
|
+
sessions: {
|
|
302
|
+
id: column.uuid().pk(), // Auto-generated UUID v4
|
|
303
|
+
idWithDefault: column.uuid().pk().default(uuid({ version: 'v6' })), // Replace auto-generated UUID v4
|
|
304
|
+
createdAt: column.timestamp(), // Auto-generated timestamp
|
|
305
|
+
defaultTs: column.timestamp().default(getTimestamp()), // Auto-generated timestamp with default using utility built-in function
|
|
306
|
+
customTs: column.timestamp().default(new Chronos().toLocalISOString() as Timestamp), // Default timestamp with custom format
|
|
307
|
+
},
|
|
308
|
+
});
|
|
280
309
|
```
|
|
281
310
|
|
|
311
|
+
> **Note:**
|
|
312
|
+
>
|
|
313
|
+
> - Auto-generated values can be overridden by providing explicit values during insert.
|
|
314
|
+
> - Use the `default()` modifier to set custom default values instead of auto-generated ones.
|
|
315
|
+
> - Auto-generated values are generated at runtime during insert operations.
|
|
316
|
+
> - Type extensions for `uuid` and `timestamp` are not applicable since they are already typed.
|
|
317
|
+
> - For custom UUID versions, use [`uuid`](https://toolbox.nazmul-nhb.dev/docs/utilities/hash/uuid) utility from [`nhb-toolbox`](https://www.npmjs.com/package/nhb-toolbox).
|
|
318
|
+
> - For custom timestamp formats, use date libraries like [`Chronos`](https://toolbox.nazmul-nhb.dev/docs/classes/Chronos) (from [`nhb-toolbox`](https://www.npmjs.com/package/nhb-toolbox)) or [`date-fns`](https://www.npmjs.com/package/date-fns) to generate ISO 8601 strings.
|
|
319
|
+
|
|
282
320
|
##### Boolean Types (`bool`, `boolean`)
|
|
283
321
|
|
|
284
322
|
```typescript
|
|
@@ -688,6 +726,163 @@ await db
|
|
|
688
726
|
.run();
|
|
689
727
|
```
|
|
690
728
|
|
|
729
|
+
### Transactions
|
|
730
|
+
|
|
731
|
+
Transactions enable you to perform multiple operations across multiple tables atomically. All operations in a transaction either succeed together or fail together, ensuring data consistency.
|
|
732
|
+
|
|
733
|
+
#### Basic Transaction
|
|
734
|
+
|
|
735
|
+
```typescript
|
|
736
|
+
// Create a user and their first post atomically
|
|
737
|
+
await db.transaction(['users', 'posts'], async (ctx) => {
|
|
738
|
+
const newUser = await ctx
|
|
739
|
+
.insert('users')
|
|
740
|
+
.values({ name: 'John Doe', email: 'john@example.com' })
|
|
741
|
+
.run();
|
|
742
|
+
|
|
743
|
+
await ctx
|
|
744
|
+
.insert('posts')
|
|
745
|
+
.values({
|
|
746
|
+
userId: newUser.id,
|
|
747
|
+
title: 'My First Post',
|
|
748
|
+
content: 'Hello World!',
|
|
749
|
+
})
|
|
750
|
+
.run();
|
|
751
|
+
});
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
#### Transaction with Multiple Operations
|
|
755
|
+
|
|
756
|
+
```typescript
|
|
757
|
+
// Transfer data between tables atomically
|
|
758
|
+
await db.transaction(['users', 'posts', 'comments'], async (ctx) => {
|
|
759
|
+
// Update user
|
|
760
|
+
await ctx
|
|
761
|
+
.update('users')
|
|
762
|
+
.set({ isActive: true })
|
|
763
|
+
.where((user) => user.id === 1)
|
|
764
|
+
.run();
|
|
765
|
+
|
|
766
|
+
// Create post
|
|
767
|
+
const post = await ctx
|
|
768
|
+
.insert('posts')
|
|
769
|
+
.values({ userId: 1, title: 'New Post', content: 'Content' })
|
|
770
|
+
.run();
|
|
771
|
+
|
|
772
|
+
// Add comment
|
|
773
|
+
await ctx
|
|
774
|
+
.insert('comments')
|
|
775
|
+
.values({ postId: post.id, userId: 1, text: 'First comment!' })
|
|
776
|
+
.run();
|
|
777
|
+
|
|
778
|
+
// Query within transaction
|
|
779
|
+
const userPosts = await ctx
|
|
780
|
+
.from('posts')
|
|
781
|
+
.where((p) => p.userId === 1)
|
|
782
|
+
.findAll();
|
|
783
|
+
|
|
784
|
+
console.log(`User now has ${userPosts.length} posts`);
|
|
785
|
+
});
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
#### Automatic Rollback
|
|
789
|
+
|
|
790
|
+
```typescript
|
|
791
|
+
try {
|
|
792
|
+
await db.transaction(['users', 'posts'], async (ctx) => {
|
|
793
|
+
const user = await ctx
|
|
794
|
+
.insert('users')
|
|
795
|
+
.values({ name: 'Alice', email: 'alice@example.com' })
|
|
796
|
+
.run();
|
|
797
|
+
|
|
798
|
+
// This will cause the entire transaction to rollback
|
|
799
|
+
throw new Error('Something went wrong!');
|
|
800
|
+
|
|
801
|
+
// This never executes
|
|
802
|
+
await ctx
|
|
803
|
+
.insert('posts')
|
|
804
|
+
.values({ userId: user.id, title: 'Post' })
|
|
805
|
+
.run();
|
|
806
|
+
});
|
|
807
|
+
} catch (error) {
|
|
808
|
+
console.error('Transaction failed:', error);
|
|
809
|
+
// No data was inserted - transaction was rolled back
|
|
810
|
+
}
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
> **Note:**
|
|
814
|
+
>
|
|
815
|
+
> - Transactions guarantee atomicity: all operations succeed or all fail.
|
|
816
|
+
> - If any operation fails or an error is thrown, the entire transaction is automatically rolled back.
|
|
817
|
+
> - Transaction context (`ctx`) provides `insert()`, `update()`, `delete()`, and `from()` methods.
|
|
818
|
+
> - All operations must be performed on tables specified in the transaction.
|
|
819
|
+
|
|
820
|
+
### Export Database
|
|
821
|
+
|
|
822
|
+
Export your database data as JSON for backup, migration, or debugging purposes. The export includes metadata and table data, and automatically triggers a browser download.
|
|
823
|
+
|
|
824
|
+
#### Export All Tables
|
|
825
|
+
|
|
826
|
+
```typescript
|
|
827
|
+
// Export entire database with pretty-printed JSON
|
|
828
|
+
await db.export();
|
|
829
|
+
// Downloads: my-database-2026-02-04T10-30-45-123Z.json
|
|
830
|
+
```
|
|
831
|
+
|
|
832
|
+
#### Export Specific Tables
|
|
833
|
+
|
|
834
|
+
```typescript
|
|
835
|
+
// Export only users and posts tables
|
|
836
|
+
await db.export({
|
|
837
|
+
tables: ['users', 'posts'],
|
|
838
|
+
filename: 'users-posts-backup.json',
|
|
839
|
+
});
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
#### Export with Custom Options
|
|
843
|
+
|
|
844
|
+
```typescript
|
|
845
|
+
// Export with custom configuration
|
|
846
|
+
await db.export({
|
|
847
|
+
tables: ['users'], // Optional: specific tables
|
|
848
|
+
filename: 'users-export.json', // Optional: custom filename
|
|
849
|
+
pretty: false, // Optional: compact JSON (default: true)
|
|
850
|
+
includeMetadata: true, // Optional: include metadata (default: true)
|
|
851
|
+
});
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
#### Export Data Structure
|
|
855
|
+
|
|
856
|
+
The exported JSON file contains:
|
|
857
|
+
|
|
858
|
+
```json
|
|
859
|
+
{
|
|
860
|
+
"metadata": {
|
|
861
|
+
"dbName": "my-database",
|
|
862
|
+
"version": 1,
|
|
863
|
+
"exportedAt": "2026-02-04T10:30:45.123Z",
|
|
864
|
+
"tables": ["users", "posts"]
|
|
865
|
+
},
|
|
866
|
+
"data": {
|
|
867
|
+
"users": [
|
|
868
|
+
{ "id": 1, "name": "Alice", "email": "alice@example.com" },
|
|
869
|
+
{ "id": 2, "name": "Bob", "email": "bob@example.com" }
|
|
870
|
+
],
|
|
871
|
+
"posts": [
|
|
872
|
+
{ "id": 1, "userId": 1, "title": "First Post", "content": "..." }
|
|
873
|
+
]
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
> **Note:**
|
|
879
|
+
>
|
|
880
|
+
> - Exported files are automatically downloaded in the browser.
|
|
881
|
+
> - Default filename format: `{dbName}-{timestamp}.json`
|
|
882
|
+
> - Metadata is included by default but can be disabled.
|
|
883
|
+
> - Use `pretty: true` (default) for human-readable JSON.
|
|
884
|
+
> - Use `pretty: false` for compact JSON (smaller file size).
|
|
885
|
+
|
|
691
886
|
---
|
|
692
887
|
|
|
693
888
|
## 📚 API Reference
|
|
@@ -716,6 +911,58 @@ const db = new Locality({
|
|
|
716
911
|
});
|
|
717
912
|
```
|
|
718
913
|
|
|
914
|
+
#### Properties
|
|
915
|
+
|
|
916
|
+
##### `version: number` (getter)
|
|
917
|
+
|
|
918
|
+
Gets the current database version.
|
|
919
|
+
|
|
920
|
+
**Returns:** The database version number
|
|
921
|
+
|
|
922
|
+
**Example:**
|
|
923
|
+
|
|
924
|
+
```typescript
|
|
925
|
+
const db = new Locality({
|
|
926
|
+
dbName: 'my-database',
|
|
927
|
+
version: 2,
|
|
928
|
+
schema: mySchema,
|
|
929
|
+
});
|
|
930
|
+
|
|
931
|
+
await db.ready(); // (optional) for extra safety
|
|
932
|
+
console.log(db.version); // 2
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
##### `tableList: string[]` (getter)
|
|
936
|
+
|
|
937
|
+
Gets all table (store) names in the current database.
|
|
938
|
+
|
|
939
|
+
**Returns:** Array of table names
|
|
940
|
+
|
|
941
|
+
**Example:**
|
|
942
|
+
|
|
943
|
+
```typescript
|
|
944
|
+
const tables = db.tableList;
|
|
945
|
+
console.log(tables); // ['users', 'posts', 'comments']
|
|
946
|
+
```
|
|
947
|
+
|
|
948
|
+
##### `dbList: Promise<IDBDatabaseInfo[]>` (getter)
|
|
949
|
+
|
|
950
|
+
Gets the list of all existing IndexedDB databases in the current origin.
|
|
951
|
+
|
|
952
|
+
**Returns:** Array of database information objects containing name and version
|
|
953
|
+
|
|
954
|
+
**Example:**
|
|
955
|
+
|
|
956
|
+
```typescript
|
|
957
|
+
const databases = await db.dbList;
|
|
958
|
+
console.log(databases);
|
|
959
|
+
// [{ name: 'my-database', version: 1 }, { name: 'other-db', version: 2 }]
|
|
960
|
+
```
|
|
961
|
+
|
|
962
|
+
> This is an instance method that calls the static [`Locality.getDatabaseList()`](#localitygetdatabaselist-promiseidbdatabaseinfo) internally.
|
|
963
|
+
|
|
964
|
+
---
|
|
965
|
+
|
|
719
966
|
#### Methods
|
|
720
967
|
|
|
721
968
|
##### `ready(): Promise<void>`
|
|
@@ -827,6 +1074,162 @@ const allUsers = await db.from('users').findAll();
|
|
|
827
1074
|
console.log(allUsers);
|
|
828
1075
|
```
|
|
829
1076
|
|
|
1077
|
+
#### `transaction<Tables>(tables: Tables[], callback: TransactionCallback): Promise<void>`
|
|
1078
|
+
|
|
1079
|
+
Executes multiple database operations across multiple tables in a single atomic transaction.
|
|
1080
|
+
|
|
1081
|
+
**Parameters:**
|
|
1082
|
+
|
|
1083
|
+
- `tables`: Array of table names to include in the transaction
|
|
1084
|
+
- `callback`: Async function that receives a transaction context and performs operations
|
|
1085
|
+
|
|
1086
|
+
**Returns:** Promise that resolves when the transaction completes successfully
|
|
1087
|
+
|
|
1088
|
+
**Transaction Context Methods:**
|
|
1089
|
+
|
|
1090
|
+
- `ctx.insert(table)`: Insert records within the transaction
|
|
1091
|
+
- `ctx.update(table)`: Update records within the transaction
|
|
1092
|
+
- `ctx.delete(table)`: Delete records within the transaction
|
|
1093
|
+
- `ctx.from(table)`: Query records within the transaction
|
|
1094
|
+
|
|
1095
|
+
**Example:**
|
|
1096
|
+
|
|
1097
|
+
```typescript
|
|
1098
|
+
// Create user and post atomically
|
|
1099
|
+
await db.transaction(['users', 'posts'], async (ctx) => {
|
|
1100
|
+
const user = await ctx
|
|
1101
|
+
.insert('users')
|
|
1102
|
+
.values({ name: 'Alice', email: 'alice@example.com' })
|
|
1103
|
+
.run();
|
|
1104
|
+
|
|
1105
|
+
await ctx
|
|
1106
|
+
.insert('posts')
|
|
1107
|
+
.values({ userId: user.id, title: 'First Post', content: 'Hello!' })
|
|
1108
|
+
.run();
|
|
1109
|
+
});
|
|
1110
|
+
```
|
|
1111
|
+
|
|
1112
|
+
> **Important:**
|
|
1113
|
+
>
|
|
1114
|
+
> - All operations succeed or all fail (atomicity).
|
|
1115
|
+
> - If any operation fails or an error is thrown, the entire transaction is rolled back.
|
|
1116
|
+
> - Only tables specified in the `tables` array can be accessed within the transaction.
|
|
1117
|
+
> - Transactions use IndexedDB's native transaction mechanism.
|
|
1118
|
+
|
|
1119
|
+
#### `export(options?: ExportOptions): Promise<void>`
|
|
1120
|
+
|
|
1121
|
+
Exports database data as a JSON file and triggers a browser download.
|
|
1122
|
+
|
|
1123
|
+
**Parameters:**
|
|
1124
|
+
|
|
1125
|
+
- `options`: Optional export configuration
|
|
1126
|
+
- `options.tables`: Array of table names to export (default: all tables)
|
|
1127
|
+
- `options.filename`: Custom filename (default: `{dbName}-{timestamp}.json`)
|
|
1128
|
+
- `options.pretty`: Enable pretty-printed JSON (default: `true`)
|
|
1129
|
+
- `options.includeMetadata`: Include export metadata (default: `true`)
|
|
1130
|
+
|
|
1131
|
+
**Returns:** Promise that resolves when the export completes
|
|
1132
|
+
|
|
1133
|
+
**Example:**
|
|
1134
|
+
|
|
1135
|
+
```typescript
|
|
1136
|
+
// Export all tables with default settings
|
|
1137
|
+
await db.export();
|
|
1138
|
+
|
|
1139
|
+
// Export specific tables with custom filename
|
|
1140
|
+
await db.export({
|
|
1141
|
+
tables: ['users', 'posts'],
|
|
1142
|
+
filename: 'backup-2026-02-04.json',
|
|
1143
|
+
pretty: true,
|
|
1144
|
+
});
|
|
1145
|
+
|
|
1146
|
+
// Export without metadata in compact format
|
|
1147
|
+
await db.export({
|
|
1148
|
+
pretty: false,
|
|
1149
|
+
includeMetadata: false,
|
|
1150
|
+
});
|
|
1151
|
+
```
|
|
1152
|
+
|
|
1153
|
+
**Exported JSON Structure:**
|
|
1154
|
+
|
|
1155
|
+
```typescript
|
|
1156
|
+
{
|
|
1157
|
+
metadata?: { // Optional (when includeMetadata = true)
|
|
1158
|
+
dbName: string;
|
|
1159
|
+
version: number;
|
|
1160
|
+
exportedAt: string; // ISO 8601 timestamp
|
|
1161
|
+
tables: string[];
|
|
1162
|
+
};
|
|
1163
|
+
data: {
|
|
1164
|
+
[tableName: string]: Array<Record<string, any>>;
|
|
1165
|
+
};
|
|
1166
|
+
}
|
|
1167
|
+
```
|
|
1168
|
+
|
|
1169
|
+
> **Note:**
|
|
1170
|
+
>
|
|
1171
|
+
> - Automatically triggers a file download in the browser.
|
|
1172
|
+
> - Exported data includes all records from specified tables.
|
|
1173
|
+
> - Use for backup, debugging, or data migration.
|
|
1174
|
+
> - File download works in browser environments only.
|
|
1175
|
+
|
|
1176
|
+
---
|
|
1177
|
+
|
|
1178
|
+
#### Static Methods
|
|
1179
|
+
|
|
1180
|
+
##### `Locality.getDatabaseList(): Promise<IDBDatabaseInfo[]>`
|
|
1181
|
+
|
|
1182
|
+
Gets the list of all existing IndexedDB databases in the current origin (static method).
|
|
1183
|
+
|
|
1184
|
+
**Returns:** Array of database information objects containing name and version
|
|
1185
|
+
|
|
1186
|
+
**Example:**
|
|
1187
|
+
|
|
1188
|
+
```typescript
|
|
1189
|
+
import { Locality } from 'locality-idb';
|
|
1190
|
+
|
|
1191
|
+
const databases = await Locality.getDatabaseList();
|
|
1192
|
+
console.log(databases);
|
|
1193
|
+
// [{ name: 'app-db', version: 1 }, { name: 'cache-db', version: 2 }]
|
|
1194
|
+
```
|
|
1195
|
+
|
|
1196
|
+
> **Note:**
|
|
1197
|
+
>
|
|
1198
|
+
> - This method requires IndexedDB support in the browser.
|
|
1199
|
+
> - Returns an empty array if the browser doesn't support `indexedDB.databases()`.
|
|
1200
|
+
> - Can be called without instantiating the Locality class.
|
|
1201
|
+
|
|
1202
|
+
##### `Locality.deleteDatabase(name: string): Promise<void>`
|
|
1203
|
+
|
|
1204
|
+
Deletes an IndexedDB database by name (static method).
|
|
1205
|
+
|
|
1206
|
+
**Parameters:**
|
|
1207
|
+
|
|
1208
|
+
- `name`: The name of the database to delete
|
|
1209
|
+
|
|
1210
|
+
**Returns:** Promise that resolves when the database is deleted
|
|
1211
|
+
|
|
1212
|
+
**Example:**
|
|
1213
|
+
|
|
1214
|
+
```typescript
|
|
1215
|
+
import { Locality } from 'locality-idb';
|
|
1216
|
+
|
|
1217
|
+
// Delete a database without creating an instance
|
|
1218
|
+
await Locality.deleteDatabase('old-database');
|
|
1219
|
+
|
|
1220
|
+
// Alternative: Get list of databases first
|
|
1221
|
+
const databases = await Locality.getDatabaseList();
|
|
1222
|
+
for (const db of databases) {
|
|
1223
|
+
if (db.name.startsWith('temp-')) {
|
|
1224
|
+
await Locality.deleteDatabase(db.name);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
```
|
|
1228
|
+
|
|
1229
|
+
> **Warning:** This will permanently remove all data from the specified database and cannot be undone.
|
|
1230
|
+
>
|
|
1231
|
+
> **Note:** This is a static method that can be called without creating a Locality instance. For deleting the current database instance, use the instance method `db.deleteDB()` instead.
|
|
1232
|
+
|
|
830
1233
|
---
|
|
831
1234
|
|
|
832
1235
|
### Schema Functions
|
|
@@ -1028,6 +1431,40 @@ const emailColumn = column.text().validate((val) => { /* ... */ });
|
|
|
1028
1431
|
const validatorFn = emailColumn[ValidateFn]; // Function reference
|
|
1029
1432
|
```
|
|
1030
1433
|
|
|
1434
|
+
#### `onUpdate<T>(updater: (currentValue: T) => T): Column`
|
|
1435
|
+
|
|
1436
|
+
Sets a function to auto-update the column value during update operations.
|
|
1437
|
+
|
|
1438
|
+
```typescript
|
|
1439
|
+
const schema = defineSchema({
|
|
1440
|
+
users: {
|
|
1441
|
+
id: column.int().pk().auto(),
|
|
1442
|
+
name: column.text(),
|
|
1443
|
+
updatedAt: column.timestamp().onUpdate(() => getTimestamp()),
|
|
1444
|
+
},
|
|
1445
|
+
});
|
|
1446
|
+
```
|
|
1447
|
+
|
|
1448
|
+
> **Note:**
|
|
1449
|
+
>
|
|
1450
|
+
> - The updater function is called automatically during update operations.
|
|
1451
|
+
> - **Important**: It overrides any value provided during updates.
|
|
1452
|
+
> - It receives the current value of the column and should return the updated value.
|
|
1453
|
+
> - This is useful for fields like `"updatedAt"` timestamps that need to be refreshed on each update.
|
|
1454
|
+
> - If multiple updaters are chained, only the last one is used.
|
|
1455
|
+
> - Should not be used with auto-generated indexed columns like primary keys.
|
|
1456
|
+
> - The updated value is validated according to the column's type and custom validators (if any).
|
|
1457
|
+
|
|
1458
|
+
**Access the `OnUpdate` symbol (advanced):**
|
|
1459
|
+
|
|
1460
|
+
```typescript
|
|
1461
|
+
import { OnUpdate } from 'locality-idb';
|
|
1462
|
+
|
|
1463
|
+
// Access updater function programmatically
|
|
1464
|
+
const updatedAtColumn = column.timestamp().onUpdate(() => getTimestamp());
|
|
1465
|
+
const updaterFn = updatedAtColumn[OnUpdate]; // Function reference
|
|
1466
|
+
```
|
|
1467
|
+
|
|
1031
1468
|
---
|
|
1032
1469
|
|
|
1033
1470
|
### Query Methods
|
|
@@ -1329,6 +1766,86 @@ isTimestamp('invalid'); // false
|
|
|
1329
1766
|
isTimestamp(123); // false
|
|
1330
1767
|
```
|
|
1331
1768
|
|
|
1769
|
+
#### `isUUID(value: unknown): value is UUID<UUIDVersion>`
|
|
1770
|
+
|
|
1771
|
+
Checks if a value is a valid UUID string (v1, v4, or v5).
|
|
1772
|
+
|
|
1773
|
+
**Parameters:**
|
|
1774
|
+
|
|
1775
|
+
- `value`: The value to check
|
|
1776
|
+
|
|
1777
|
+
**Returns:** `true` if the value is a valid UUID, otherwise `false`
|
|
1778
|
+
|
|
1779
|
+
**Example:**
|
|
1780
|
+
|
|
1781
|
+
```typescript
|
|
1782
|
+
import { isUUID } from 'locality-idb';
|
|
1783
|
+
|
|
1784
|
+
// Valid UUIDs
|
|
1785
|
+
isUUID('d9428888-122b-11e8-b642-0ed5f89f718b'); // true (v1)
|
|
1786
|
+
isUUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8'); // true (v1)
|
|
1787
|
+
isUUID('550e8400-e29b-41d4-a716-446655440000'); // true (v4)
|
|
1788
|
+
|
|
1789
|
+
// Invalid formats
|
|
1790
|
+
isUUID('not-a-uuid'); // false
|
|
1791
|
+
isUUID('12345678-1234-1234-1234-123456789abc'); // false (invalid version)
|
|
1792
|
+
isUUID(123456789); // false
|
|
1793
|
+
```
|
|
1794
|
+
|
|
1795
|
+
#### `isEmail(value: unknown): value is EmailString`
|
|
1796
|
+
|
|
1797
|
+
Checks if a value is a valid email string.
|
|
1798
|
+
|
|
1799
|
+
**Parameters:**
|
|
1800
|
+
|
|
1801
|
+
- `value`: The value to check
|
|
1802
|
+
|
|
1803
|
+
**Returns:** `true` if the value is a valid email, otherwise `false`
|
|
1804
|
+
|
|
1805
|
+
**Example:**
|
|
1806
|
+
|
|
1807
|
+
```typescript
|
|
1808
|
+
import { isEmail } from 'locality-idb';
|
|
1809
|
+
|
|
1810
|
+
// Valid emails
|
|
1811
|
+
isEmail('user@example.com'); // true
|
|
1812
|
+
isEmail('first.last@sub.domain.co.uk'); // true
|
|
1813
|
+
isEmail('user+filter@example.org'); // true
|
|
1814
|
+
|
|
1815
|
+
// Invalid emails
|
|
1816
|
+
isEmail('plain-string'); // false
|
|
1817
|
+
isEmail('user@.com'); // false
|
|
1818
|
+
isEmail('@example.com'); // false
|
|
1819
|
+
isEmail('user@domain'); // false
|
|
1820
|
+
isEmail(12345); // false
|
|
1821
|
+
```
|
|
1822
|
+
|
|
1823
|
+
#### `isURL(value: unknown): value is URLString`
|
|
1824
|
+
|
|
1825
|
+
Checks if a value is a valid URL string.
|
|
1826
|
+
|
|
1827
|
+
**Parameters:**
|
|
1828
|
+
|
|
1829
|
+
- `value`: The value to check
|
|
1830
|
+
|
|
1831
|
+
**Returns:** `true` if the value is a valid URL, otherwise `false`
|
|
1832
|
+
|
|
1833
|
+
**Example:**
|
|
1834
|
+
|
|
1835
|
+
```typescript
|
|
1836
|
+
import { isURL } from 'locality-idb';
|
|
1837
|
+
|
|
1838
|
+
// Valid URLs
|
|
1839
|
+
isURL('https://example.com'); // true
|
|
1840
|
+
isURL('ftp://files.test/path?q=1'); // true
|
|
1841
|
+
|
|
1842
|
+
// Invalid URLs
|
|
1843
|
+
isURL('example.com'); // false (missing protocol)
|
|
1844
|
+
isURL('http://'); // false (empty domain)
|
|
1845
|
+
isURL('//cdn.domain/image.png'); // false (`URL` constructor cannot parse it)
|
|
1846
|
+
isURL(123456); // false
|
|
1847
|
+
```
|
|
1848
|
+
|
|
1332
1849
|
#### `openDBWithStores(name: string, stores: StoreConfig[], version?: number): Promise<IDBDatabase>`
|
|
1333
1850
|
|
|
1334
1851
|
Opens an IndexedDB database with specified stores (low-level API).
|
|
@@ -1339,7 +1856,7 @@ Opens an IndexedDB database with specified stores (low-level API).
|
|
|
1339
1856
|
|
|
1340
1857
|
- `name`: Database name
|
|
1341
1858
|
- `stores`: Array of store configurations
|
|
1342
|
-
- `version`: Database version (optional, default:
|
|
1859
|
+
- `version`: Database version (optional, default: `undefined`)
|
|
1343
1860
|
|
|
1344
1861
|
**Returns:** Promise resolving to `IDBDatabase` instance
|
|
1345
1862
|
|
|
@@ -1530,6 +2047,48 @@ type Selected = SelectFields<User, { name: true; email: true }>;
|
|
|
1530
2047
|
// { name: string; email: string }
|
|
1531
2048
|
```
|
|
1532
2049
|
|
|
2050
|
+
### Transaction & Export Types
|
|
2051
|
+
|
|
2052
|
+
```typescript
|
|
2053
|
+
import type {
|
|
2054
|
+
TransactionContext,
|
|
2055
|
+
TransactionCallback,
|
|
2056
|
+
ExportOptions,
|
|
2057
|
+
ExportData,
|
|
2058
|
+
} from 'locality-idb';
|
|
2059
|
+
|
|
2060
|
+
// TransactionContext: Context object provided to transaction callback
|
|
2061
|
+
type TxContext = TransactionContext<Schema, TableName, ['users', 'posts']>;
|
|
2062
|
+
|
|
2063
|
+
// TransactionCallback: Function signature for transaction operations
|
|
2064
|
+
type TxCallback = TransactionCallback<Schema, TableName, ['users']>;
|
|
2065
|
+
|
|
2066
|
+
// ExportOptions: Configuration options for database export
|
|
2067
|
+
type ExportOpts = ExportOptions<'users' | 'posts'>;
|
|
2068
|
+
/*
|
|
2069
|
+
{
|
|
2070
|
+
tables?: ('users' | 'posts')[];
|
|
2071
|
+
filename?: string;
|
|
2072
|
+
pretty?: boolean;
|
|
2073
|
+
includeMetadata?: boolean;
|
|
2074
|
+
}
|
|
2075
|
+
*/
|
|
2076
|
+
|
|
2077
|
+
// ExportData: Structure of exported database data
|
|
2078
|
+
type Exported = ExportData;
|
|
2079
|
+
/*
|
|
2080
|
+
{
|
|
2081
|
+
metadata?: {
|
|
2082
|
+
dbName: string;
|
|
2083
|
+
version: number;
|
|
2084
|
+
exportedAt: Timestamp;
|
|
2085
|
+
tables: string[];
|
|
2086
|
+
};
|
|
2087
|
+
data: Record<string, GenericObject[]>;
|
|
2088
|
+
}
|
|
2089
|
+
*/
|
|
2090
|
+
```
|
|
2091
|
+
|
|
1533
2092
|
---
|
|
1534
2093
|
|
|
1535
2094
|
## 📄 License
|