locality-idb 0.6.0 → 0.6.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 CHANGED
@@ -11,9 +11,9 @@
11
11
  ![license](https://img.shields.io/npm/l/locality-idb)
12
12
  ![beta](https://img.shields.io/badge/status-beta-orange)
13
13
  <!-- ![bundle](https://img.shields.io/bundlephobia/minzip/locality-idb) -->
14
- ![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue)
14
+ <!-- ![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue) -->
15
15
 
16
- [Documentation](#-api-reference) • [Examples](#-usage) • [Contributing](#-contributing)
16
+ [API Reference](#-api-reference) • [Examples](#-usage) • [Contributing](#-contributing)
17
17
 
18
18
  </div>
19
19
 
@@ -46,6 +46,7 @@
46
46
  - [Column Modifiers](#column-modifiers)
47
47
  - [Query Methods](#query-methods)
48
48
  - [Utility Functions](#utility-functions)
49
+ - [Validation](#validation)
49
50
  - [Type System](#-type-system)
50
51
  - [Contributing](#-contributing)
51
52
  - [License](#-license)
@@ -62,6 +63,7 @@
62
63
  - 🎨 **Schema-First**: Define your database schema with a simple, declarative API
63
64
  - ⚡ **Promise-Based**: Fully async/await compatible
64
65
  - 🛠️ **Rich Column Types**: Support for various data types including custom types
66
+ - ✅ **Built-in Validation**: Automatic data type validation for built-in column types during insert and update operations
65
67
 
66
68
  ---
67
69
 
@@ -166,24 +168,26 @@ const schema = defineSchema({
166
168
 
167
169
  Locality IDB supports a wide range of column types:
168
170
 
169
- | Type | Description | Example |
170
- | -------------------------------- | ------------------------------------ | ---------------------------------- |
171
- | `int()` / `number()` / `float()` | Numeric values | `column.int()` |
172
- | `bigint()` | Large integers | `column.bigint()` |
173
- | `text()` / `string()` | Text strings | `column.text()` |
174
- | `char(length?)` | Fixed-length string | `column.char(10)` |
175
- | `varchar(length?)` | Variable-length string | `column.varchar(255)` |
176
- | `bool()` | Boolean values | `column.bool()` |
177
- | `date()` | Date objects | `column.date()` |
178
- | `timestamp()` | ISO 8601 timestamps (auto-generated) | `column.timestamp()` |
179
- | `uuid()` | UUID strings (auto-generated v4) | `column.uuid()` |
180
- | `object<T>()` | Generic objects | `column.object<UserData>()` |
181
- | `array<T>()` | Arrays | `column.array<number>()` |
182
- | `list<T>()` | Read-only arrays | `column.list<string>()` |
183
- | `tuple<T>()` | Fixed-size tuples | `column.tuple<[string, number]>()` |
184
- | `set<T>()` | Sets | `column.set<string>()` |
185
- | `map<K,V>()` | Maps | `column.map<string, number>()` |
186
- | `custom<T>()` | Custom types | `column.custom<MyType>()` |
171
+ | Type | Description | Example |
172
+ | ---------------------- | ---------------------------------------------------------- | ---------------------------------- |
173
+ | `number()` / `float()` | Numeric values (integer or float) | `column.int()` |
174
+ | `int()` | Numeric values (only integer is allowed) | `column.int()` |
175
+ | `numeric()` | Number or numeric string | `column.numeric()` |
176
+ | `bigint()` | Large integers | `column.bigint()` |
177
+ | `text()` / `string()` | Text strings | `column.text()` |
178
+ | `char(length?)` | Fixed-length string | `column.char(10)` |
179
+ | `varchar(length?)` | Variable-length string | `column.varchar(255)` |
180
+ | `bool()` / `boolean()` | Boolean values | `column.bool()` |
181
+ | `date()` | Date objects | `column.date()` |
182
+ | `timestamp()` | ISO 8601 timestamps ([auto-generated](#utility-functions)) | `column.timestamp()` |
183
+ | `uuid()` | UUID strings ([auto-generated](#utility-functions) v4) | `column.uuid()` |
184
+ | `object<T>()` | Generic objects | `column.object<UserData>()` |
185
+ | `array<T>()` | Arrays | `column.array<number>()` |
186
+ | `list<T>()` | Read-only arrays | `column.list<string>()` |
187
+ | `tuple<T>()` | Fixed-size tuples | `column.tuple<[string, number]>()` |
188
+ | `set<T>()` | Sets | `column.set<string>()` |
189
+ | `map<K,V>()` | Maps | `column.map<string, number>()` |
190
+ | `custom<T>()` | Custom types | `column.custom<MyType>()` |
187
191
 
188
192
  ### Type Inference
189
193
 
@@ -779,6 +783,27 @@ const fromUnix = getTimestamp(1704067200000); // "2024-01-01T00:00:00.000Z"
779
783
  const fallback = getTimestamp('invalid'); // Current timestamp
780
784
  ```
781
785
 
786
+ #### `isTimestamp(value: unknown): value is Timestamp`
787
+
788
+ Checks if a value is a valid Timestamp string in ISO 8601 format.
789
+
790
+ **Parameters:**
791
+
792
+ - `value`: The value to check
793
+
794
+ **Returns:** `true` if the value is a valid Timestamp, otherwise `false`
795
+
796
+ **Example:**
797
+
798
+ ```typescript
799
+ import { isTimestamp } from 'locality-idb';
800
+
801
+ isTimestamp('2026-01-29T12:34:56.789Z'); // true
802
+ isTimestamp('2026-01-29'); // false (not full ISO 8601)
803
+ isTimestamp('invalid'); // false
804
+ isTimestamp(123); // false
805
+ ```
806
+
782
807
  #### `openDBWithStores(name: string, stores: StoreConfig[], version?: number): Promise<IDBDatabase>`
783
808
 
784
809
  Opens an IndexedDB database with specified stores (low-level API).
@@ -813,6 +838,88 @@ const db = await openDBWithStores(
813
838
 
814
839
  ---
815
840
 
841
+ ### Validation
842
+
843
+ Locality IDB includes built-in validation that automatically validates data types for built-in column types during insert and update operations based on your schema definitions.
844
+
845
+ #### Automatic Validation
846
+
847
+ When you insert or update records, Locality IDB automatically validates that the values match their expected column types:
848
+
849
+ ```typescript
850
+ const schema = defineSchema({
851
+ users: {
852
+ id: column.int().pk().auto(),
853
+ name: column.text(),
854
+ age: column.int(),
855
+ email: column.varchar(255),
856
+ },
857
+ });
858
+
859
+ const db = new Locality({ dbName: 'app', schema });
860
+
861
+ // ✅ Valid - all types match
862
+ await db.insert('users').values({ name: 'Alice', age: 25, email: 'alice@example.com' }).run();
863
+
864
+ // ❌ Throws TypeError - age must be an integer
865
+ await db.insert('users').values({ name: 'Bob', age: 'twenty', email: 'bob@example.com' }).run();
866
+
867
+ // ❌ Throws TypeError - email exceeds varchar(255) length
868
+ await db.insert('users').values({ name: 'Charlie', age: 30, email: 'a'.repeat(300) }).run();
869
+ ```
870
+
871
+ #### `validateColumnType<T>(type: T, value: unknown): string | null`
872
+
873
+ Manually validate if a value matches the specified column data type.
874
+
875
+ **Parameters:**
876
+
877
+ - `type`: The column data type (e.g., `'int'`, `'text'`, `'uuid'`, `'varchar(255)'`)
878
+ - `value`: The value to validate
879
+
880
+ **Returns:** `null` if valid, otherwise an error message string
881
+
882
+ **Example:**
883
+
884
+ ```typescript
885
+ import { validateColumnType } from 'locality-idb';
886
+
887
+ validateColumnType('int', 42); // null (valid)
888
+ validateColumnType('int', 'hello'); // "'\"hello\"' is not an integer"
889
+ validateColumnType('text', 'hello'); // null (valid)
890
+ validateColumnType('uuid', '550e8400-e29b-41d4-a716-446655440000'); // null (valid)
891
+ validateColumnType('varchar(5)', 'hi'); // null (valid)
892
+ validateColumnType('varchar(5)', 'hello world'); // error message
893
+ validateColumnType('numeric', 42); // null (valid)
894
+ validateColumnType('numeric', '3.14'); // null (valid)
895
+ validateColumnType('numeric', 'abc'); // error message
896
+ ```
897
+
898
+ #### Validated Column Types
899
+
900
+ The following column types are validated:
901
+
902
+ | Type | Validation Rule |
903
+ | -------------------------- | --------------------------------------------------------------------------- |
904
+ | `int` | Must be an integer |
905
+ | `float` / `number` | Must be a number |
906
+ | `numeric` | Must be a number or numeric string |
907
+ | `bigint` | Must be a BigInt |
908
+ | `text` / `string` | Must be a string |
909
+ | `char(n)` | Must be a string with exactly `n` characters |
910
+ | `varchar(n)` | Must be a string with at most `n` characters |
911
+ | `bool` / `boolean` | Must be a boolean |
912
+ | `uuid` | Must be a valid UUID string |
913
+ | `timestamp` | Must be a valid ISO 8601 timestamp string |
914
+ | `date` | Must be a Date object |
915
+ | `array` / `list` / `tuple` | Must be an array |
916
+ | `set` | Must be a Set |
917
+ | `map` | Must be a Map |
918
+ | `object` | Must be an object |
919
+ | `custom` | No validation (always passes, custom validation integration coming soon...) |
920
+
921
+ ---
922
+
816
923
  ## 🔧 Type System
817
924
 
818
925
  Locality IDB provides comprehensive TypeScript support:
package/dist/index.cjs CHANGED
@@ -870,6 +870,7 @@ const column = {
870
870
  uuid: () => new Column("uuid"),
871
871
  timestamp: () => new Column("timestamp"),
872
872
  bool: () => new Column("bool"),
873
+ boolean: () => new Column("boolean"),
873
874
  date: () => new Column("date"),
874
875
  object: () => new Column(`object`),
875
876
  array: () => new Column(`array`),
package/dist/index.d.cts CHANGED
@@ -312,7 +312,7 @@ type InferUpdateType<T extends Table> = Prettify<Partial<Omit<$InferRow<T['colum
312
312
  /** Creates a type for select operations. */
313
313
  type InferSelectType<S extends Table> = Prettify<S extends infer T ? T extends Table<infer C> ? $InferRow<C> : never : never>;
314
314
  /** Column type strings used in {@link Column} definitions */
315
- type TypeName = LooseLiteral<'int' | 'float' | 'number' | 'numeric' | 'bigint' | 'text' | 'string' | 'uuid' | 'timestamp' | 'bool' | 'date' | 'object' | 'array' | 'list' | 'tuple' | 'set' | 'map' | 'custom'>;
315
+ type TypeName<L extends number = number> = LooseLiteral<'int' | 'float' | 'number' | 'numeric' | 'bigint' | 'text' | 'string' | `char(${L})` | `varchar(${L})` | 'uuid' | 'timestamp' | 'bool' | 'boolean' | 'date' | 'object' | 'array' | 'list' | 'tuple' | 'set' | 'map' | 'custom'>;
316
316
  /** Store configuration type for {@link IndexedDB} */
317
317
  type StoreConfig = {
318
318
  /** Store name */name: string; /** Primary key path(s) */
@@ -650,11 +650,17 @@ declare const column: {
650
650
  */
651
651
  readonly timestamp: () => Column<Timestamp, "timestamp">;
652
652
  /**
653
- * Creates a boolean column.
653
+ * Creates a boolean column. Same as {@link column.boolean boolean}.
654
654
  * @returns A new {@link Column} instance for booleans.
655
655
  * @remarks This column type is used for true/false values.
656
656
  */
657
657
  readonly bool: () => Column<boolean, "bool">;
658
+ /**
659
+ * Creates a boolean column. Same as {@link column.bool bool}.
660
+ * @returns A new {@link Column} instance for booleans.
661
+ * @remarks This column type is used for true/false values.
662
+ */
663
+ readonly boolean: () => Column<boolean, "boolean">;
658
664
  /**
659
665
  * Creates a date column.
660
666
  * @returns A new {@link Column} instance for dates.
package/dist/index.d.mts CHANGED
@@ -312,7 +312,7 @@ type InferUpdateType<T extends Table> = Prettify<Partial<Omit<$InferRow<T['colum
312
312
  /** Creates a type for select operations. */
313
313
  type InferSelectType<S extends Table> = Prettify<S extends infer T ? T extends Table<infer C> ? $InferRow<C> : never : never>;
314
314
  /** Column type strings used in {@link Column} definitions */
315
- type TypeName = LooseLiteral<'int' | 'float' | 'number' | 'numeric' | 'bigint' | 'text' | 'string' | 'uuid' | 'timestamp' | 'bool' | 'date' | 'object' | 'array' | 'list' | 'tuple' | 'set' | 'map' | 'custom'>;
315
+ type TypeName<L extends number = number> = LooseLiteral<'int' | 'float' | 'number' | 'numeric' | 'bigint' | 'text' | 'string' | `char(${L})` | `varchar(${L})` | 'uuid' | 'timestamp' | 'bool' | 'boolean' | 'date' | 'object' | 'array' | 'list' | 'tuple' | 'set' | 'map' | 'custom'>;
316
316
  /** Store configuration type for {@link IndexedDB} */
317
317
  type StoreConfig = {
318
318
  /** Store name */name: string; /** Primary key path(s) */
@@ -650,11 +650,17 @@ declare const column: {
650
650
  */
651
651
  readonly timestamp: () => Column<Timestamp, "timestamp">;
652
652
  /**
653
- * Creates a boolean column.
653
+ * Creates a boolean column. Same as {@link column.boolean boolean}.
654
654
  * @returns A new {@link Column} instance for booleans.
655
655
  * @remarks This column type is used for true/false values.
656
656
  */
657
657
  readonly bool: () => Column<boolean, "bool">;
658
+ /**
659
+ * Creates a boolean column. Same as {@link column.bool bool}.
660
+ * @returns A new {@link Column} instance for booleans.
661
+ * @remarks This column type is used for true/false values.
662
+ */
663
+ readonly boolean: () => Column<boolean, "boolean">;
658
664
  /**
659
665
  * Creates a date column.
660
666
  * @returns A new {@link Column} instance for dates.
@@ -872,6 +872,7 @@ var LocalityIDB = (function(exports) {
872
872
  uuid: () => new Column("uuid"),
873
873
  timestamp: () => new Column("timestamp"),
874
874
  bool: () => new Column("bool"),
875
+ boolean: () => new Column("boolean"),
875
876
  date: () => new Column("date"),
876
877
  object: () => new Column(`object`),
877
878
  array: () => new Column(`array`),
package/dist/index.mjs CHANGED
@@ -869,6 +869,7 @@ const column = {
869
869
  uuid: () => new Column("uuid"),
870
870
  timestamp: () => new Column("timestamp"),
871
871
  bool: () => new Column("bool"),
872
+ boolean: () => new Column("boolean"),
872
873
  date: () => new Column("date"),
873
874
  object: () => new Column(`object`),
874
875
  array: () => new Column(`array`),
package/dist/index.umd.js CHANGED
@@ -875,6 +875,7 @@
875
875
  uuid: () => new Column("uuid"),
876
876
  timestamp: () => new Column("timestamp"),
877
877
  bool: () => new Column("bool"),
878
+ boolean: () => new Column("boolean"),
878
879
  date: () => new Column("date"),
879
880
  object: () => new Column(`object`),
880
881
  array: () => new Column(`array`),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "locality-idb",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "SQL-like query builder for IndexedDB with Drizzle-style API",
5
5
  "type": "module",
6
6
  "sideEffects": false,