Skip to content
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

\RavenDB\Documents\Commands\GetDocumentsCommand::withStartWith() throw on not null but empty prefix #57

Open
Geolim4 opened this issue Jan 11, 2024 · 19 comments

Comments

@Geolim4
Copy link

Geolim4 commented Jan 11, 2024

Hello,

Method \RavenDB\Documents\Commands\GetDocumentsCommand::withStartWith throw when $startWith is an empty string (but is not null), while an empty string is working and theoretically a valid prefix.

Solution:

Replace:

        if (empty($startWith)) {
            throw new IllegalArgumentException("startWith cannot be null");
        }

by:

        if ($startWith === null) {
            throw new IllegalArgumentException("startWith cannot be null");
        }
@ayende
Copy link
Member

ayende commented Jan 11, 2024

Can you explain what your scenario is for using startsWith with an empty string?
Are you trying to iterate over all the documents?

@Geolim4
Copy link
Author

Geolim4 commented Jan 11, 2024

Can you explain what your scenario is for using startsWith with an empty string? Are you trying to iterate over all the documents?

Yes indeed, with a limit of 1000 documents ( via the pageSize parameter), there's ofc an option pattern I'm using for "matches" parameters, but it's effectively what I'm doing.

@Geolim4
Copy link
Author

Geolim4 commented Jan 11, 2024

But if I'm going on the wrong way, just tell me what alternative to use :P

I'm only looking for a way to fetch up to 1000 documents (metadata only, I don't need the rest) with an optional "matches" parameter.

@ayende
Copy link
Member

ayende commented Jan 11, 2024

Can you go back a step? What is the actual scenario? You want to find 1000 documents based on their id?

Note that if you matches for empty startsWith means that you are doing a full scan.

Basically:

for item in docs:
   if match(item):
       yield item

I assume that this isn't what you want.

@Geolim4
Copy link
Author

Geolim4 commented Jan 11, 2024

Not exactly, I have a public API that allow users to retrieve all the cache items (the objects stored in Ravendb) with a maximum hard-limit of 999 items. This public API have an optional "$pattern" parameter that I successfully bound to Ravendb:

    /**
     * @return array<int, string>
     * @throws PhpfastcacheDriverException
     * @throws PhpfastcacheInvalidArgumentException
     */
    protected function driverReadAllKeys(string $pattern = ''): iterable
    {
        $keys = [];
        if (empty($this->documentPrefix)) {
            throw new PhpfastcacheUnsupportedMethodException('A document prefix must be configured and not empty to be able to load all items from Raven.');
        }
        $results = $this->instance->loadStartingWith(
            RavenProxy::class,
            $this->documentPrefix,
            $pattern,
            0,
            ExtendedCacheItemPoolInterface::MAX_ALL_KEYS_COUNT
        );

        if (is_iterable($results)) {
            /** @var RavenProxy $item */
            foreach (iterator_to_array($results) as $item) {
                $keys[] = $item->getKey();
            }
        }

        return $keys;
    }

So to bypass this "error", I made the prefix mandatory so the /docs can be called without errors.

@ayende
Copy link
Member

ayende commented Jan 11, 2024

What is the meaning of the pattern in your case? What is the user's scenario for this?

@Geolim4
Copy link
Author

Geolim4 commented Jan 11, 2024

It is like a "I want all the cache item that contain xxxx keyword".

And I wrap the keyword with * like this: *keyword*. it is currently really working well:

image

But the pattern is working well, it's just the $startsWith prefix which is mandatory on the Php client while it is not on the Ravendb API. Well not exactly "mandatory" but incorrectly checked as it considers an empty string as null due to if (empty($startWith)) check :)

@ayende
Copy link
Member

ayende commented Jan 11, 2024

The issue is that this works as long as you have a small amount of data. But if you have 1M items, you may need to scan through all of those.
What kind of freedom do you have in this scenario?
If I was writing independently, I would want to do something like:

{ data: ..., id: ..., tags: ["cache-test3"] }

So add the ability to tag a cache item (with multiple tags), then allow to query on that. This will result in both better API and use case, I think.
But I don't know if this is something that is possible from your end given that you integrate with an existing project

@Geolim4
Copy link
Author

Geolim4 commented Jan 11, 2024

Tags already exists and are handled well on my side, but don't bother about the pattern, it is not the issue here 😂
The issue is just that the php client requires developers to provide an non-empty string to $startWith while it is not required at all by the API. Because it considers an empty string equal to null.

So; short version: I'd like to be all to grab the 999 first documents without having to provide $startWith or $matches ☺️

@ayende
Copy link
Member

ayende commented Jan 11, 2024

That is indeed a bug, and we can fix that. @alxsabo

The actual use case is probably better off with a query, rather that loadStartingWith

@alxsabo
Copy link
Contributor

alxsabo commented Jan 11, 2024

Ok. I will make a bug fix for this issue.

@Geolim4
Copy link
Author

Geolim4 commented Jan 11, 2024

Aside topic:

Do the ravendb client is Semver-compliant ?

Because I found changes that are completely breaking between 5.21 et 5.2.6 :(

@ayende
Copy link
Member

ayende commented Jan 11, 2024

There shouldn't be any breaking changes, only additional APIs

@alxsabo
Copy link
Contributor

alxsabo commented Jan 11, 2024

Because I found changes that are completely breaking between 5.21 et 5.2.6 :(

Can you tell us what changes you found?

@Geolim4
Copy link
Author

Geolim4 commented Jan 11, 2024

PHP version changes from 8.0 to 8.1 minimum in between 2 PATCH version :(

So basically when my CI is running, composer rollback from 5.2.6 to 5.2.1 to run the tests which make new methods added between 5.2.1 and 5.2.6 suddenly unavailable :(

Because Phpfastcache runs from 8.0 up to 8.4, so the Github Actions runs the tests on each of them.

@alxsabo
Copy link
Contributor

alxsabo commented Jan 11, 2024

Yes, we update minimum version of PHP to be 8.1, and RavenDB cant be run on PHP 8.0

@Geolim4
Copy link
Author

Geolim4 commented Jan 11, 2024

Yes, that was a breaking changes, for being Semver compliant this change should have occurred on a MINOR or MAJOR version.
Here you increased the minimum support between 2 PATCH version, so users from the 5.2 library will have incompatible code between php 8.0 and 8.1. Fine for me, I'll make the necessary checks and changes, but you should be carefully not introducing too much BC else users will have pain maintaining their code to your client :)

@alxsabo
Copy link
Contributor

alxsabo commented Jan 11, 2024

Thank you for raising this concern. We'll ensure better backward compatibility in our future updates.

@Geolim4
Copy link
Author

Geolim4 commented Jan 11, 2024

This is something I'm very vigilant to since I took the Phpfastcache library 8 years ago.
PHP version was only increased from major to major version to avoid users to have brutal composer rollbacks and versions constraint sticked.

I will continue my implementation on my side until I consider it stable enough to make an official release of Ravendb support on Phpfastcache. Thanks for the quick support however !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants