-
Notifications
You must be signed in to change notification settings - Fork 139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement .has() #75
Implement .has() #75
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While you could pass this through to the storage adapter with store.has()
you'd then need to implement a has()
method on all storage adapters for this to work and it would break all existing third-party storage adapters.
I'd suggest a better solution would be to allow passing an option to get()
to return the raw value and checking if the raw value is set.
That should work without requiring any changes to the official storage adapters and without breaking third-party adapters.
src/index.js
Outdated
|
||
return Promise.resolve() | ||
.then(() => { | ||
return store.has(key); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You would need to implement the .has()
method on all official storage adapters before this would work.
src/index.js
Outdated
}); | ||
} | ||
|
||
isUndefined(key) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure an .isUndefined()
method is necessary, it can be done outside of Keyv once .has()
is implemented.
This is already implemented in #42. It just needs to be pulled. |
Woops sorry, just seen #42 is over a year old! Apologies for the delay, it's been a very crazy year and have been struggling to keep up with OSS, will take a look at that PR now. |
@dusansimic I've reviewed #42 and made a few tweaks and merged. If you could update this PR to make use of the raw option that would be brilliant. Sorry again for the delay on that! |
Implemented has method so set will only accept values that are NOT undefined and has will check if get method result is undefined. It will be only if the key doesn't exist.
To make Keyv return more raw data which will help with creating modules, .has method is separated from .isUndefined method so .has just tells us if the key exists and .isUndefined if it has a value.
453c8e4
to
675a60d
Compare
Remove isUndefined() function from index and test as requested. Also update has() function so it gets raw value of a key and checks if it exsits that way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should just do a raw .get()
inside .has()
and check if the raw value is set or not.
src/index.js
Outdated
|
||
return Promise.resolve() | ||
.then(() => { | ||
return Boolean(store.get(key, { raw: true })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This won't work, store
references the underlying storage adapter which likely won't support the raw option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So it should be called via this
?
src/index.js
Outdated
@@ -86,6 +86,16 @@ class Keyv extends EventEmitter { | |||
.then(() => true); | |||
} | |||
|
|||
has(key) { | |||
key = this._getKeyPrefix(key); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need to re-implement .get()
inside .has()
, you can just call .get()
inside it with { raw: true }
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Get boolean weather key exisits by running .get() with raw option inside .has(). Also calling .get() method via this.
src/index.js
Outdated
@@ -86,6 +86,10 @@ class Keyv extends EventEmitter { | |||
.then(() => true); | |||
} | |||
|
|||
async has(key) { | |||
return Boolean(await this.get(key, { raw: true })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here I would probably check like this
(typeof await this.get(key, { raw: true }) === 'object')
Although not sure that's necessarily better. Any specific reason you chose to wrap with Boolean()
?
// CC @sindresorhus any input would be appreciated here 🙏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well it's just something I do so I would know I want to know if that value exists or not. If I use typeof
it look to me like I'm checking for object
specifically but what I actually want anything except null
/undefined
. I'd also like Sindres input on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I use typeof it look to me like I'm checking for object specifically but what I actually want anything except null/undefined.
That's exactly why I don't think it should be written like this. I think you should be checking for an object explicitly.
Using {raw: true}
will return the raw keyv object if it's set or undefined
if it's not. So you literally want to say "Does this function return an object." or "Does this function not return undefined
"
So
typeof (await this.get(key, { raw: true })) === 'object'
or
(await this.get(key, { raw: true })) !== undefined
are semantically correct.
What you're currently doing:
Boolean(await this.get(key, { raw: true }));
is just saying "Is this value truthy".
Which happens to work in this scenario, an object will be truthy and undefined
will be falsey. However it's not checking the exact value we know it should be. It's less explicit and it's possible if we change the way data is structured internally it could break.
Does that make sense?
test/keyv.js
Outdated
@@ -85,6 +85,14 @@ test.serial('.get(key, {raw: true}) returns the raw object instead of the value' | |||
t.is(rawObject.value, 'bar'); | |||
}); | |||
|
|||
test.serial('.has(key) where key is the key we are looking for', async t => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These tests should actually be in keyv-test-suite
so they are run against all storage adapters and catch any anomalies.
Don't worry about that for now, you can add the tests here and I'll move them over. The development process is a bit painful because all the modules depend on each other.
Would you be able to make the tests a bit more extensive though, it should test all possible different types of behaviour with all types. Ideally a single test for each check.
It may seem over the top and it's fine with the current implementation because you know it'll always return an object or undefined. But that's testing the current implementation, not the intended functionality.
If in the future we made a change to how entries are stored internally it could mean that a value of undefined would then cause .has()
to return false when it should return true.
You should extensively test all expected behaviours with all types.
You can use these test files for inspiration:
https://github.com/lukechilds/keyv-test-suite/blob/master/src/api.js
https://github.com/lukechilds/keyv-test-suite/blob/master/src/values.js
Check if value is `undefined` instead of using `Boolean()` function for converting it to boolean.
I'm sorry for not finishing this up earlier, I had a lot of work around university. I've added all the requested changes and also created a PR on |
Implemented at https://keyv.js.org 👍 |
Implementing
.has()
method from Map instances. Also adding.isUndefined()
method since there's been a request for it in an issue referenced below.The idea is to expose more raw data from Keyv via creating a method
.has()
that just tells us if the specified key exists and.isUndefined()
method that tells us if that key has a value.Closes: #50