Skip to content

Use database type conversion in Filters (test postgres+mysql) #1480

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

Merged
merged 1 commit into from
Nov 28, 2017

Conversation

soyuka
Copy link
Member

@soyuka soyuka commented Nov 6, 2017

Q A
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets na
License MIT
Doc PR na

Stated in Advanced field value conversion using custom mapping types:

When using DQL queries, the convertToPHPValueSQL and convertToDatabaseValueSQL methods only apply to identification variables and path expressions in SELECT clauses. Expressions in WHERE clauses are not wrapped!

We won't see any difference in sqlite for example (know why here) but I'm definitely seeing one in Oracle where the date parameter has the wrong format and therefore leads to a bad query. Maybe we should use this also in numeric filters.

/edit:

  • Add something to skip the ordering of relations while comparing values in JSON
  • Adding postgresql to travis:
    I wouldn't think this would be so hard haha. Few bugs discovered:
    • filtering on any integer field with a string containing a decimal (eg9.3) will throw (fixed but changes behavior as they're ignored)
    • actually sqlite LIKE filters are case insensitive whereas postgres is case sensitive. This renders a few tests useless on sqlite.
    • in features/numeric_filters we DO NOT test the numeric filter but only the search filter... (renamed)
    • add numeric filters tests
    • there is weird stuff going on in search_filter which should not be there (mainly on id and associations) maybe this should've been called text_filter. For example we can't say that an identifier is always named id assumption made here (fixed by using metadata)
    • needs more tests on AbstractFilter (convert) + test iriconvert new method
  • Why does tags.feature fail on postgresql?
And the header "Cache-Tags" should not exist
And "/relation_embedders,/related_dummies,/third_levels" IRIs should be purged
IRIs "/relation_embedders,/related_dummies/1,/related_dummies,/third_levels/1,/third_levels" does not match expected "/relation_embedders,/related_dummies,/third_levels".
  • Why does fos_user.feature fail? My guess is bad table name?
An exception occurred while executing 'INSERT INTO User (username, username_canonical, email, email_canonical, enabled, salt, password, last_login, confirmation_token, password_requested_at, roles, id, fullname) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' with params ["dummy.user", "dummy.user", "[email protected]", "[email protected]", 0, null, "$2y$13$h11wei5V1h8MHUrolsKhCuJo9DgkEDsl62wQVVTJYiTYuncjzRPL6", null, null, null, "a:0:{}", 1, "Dummy User"]:
SQLSTATE[42601]: Syntax error: 7 ERROR:  syntax error at or near "User"
LINE 1: INSERT INTO User (username, username_canonical, email, email...
                    ^

Debug instructions:

docker run --name postgres -e POSTGRES_PASSWORD=api-platform -d postgres:9.6.5-alpine
# tests/Fixtures/app/config/config.yml
 doctrine:
     dbal:
-        default_connection: '%default_connection%'
+        default_connection: 'postgres'
@@ -28,10 +28,10 @@ doctrine:
             postgres:
                 driver:   'pdo_pgsql'
-                dbname:   'api_platform_test'
+                dbname:   'postgres'
                 user:     'postgres'
-                password: ''
-                host:     'localhost'
+                password: 'api-platform'
+                host:     '172.17.0.2' # docker inspect

Copy link
Contributor

@sroze sroze left a comment

Choose a reason for hiding this comment

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

Seems very weird that Doctrine isn't in charge of that

@@ -185,7 +191,7 @@ protected function addWhere(QueryBuilder $queryBuilder, QueryNameGeneratorInterf
));
}

$queryBuilder->setParameter($valueParameter, new \DateTime($value));
$queryBuilder->setParameter($valueParameter, $type->convertToDatabaseValue(new \DateTime($value), $queryBuilder->getEntityManager()->getConnection()->getDatabasePlatform()));
Copy link
Contributor

Choose a reason for hiding this comment

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

What if $type is null?

Copy link
Member Author

Choose a reason for hiding this comment

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

I had the condition before but removed it. Indeed Type::getType will throw if not found (in getDateType).

What I can do:

  1. test for hasType
  2. Use what we had before when null

Though, this method will only be called when the Type is available in the DOCTRINE_DATE_TYPES constant. Therefore, it's not really useful because it'll never be null (those are all defined by default).

Scenario: Get collection filtered by date that is not a datetime
Given there is "30" dummydate objects with dummyDate
When I send a "GET" request to "/dummy_dates?dummyDate[after]=2015-04-28"
Then the response status code should be 200
Copy link
Contributor

Choose a reason for hiding this comment

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

You don't test anything in here if you don't test the content of the response. Therefore, I don't understand what is this test trying to prove

Copy link
Member Author

@soyuka soyuka Nov 6, 2017

Choose a reason for hiding this comment

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

If I run this test on my database without the patch it fails to status code 500. This is just to ensure a non-regression.

And it's totally useless on sqlite haha.

Copy link
Member

Choose a reason for hiding this comment

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

Does it affects MySQL or Postgres? it it is the case, maybe should we also run the Behat test suite with such DBMS.

Copy link
Member Author

Choose a reason for hiding this comment

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

As long as they have two types for dates (ie date vs datetime) yes. And yes I think we should.

I came across this when using a date on an index (it's weird to keep time on an index imo).

@soyuka
Copy link
Member Author

soyuka commented Nov 6, 2017

Seems very weird that Doctrine isn't in charge of that

Indeed it surprised me as well but according to what I quoted from the docs the behavior is correct no?

driver: 'pdo_sqlite'
path: '%kernel.cache_dir%/db.sqlite'
charset: 'UTF8'
default_connection: '%default_connection%'
Copy link
Member Author

Choose a reason for hiding this comment

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

I made an attempt with %env(DEFAULT_CONNECTION)% which would've been cleaner IMO but because this is an alias it doesn't work, see symfony/symfony#21609

Copy link
Member

Choose a reason for hiding this comment

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

Why don't you use different environments with multiple config files instead (config_test.yml, config_test_mysql.yml, config_test_pgsql)? Then you just have to set the APP_ENV environment variable in your Travis config instead of doing cp!

Copy link
Member Author

Choose a reason for hiding this comment

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

would this mean that I'd have to copy the whole configuration file 3 times?

Copy link
Member

Choose a reason for hiding this comment

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

Nop:

  • config_test.yaml: the whole configuration +
doctrine:
      dbal:
         driver:                        'pdo_sqlite'
         path:                          '%kernel.cache_dir%/db.sqlite'
         charset:                       'UTF8'
  • config_test_mysql.yaml:
imports:
    - { resource: config_test.yaml }

doctrine:
    dbal:
        driver: pdo_mysql
        path: ~
        dbname:   'api_platform_test'
        user:     'travis'
        password: ''
        host:     'localhost'

etc.

@soyuka soyuka force-pushed the fix/doctrine-type-where branch 4 times, most recently from f6c0f7b to 9e7d479 Compare November 9, 2017 10:48
@soyuka soyuka added the bug label Nov 9, 2017
@soyuka soyuka force-pushed the fix/doctrine-type-where branch 2 times, most recently from c5aaf1b to 9528880 Compare November 9, 2017 14:55
@soyuka soyuka changed the title Use type conversion in DateFilter WIP: Use database type conversion in Filters Nov 9, 2017
@soyuka soyuka changed the title WIP: Use database type conversion in Filters WIP: Use database type conversion in Filters (test postgres+mysql) Nov 9, 2017
@soyuka soyuka force-pushed the fix/doctrine-type-where branch 3 times, most recently from c8262c6 to 620d25d Compare November 9, 2017 17:21
@soyuka soyuka changed the base branch from 2.1 to master November 10, 2017 11:26
@soyuka soyuka force-pushed the fix/doctrine-type-where branch 9 times, most recently from e503023 to dba1cea Compare November 13, 2017 09:40
@soyuka soyuka changed the title WIP: Use database type conversion in Filters (test postgres+mysql) Use database type conversion in Filters (test postgres+mysql) Nov 13, 2017
@soyuka soyuka force-pushed the fix/doctrine-type-where branch 2 times, most recently from 76297af to b5780eb Compare November 13, 2017 10:08
@soyuka soyuka changed the base branch from master to 2.1 November 23, 2017 16:54
@soyuka soyuka force-pushed the fix/doctrine-type-where branch from 4bf9863 to 5bf30c4 Compare November 23, 2017 17:01
@soyuka soyuka force-pushed the fix/doctrine-type-where branch 14 times, most recently from ff46042 to a586b2e Compare November 24, 2017 13:14
@soyuka
Copy link
Member Author

soyuka commented Nov 24, 2017

All green :D.

ping @sroze @dunglas @meyerbaptiste would love some review on this.

I've simplified the pull request:

  • the numeric_fitler.feature has a big diff because the old ones were put in search_filter.feature and I wrote new ones for numeric filters.
  • tests run on postgres, mysql and sqlite (added a JSON should be deep equal to feature to compare without taking the order into consideration).
  • the only code change is to add the doctrine Type to setParameter and to skip invalid values in filters (which is our policy with Doctrine Filters instead of throwing).

We could argue that there is a BC break where id=9.99 will be ignored, but IMHO it's a bug and would be silly to count it as break.

Let me know your thoughts!

@soyuka soyuka force-pushed the fix/doctrine-type-where branch 2 times, most recently from ad52ada to c76edc0 Compare November 24, 2017 14:46
Copy link
Member

@dunglas dunglas left a comment

Choose a reason for hiding this comment

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

Some minor comments, then 👍 for me.

imports:
- { resource: config_test.yml }

doctrine:
Copy link
Member

Choose a reason for hiding this comment

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

It should use environment variables to allow to run test locally (same for Postgres).

$env = $input->getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev');
$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(array('--no-debug', '')) && $env !== 'prod';
$env = $input->getParameterOption(array('--env', '-e'), $_SERVER['APP_ENV'] ?? null ?: 'test');
$debug = ($_SERVER['SYMFONY_DEBUG'] ?? null) !== '0' && !$input->hasParameterOption(array('--no-debug', '')) && $env !== 'prod';
Copy link
Member

Choose a reason for hiding this comment

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

$_SERVER['SYMFONY_DEBUG'] ?? 0 ?

@@ -13,8 +13,8 @@ use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Debug\Debug;

$input = new ArgvInput();
$env = $input->getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev');
$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(array('--no-debug', '')) && $env !== 'prod';
$env = $input->getParameterOption(array('--env', '-e'), $_SERVER['APP_ENV'] ?? null ?: 'test');
Copy link
Member

Choose a reason for hiding this comment

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

$_SERVER['SYMFONY_DEBUG'] ?? 'test'?

@soyuka soyuka force-pushed the fix/doctrine-type-where branch from c76edc0 to c25b81b Compare November 27, 2017 13:22
@soyuka soyuka merged commit acb6ee7 into api-platform:2.1 Nov 28, 2017
@soyuka soyuka deleted the fix/doctrine-type-where branch November 28, 2017 09:19
$environment = $this->getEnvironment();

// patch for behat not supporting %env(APP_ENV)% in older versions
if ($appEnv = $_SERVER['APP_ENV'] ?? null && $appEnv !== $environment) {
Copy link
Member

Choose a reason for hiding this comment

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

Should not it be if (($appEnv = $_SERVER['APP_ENV'] ?? null) && $appEnv !== $environment) {?

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, fixed by #1524.

hoangnd25 pushed a commit to hoangnd25/core that referenced this pull request Feb 23, 2018
Use database type conversion in Filters (test postgres+mysql)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants