Skip to content

Commit

Permalink
Documentation for hSet() and hGet()
Browse files Browse the repository at this point in the history
  • Loading branch information
gerold-penz committed Aug 11, 2024
1 parent 5a24ec0 commit fda97d4
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 33 deletions.
90 changes: 90 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,96 @@ store.db.transaction(() => {
```


## Hash (Map Object) - Write Value
```typescript
hSet(key: string, field: string, value: any, ttlMs?: number)
```

First the
[JavaScript Map Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
is read from the database.
If the data record does not yet exist, a new "Map Object" is created.
Then the entry marked with `field` is added to the "Map Object" or overwritten.
Finally, the modified "Map Object" is written back to the database.
Inspired by: https://docs.keydb.dev/docs/commands/#hset


### key

The key must be a string.

### field

The field name must be a string.

### value

The value can be any object that can be serialized with
[v8](https://github.com/nodejs/node/blob/main/doc/api/v8.md#serialization-api).
This means that not only simple data types (string, number) are possible,
but also more complex types such as sets or maps.
You can find a list of the
[supported data types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#supported_types) here.

### ttlMs (optional)

"Time to live" in milliseconds (for the database line, marked with `key`).
After this time, the item becomes invalid and is deleted from the database
the next time it is accessed or when the application is started.
Set the value to 0 if you want to explicitly deactivate the process.

### Example

```typescript
import { BunSqliteKeyValue } from "bun-sqlite-key-value"
const store = new BunSqliteKeyValue()
store.hSet("key-1", "field-name-1", "field-value-1")
store.hSet("key-1", "field-name-2", "field-value-2")
store.get("key-1") // --> Map(2) {
"field-name-1": "field-value-1",
"field-name-2": "field-value-2",
}
```


## Hash (Map Object) - Read Value
```typescript
hGet(key: string, field: string)
```

First the
[JavaScript Map Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
is read from the database.
If the data record (marked with `key`) does not exist, `undefined` is returned.
If the field (marked with `field`) does not exist in the "Map Object", `undefined` is returned.
Inspired by: https://docs.keydb.dev/docs/commands/#hget


### key

The key must be a string.

### field

The field name must be a string.

### Example

```typescript
import { BunSqliteKeyValue } from "bun-sqlite-key-value"
const store = new BunSqliteKeyValue()
store.hSet("key-1", "field-name-1", "field-value-1")
store.hGet("key-1", "field-name-1") // --> "field-value-1"
store.hGet("key-1", "field-name-2") // --> undefined
```


## All Functions

### Database
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bun-sqlite-key-value",
"version": "1.9.5",
"version": "1.9.6",
"author": {
"name": "Gerold Penz",
"email": "[email protected]",
Expand Down
37 changes: 21 additions & 16 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ export class BunSqliteKeyValue {
// @ts-ignore (Transaction returns boolean, not void.)
return this.db.transaction(() => {
if (this.has(oldKey)) {
this.delete(newKey)
this.deleteStatement.run({key: newKey})
this.renameStatement.run({oldKey, newKey})
return true
} else {
Expand All @@ -615,44 +615,48 @@ export class BunSqliteKeyValue {
// Inspired by: https://docs.keydb.dev/docs/commands/#pttl


// Don't use it with large values or blobs.
// Do not use it with several large amounts of data or blobs.
// This is because the entire data record with all fields is always read and written.
// Inspired by: https://docs.keydb.dev/docs/commands/#hset
hSet<T = any>(key: string, field: string, value: T, ttlMs?: number): boolean {
// @ts-ignore (Transaction returns boolean, not void.)
return this.db.transaction(() => {
const internalValue = this.get<Map<string, T>>(key) ?? new Map<string, T>()
const isNewField: boolean = !internalValue.has(field)
internalValue.set(field, value)
this.set(key, internalValue, ttlMs)
const map = this.get<Map<string, T>>(key) ?? new Map<string, T>()
const isNewField: boolean = !map.has(field)
map.set(field, value)
this.set(key, map, ttlMs)
return isNewField
}).immediate()
}


// Don't use it with large values or blobs.
// Do not use it with several large amounts of data or blobs.
// This is because the entire data record with all fields is always read and written.
// Inspired by: https://docs.keydb.dev/docs/commands/#hget
hGet<T = any>(key: string, field: string): T | undefined {
const internalValue = this.get<Map<string, T>>(key)
if (internalValue === undefined) return undefined
return internalValue.get(field)
const map = this.get<Map<string, T>>(key)
if (map === undefined) return undefined
return map.get(field)
}


// Don't use it with large values or blobs.
// Do not use it with several large amounts of data or blobs.
// This is because the entire data record with all fields is always read and written.
// Inspired by: https://docs.keydb.dev/docs/commands/#hmset
hmSet<T = any>(key: string, fields: {[field: string]: T}, ttlMs?: number) {
this.db.transaction(() => {
const internalValue = this.get<Map<string, T>>(key) ?? new Map<string, T>()
const map = this.get<Map<string, T>>(key) ?? new Map<string, T>()
Object.entries(fields).forEach(([field, value]) => {
internalValue.set(field, value)
map.set(field, value)
})
this.set(key, internalValue, ttlMs)
this.set(key, map, ttlMs)
}).immediate()
}


// ToDo: hmGet()
// Don't use it with large values or blobs.
// Do not use it with several large amounts of data or blobs.
// This is because the entire data record with all fields is always read and written.
// Inspired by: https://docs.keydb.dev/docs/commands/#hmget


Expand All @@ -673,7 +677,8 @@ export class BunSqliteKeyValue {


// ToDo: hVals()
// Don't use it with large values or blobs.
// Do not use it with several large amounts of data or blobs.
// This is because the entire data record with all fields is always read and written.
// Inspired by: https://docs.keydb.dev/docs/commands/#hvals


Expand Down
33 changes: 17 additions & 16 deletions tests/memory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ test("rename()", async () => {
})


test("hSet(), hGet(), hmSet(), hmGet()", async () => {
test("hSet(), hGet()", async () => {
const store = new BunSqliteKeyValue()

store.hSet(KEY_1, FIELD_1, STRING_VALUE_1)
Expand All @@ -576,21 +576,22 @@ test("hSet(), hGet(), hmSet(), hmGet()", async () => {

store.hSet(KEY_1, FIELD_2, STRING_VALUE_3)
expect(store.hGet<string>(KEY_1, FIELD_2)).toEqual(STRING_VALUE_3)

// Set multiple fields
store.hmSet(KEY_1, {
"test-field-3": "value-3",
"test-field-4": "value-4",
"test-field-5": "value-5"
})

// ToDo: Get multiple fields


console.log(store.get(KEY_1))


})



// test("hmSet(), hmGet()", async () => {
// const store = new BunSqliteKeyValue()
//
// // // Set multiple fields
// // store.hmSet(KEY_1, {
// // "test-field-3": "value-3",
// // "test-field-4": "value-4",
// // "test-field-5": "value-5"
// // })
// //
// // // ToDo: Get multiple fields
// //
// //
// // console.log(store.get(KEY_1))
//
// })

0 comments on commit fda97d4

Please sign in to comment.