Skip to content

Feat - add custom filter parser#3

Merged
eldadfux merged 47 commits intoutopia-php:v0from
kodumbeats:v0
Apr 26, 2021
Merged

Feat - add custom filter parser#3
eldadfux merged 47 commits intoutopia-php:v0from
kodumbeats:v0

Conversation

@kodumbeats
Copy link
Copy Markdown
Contributor

@kodumbeats kodumbeats commented Apr 22, 2021

New Feature

This PR introduces a new Query class which will hold all related information for custom document filters.

Note - due to $filter being used already, I refer to a custom filter as a $query until we can find something more clear.

Test plan

Tests included with PR

Todo

  • Implement filter parser with no nesting
  • Create new Query class
  • Add tests
  • Unit test parseExpression()

Should we...

  • Check types against collection schema
  • Expand tests to check all query types

@kodumbeats kodumbeats marked this pull request as draft April 22, 2021 18:09
@kodumbeats
Copy link
Copy Markdown
Contributor Author

Testing locally against MariaDB has 🟢

$ docker-compose exec tests vendor/bin/phpunit --debug /usr/src/code/tests/Database/Adapter/MariaDBTest.php

PHPUnit 9.5.4 by Sebastian Bergmann and contributors.

Test 'Utopia\Tests\Adapter\MariaDBTest::testCreateDelete' started
Test 'Utopia\Tests\Adapter\MariaDBTest::testCreateDelete' ended
Test 'Utopia\Tests\Adapter\MariaDBTest::testCreateDeleteCollection' started
Test 'Utopia\Tests\Adapter\MariaDBTest::testCreateDeleteCollection' ended
Test 'Utopia\Tests\Adapter\MariaDBTest::testCreateDeleteAttribute' started
Test 'Utopia\Tests\Adapter\MariaDBTest::testCreateDeleteAttribute' ended
Test 'Utopia\Tests\Adapter\MariaDBTest::testCreateDeleteIndex' started
Test 'Utopia\Tests\Adapter\MariaDBTest::testCreateDeleteIndex' ended
Test 'Utopia\Tests\Adapter\MariaDBTest::testCreateDocument' started
Test 'Utopia\Tests\Adapter\MariaDBTest::testCreateDocument' ended
Test 'Utopia\Tests\Adapter\MariaDBTest::testGetDocument' started
Test 'Utopia\Tests\Adapter\MariaDBTest::testGetDocument' ended
Test 'Utopia\Tests\Adapter\MariaDBTest::testUpdateDocument' started
Test 'Utopia\Tests\Adapter\MariaDBTest::testUpdateDocument' ended
Test 'Utopia\Tests\Adapter\MariaDBTest::testDeleteDocument' started
Test 'Utopia\Tests\Adapter\MariaDBTest::testDeleteDocument' ended
Test 'Utopia\Tests\Adapter\MariaDBTest::testFindFirst' started
Test 'Utopia\Tests\Adapter\MariaDBTest::testFindFirst' ended
Test 'Utopia\Tests\Adapter\MariaDBTest::testFindLast' started
Test 'Utopia\Tests\Adapter\MariaDBTest::testFindLast' ended
Test 'Utopia\Tests\Adapter\MariaDBTest::testParseQueries' started
Test 'Utopia\Tests\Adapter\MariaDBTest::testParseQueries' ended


Time: 00:03.764, Memory: 6.00 MB

OK (11 tests, 101 assertions)

@eldadfux
Copy link
Copy Markdown
Member

Thinking about this a bit here are some of my ideas:

  • We will create a class called Database\Query to hold all query related operations/data
  • The class constructor will create a query instance with all relevant metadata that will allow us to build a native SQL/NOSQL query (key, operator, value/values), an array of query objects will allow us to build complex queries.
  • Create a static method called Database\Query::parse([STRING]) that will parse a string query (director.equals('brandon')) and return a Database\Query instance.
  • The Database\Query class can have multiple getters and setters to make DX nicer.

@kodumbeats
Copy link
Copy Markdown
Contributor Author

As of e802153

# kodumbeats @ magician in ~/w/kodumbeats/database on git:v0 x [12:28:00]
$ dc exec tests vendor/bin/phpunit tests/Database/Adapter/MariaDBTest.php 
PHPUnit 9.5.4 by Sebastian Bergmann and contributors.

..........                                                        10 / 10 (100%)

Time: 00:00.711, Memory: 6.00 MB

OK (10 tests, 85 assertions)

# kodumbeats @ magician in ~/w/kodumbeats/database on git:v0 x [12:28:17] 
$ dc exec tests vendor/bin/phpunit tests/Database/QueryTest.php          
PHPUnit 9.5.4 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 00:00.002, Memory: 6.00 MB

OK (2 tests, 10 assertions)

@kodumbeats kodumbeats marked this pull request as ready for review April 23, 2021 16:37
Comment thread src/Database/Query.php Outdated
Comment thread src/Database/Query.php Outdated
Comment thread src/Database/Query.php Outdated
Comment thread src/Database/Query.php Outdated
return [$operator, $operand];
}

// /**
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love this idea! we should probably have a validator class for queries syntax...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How's this for a start? I figure this is a good place to check if the operator is supported too:
179a0d5

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a good start, we can have it as a standalone PR

@eldadfux
Copy link
Copy Markdown
Member

We also need to support multiple params for or queries, a few examples:

director.equals('eldad', 'brandon')
director.equals('eldad','brandon')

@kodumbeats
Copy link
Copy Markdown
Contributor Author

As of 631ecfd

$ docker-compose exec tests vendor/bin/phpunit --debug tests/Database/QueryTest.php
PHPUnit 9.5.4 by Sebastian Bergmann and contributors.

Test 'Utopia\Tests\QueryTest::testParse' started
Test 'Utopia\Tests\QueryTest::testParse' ended
Test 'Utopia\Tests\QueryTest::testGetAttribute' started
Test 'Utopia\Tests\QueryTest::testGetAttribute' ended
Test 'Utopia\Tests\QueryTest::testGetOperator' started
Test 'Utopia\Tests\QueryTest::testGetOperator' ended
Test 'Utopia\Tests\QueryTest::testGetValue' started
Test 'Utopia\Tests\QueryTest::testGetValue' ended
Test 'Utopia\Tests\QueryTest::testGetQuery' started
Test 'Utopia\Tests\QueryTest::testGetQuery' ended


Time: 00:00.002, Memory: 6.00 MB

OK (5 tests, 22 assertions)

@eldadfux
Copy link
Copy Markdown
Member

Looks good! I would have added more tests to make sure casting works as expected with all types

Comment thread src/Database/Query.php Outdated
Comment thread src/Database/Query.php Outdated
return null;
} else {
// strip quotes from queries of type string
return str_replace(['"',"'"], "", $value);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to remove only the first and last chars if they are " or '

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should also handle escaping of \' and \"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used trim() and stripslashes() for this

Comment thread src/Database/Query.php Outdated
Comment thread src/Database/Query.php Outdated
Comment thread src/Database/Query.php Outdated
Comment thread tests/Database/QueryTest.php Outdated
@eldadfux eldadfux merged commit 60391ec into utopia-php:v0 Apr 26, 2021
@coderabbitai coderabbitai Bot mentioned this pull request Dec 2, 2025
@coderabbitai coderabbitai Bot mentioned this pull request Dec 18, 2025
premtsd-code added a commit that referenced this pull request Apr 13, 2026
#1 Drop $enable flag on skipDuplicates() scope guard
The $enable param made every non-skipDuplicates createDocuments call pay
for a closure allocation + extra function call. Branch at the call site
instead so the cost only applies when the flag is actually set.

  - Adapter::skipDuplicates(callable, bool) → skipDuplicates(callable)
  - Database::skipDuplicates(callable, bool) → skipDuplicates(callable)
  - Database::createDocuments, Mirror::createDocuments, Pool::delegate,
    Pool::withTransaction now branch inline.

#2 Drop fetchExistingByIds helper, inline find()
The helper's per-tenant grouping defended a hypothetical multi-tenant
batching scenario that no caller exercises (relationships are intra-
tenant, callers always batch per tenant). Existing patterns in the same
file (refetchDocuments, relationship loading) just call find() directly.
Match that idiom and drop ~70 lines.

#4 Mirror: only capture inserted docs in skipDuplicates mode
The captureOnNext accumulator paid the cost (closure + per-doc array
push) on every createDocuments call, including the common non-skip path.
Branch at the entry of Mirror::createDocuments so the capture only
happens when skipDuplicates is set; the non-skip path passes through
to source/destination unchanged.

#5 Move getInsertKeyword/Suffix/PermissionsSuffix to getters cluster
Were sitting next to createDocuments(); moved to the getSupport*
cluster around line 1030 where other adapter-capability shims live.

Not addressed:
- #2 partial: the existing patterns (refetchDocuments etc.) don't handle
  tenant-per-document multi-tenant batches either, so this is consistent.
- #3 (drop the pre-filter): rejected. createDocumentRelationships runs
  in the encoding loop BEFORE the adapter's INSERT IGNORE no-ops the
  parent, so dropping the pre-filter would deterministically duplicate
  child rows on every CSV re-import of a collection with relationships
  (not a race window — every call). The relationships test verifies
  this. Reverting would require reintroducing the deferred-relationships
  scaffolding we just removed, and the adapter still couldn't tell us
  which parents were actually inserted (SQL INSERT IGNORE has no per-row
  reporting). Pre-filter stays.
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

Successfully merging this pull request may close these issues.

3 participants