Skip to content

Commit

Permalink
Dict.toObject and fix Dict and List conversion (#72)
Browse files Browse the repository at this point in the history
* add `toObject` and fix conversion to `Dict` / `List`

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* add more tests

* update docs

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
PythonFZ and pre-commit-ci[bot] authored Nov 8, 2024
1 parent ef269da commit 9b73a1f
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 12 deletions.
48 changes: 43 additions & 5 deletions js/dict.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,52 @@ export class Dict {

async values() {
const values = await this._client.hVals(this._key);
return values.map((x) => JSON.parse(x)); // Parse the values
return values.map((x) => {
const value = JSON.parse(x);
if (typeof value === "string") {
if (value.startsWith("znsocket.List:")) {
const refKey = value.split(/:(.+)/)[1];
return new ZnSocketList({ client: this._client,socket: this._socket , key: refKey});
} else if (value.startsWith("znsocket.Dict:")) {
const refKey = value.split(/:(.+)/)[1];
return new Dict({ client: this._client, socket: this._socket , key: refKey});
}
}
return value;
});
}

async entries() { // Renamed from items to entries
async entries() {
const entries = await this._client.hGetAll(this._key);
return Object.entries(entries).map(
([key, value]) => [key, JSON.parse(value)]
);
return Object.entries(entries).map(([key, value]) => {
const parsedValue = JSON.parse(value);

if (typeof parsedValue === "string") {
if (parsedValue.startsWith("znsocket.List:")) {
const refKey = parsedValue.split(/:(.+)/)[1];
return [key, new ZnSocketList({ client: this._client, socket: this._socket, key: refKey })];
} else if (parsedValue.startsWith("znsocket.Dict:")) {
const refKey = parsedValue.split(/:(.+)/)[1];
return [key, new Dict({ client: this._client, socket: this._socket, key: refKey })];
}
}

return [key, parsedValue];
});
}

async toObject() {
const entries = await this.entries();
// go through all and if one of them is a Dict or List, call toObject on it
const obj = {};
for (const [key, value] of entries) {
if (value instanceof Dict || value instanceof ZnSocketList) {
obj[key] = await value.toObject();
} else {
obj[key] = value;
}
}
return obj;
}

onRefresh(callback) {
Expand Down
3 changes: 2 additions & 1 deletion js/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ export class Dict {
clear(): Promise<any>;
keys(): Promise<string[]>;
values(): Promise<any[]>;
entries(): Promise<[string, any][]>; // Renamed from items to entries
entries(): Promise<[string, any][]>;
toObject(): Promise<Record<string, any>>;

onRefresh(callback: (data: { keys?: string[]; indices?: number[] }) => void): void;
offRefresh(): void;
Expand Down
21 changes: 21 additions & 0 deletions js_tests/native.dict.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,13 @@ test("native_dict_in_dict", async () => {
expect(dictValue._key).toBe(dct1._key);
const helloValue2 = await dictValue.get("Hello");
expect(helloValue2).toBe("World");

const dct2Values = await dct2.values();
expect(await dct2Values[0]["Hello"]).toEqual("World");

const dct2Entries = await dct2.entries();
expect(await dct2Entries[0][1]["Hello"]).toEqual("World");
expect(await dct2Entries[0][0]).toEqual("dict");
});

test("native_dict_with_list", async () => {
Expand All @@ -251,3 +258,17 @@ test("native_dict_with_list", async () => {
expect(await listInstance.get(0)).toBe("A");
expect(await listInstance.get(1)).toBe("B");
});


test("native_dict_to_object", async () => {
let dct1 = new Dict({ client: client, key: "dict:test:1" });
let dct2 = new Dict({ client: client, key: "dict:test:2" });

await dct1.set("Hello", "World");
await dct2.set("dict", dct1);

// convert to object
const obj = await dct2.toObject();
expect(obj).toEqual({ dict: { Hello: "World" } });

});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "znsocket",
"version": "0.2.5",
"version": "0.2.6",
"description": "JS interface for the python znsocket package",
"main": "js/index.js",
"types": "js/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "znsocket"
version = "0.2.5"
version = "0.2.6"
description = "Python implementation of a Redis-compatible API using websockets."
authors = ["Fabian Zills <[email protected]>"]
license = "Apache-2.0"
Expand Down
25 changes: 21 additions & 4 deletions znsocket/objects/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ def __init__(
callbacks: dict[str, Callable]
optional function callbacks for methods
which modify the database.
repr_type: str
repr_type: "keys"|"minimal"|"full"
Control the `repr` appearance of the object.
Reduce for better performance.
Expand Down Expand Up @@ -374,7 +374,7 @@ def __getitem__(self, key: str) -> t.Any:
value = List(r=self.redis, key=key)
elif value.startswith("znsocket.Dict:"):
key = value.split(":", 1)[1]
value = Dict(r=self.redis, key=key)
value = Dict(r=self.redis, key=key, repr_type=self.repr_type)
return value

def __setitem__(self, key: str, value: t.Any) -> None:
Expand Down Expand Up @@ -415,13 +415,30 @@ def keys(self) -> list[str]:
def values(self) -> list[t.Any]:
response = []
for v in self.redis.hvals(self.key):
response.append(_decode(self, v))
value = _decode(self, v)
if isinstance(value, str):
if value.startswith("znsocket.List:"):
key = value.split(":", 1)[1]
value = List(r=self.redis, key=key)
elif value.startswith("znsocket.Dict:"):
key = value.split(":", 1)[1]
value = Dict(r=self.redis, key=key, repr_type=self.repr_type)
response.append(value)
return response

def items(self) -> list[t.Tuple[str, t.Any]]:
response = []
for k, v in self.redis.hgetall(self.key).items():
response.append((k, _decode(self, v)))
value = _decode(self, v)
if isinstance(value, str):
if value.startswith("znsocket.List:"):
key = value.split(":", 1)[1]
value = List(r=self.redis, key=key)
elif value.startswith("znsocket.Dict:"):
key = value.split(":", 1)[1]
value = Dict(r=self.redis, key=key, repr_type=self.repr_type)

response.append((k, value))
return response

def __contains__(self, key: str) -> bool:
Expand Down

0 comments on commit 9b73a1f

Please sign in to comment.