enowars/enochecker

StoredDict Type issues

Closed this issue · 8 comments

To Reproduce

db = StoredDict(name=foo)
db['foo']={5:"aaa"}
dict = db['foo']
dict[5]```  <=== fails

the 5 gets converted to a string so:
`dict['5']` works

<< Ints will be stringified on entry, but probably not on load...

I don't think there is a trivial way to fix this. Entries are stored using json.dumps, which means {5:"a"} and {"5":"a"} result in the exact same file when stored to the disk. We could work around this by not returning a dict but instead a custom type which handles these cases, but we would still have other issues anyways, e.g. the following:

db = StoreDict()
db["foo"]={5:"a","5":"b"}

results in this being stored to disk:

{"5": "a", "5": "b"}

which, when loaded, yields:

>>> json.loads('{"5": "a", "5": "b"}')
{'5': 'b'}

And I don't see how we could fix this, apart from abandoning the StoredDict altogether. Even though it is definitely nice for testing purposes, testing with a database which behaves differently from the one being used in production might cause issues down the line.

Alternatively, always stringify keys, in every backend, on put and get

What is the expected behavior when storing {"5":"a", 5:"b"} then? Raising an exception?

It's fine to leave this unspecified imho, it's not legal in json, hence not legal in Mongo, aanyway? Or maybe check what Mongo does, it may raise an exception here.

I just checked this, Mongo does indeed have the same issue:

> db.asd.insertOne({5:"asd"});
{
	"acknowledged" : true,
	"insertedId" : ObjectId("608545c438b51dee137975a6")
}
> db.asd.findOne();
{ "_id" : ObjectId("608545c438b51dee137975a6"), "5" : "asd" }
> db.asd.insertOne({5:"asd", "5": "b"});
{
	"acknowledged" : true,
	"insertedId" : ObjectId("608545da38b51dee137975a7")
}
> db.asd.find();
{ "_id" : ObjectId("608545c438b51dee137975a6"), "5" : "asd" }
{ "_id" : ObjectId("608545da38b51dee137975a7"), "5" : "b" }

It DOES, however, support accessing the value using 5 and "5":

> db.asd.findOne({5:"b"})[5];
b
> db.asd.findOne({5:"b"})["5"];
b

Either way, we should just specify that keys in dictionaries MUST be strings and leave the behavior in case they are not undefined.

(Mostly) addressed with #104