From 66d2f5958f571a0d31d77ceb269b10dac197d8f7 Mon Sep 17 00:00:00 2001 From: Chris Lloyd Date: Fri, 17 Mar 2023 10:21:43 +0000 Subject: [PATCH] WIP --- .idea/runConfigurations/Tests__sqlsrv_.xml | 2 +- .../Update_Snapshots__sqlsrv_.xml | 2 +- composer.lock | 68 ++-- src/Drivers/SQL/SQLExpression.php | 360 +++++++++++++++++- src/Expression/Node/Func/Type/Cast.php | 30 ++ src/Expression/Parser/Common.php | 28 ++ src/Expression/Parser/Filter.php | 1 + tests/Filter/Database.php | 17 +- tests/Filter/Filter.php | 18 + tests/Helpers/StreamingJsonMatches.php | 6 +- .../StreamingJsonMatches80.php | 2 +- .../StreamingJsonMatches81.php | 4 +- tests/Parser/CastingTest.php | 238 ++++++++++++ tests/Parser/CommonExpressionTest.php | 148 ++++++- tests/Setup/InvalidModelTest.php | 1 + .../EloquentTest__test_filter_cast__1.json | 22 ++ .../EloquentTest__test_filter_search__1.json | 22 ++ ...edCollectionTest__test_filter_cast__1.json | 22 ++ ...CollectionTest__test_filter_search__1.json | 22 ++ ...icCollectionTest__test_filter_cast__1.json | 22 ++ ...CollectionTest__test_filter_search__1.json | 22 ++ .../Filter/SQLTest__test_filter_cast__1.json | 22 ++ .../SQLTest__test_filter_search__1.json | 22 ++ .../Parser/FilterTest__test_40__2.txt | 2 +- .../Parser/FilterTest__test_40__3.txt | 2 +- .../Parser/FilterTest__test_41__2.txt | 2 +- .../Parser/FilterTest__test_41__3.txt | 2 +- .../Parser/FilterTest__test_48__3.txt | 2 +- .../Parser/FilterTest__test_49__3.txt | 2 +- .../Parser/FilterTest__test_4a__3.txt | 2 +- .../Parser/FilterTest__test_4b__3.txt | 2 +- .../Parser/FilterTest__test_4c__2.txt | 2 +- .../Parser/FilterTest__test_4c__3.txt | 2 +- .../Parser/FilterTest__test_4d__3.txt | 2 +- .../Parser/FilterTest__test_4e__2.txt | 2 +- .../Parser/FilterTest__test_4e__3.txt | 2 +- .../Parser/FilterTest__test_4f__3.txt | 2 +- .../Parser/FilterTest__test_53__2.txt | 2 +- .../Parser/FilterTest__test_53__3.txt | 2 +- .../Parser/FilterTest__test_54__2.txt | 2 +- .../Parser/FilterTest__test_54__3.txt | 2 +- 41 files changed, 1066 insertions(+), 71 deletions(-) create mode 100644 src/Expression/Node/Func/Type/Cast.php create mode 100644 tests/Parser/CastingTest.php create mode 100644 tests/__snapshots__/Filter/EloquentTest__test_filter_cast__1.json create mode 100644 tests/__snapshots__/Filter/EloquentTest__test_filter_search__1.json create mode 100644 tests/__snapshots__/Filter/KeyedCollectionTest__test_filter_cast__1.json create mode 100644 tests/__snapshots__/Filter/KeyedCollectionTest__test_filter_search__1.json create mode 100644 tests/__snapshots__/Filter/NumericCollectionTest__test_filter_cast__1.json create mode 100644 tests/__snapshots__/Filter/NumericCollectionTest__test_filter_search__1.json create mode 100644 tests/__snapshots__/Filter/SQLTest__test_filter_cast__1.json create mode 100644 tests/__snapshots__/Filter/SQLTest__test_filter_search__1.json diff --git a/.idea/runConfigurations/Tests__sqlsrv_.xml b/.idea/runConfigurations/Tests__sqlsrv_.xml index 6b2d14ae7..3450f6df0 100644 --- a/.idea/runConfigurations/Tests__sqlsrv_.xml +++ b/.idea/runConfigurations/Tests__sqlsrv_.xml @@ -2,7 +2,7 @@ - + diff --git a/.idea/runConfigurations/Update_Snapshots__sqlsrv_.xml b/.idea/runConfigurations/Update_Snapshots__sqlsrv_.xml index 67ca4d7ad..96aff295c 100644 --- a/.idea/runConfigurations/Update_Snapshots__sqlsrv_.xml +++ b/.idea/runConfigurations/Update_Snapshots__sqlsrv_.xml @@ -2,7 +2,7 @@ - + diff --git a/composer.lock b/composer.lock index 57a7b847d..b187d02da 100644 --- a/composer.lock +++ b/composer.lock @@ -1321,16 +1321,16 @@ }, { "name": "laravel/framework", - "version": "v10.3.3", + "version": "v10.4.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "90f24d9e2860ecf6b5492e966956270ceb98c03d" + "reference": "c3e679cc7d19527fda4210ef137075dafb106d0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/90f24d9e2860ecf6b5492e966956270ceb98c03d", - "reference": "90f24d9e2860ecf6b5492e966956270ceb98c03d", + "url": "https://api.github.com/repos/laravel/framework/zipball/c3e679cc7d19527fda4210ef137075dafb106d0c", + "reference": "c3e679cc7d19527fda4210ef137075dafb106d0c", "shasum": "" }, "require": { @@ -1517,7 +1517,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-03-09T14:00:53+00:00" + "time": "2023-03-17T14:28:55+00:00" }, { "name": "laravel/serializable-closure", @@ -5799,16 +5799,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.261.11", + "version": "3.261.13", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "bba0c975f34325cfb218d68bda6d9e476d309b4c" + "reference": "233b70c951707830dd205959375c98be35cbb36e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/bba0c975f34325cfb218d68bda6d9e476d309b4c", - "reference": "bba0c975f34325cfb218d68bda6d9e476d309b4c", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/233b70c951707830dd205959375c98be35cbb36e", + "reference": "233b70c951707830dd205959375c98be35cbb36e", "shasum": "" }, "require": { @@ -5887,9 +5887,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.261.11" + "source": "https://github.com/aws/aws-sdk-php/tree/3.261.13" }, - "time": "2023-03-14T18:26:15+00:00" + "time": "2023-03-16T18:22:32+00:00" }, { "name": "brianium/paratest", @@ -6831,24 +6831,24 @@ }, { "name": "orchestra/testbench", - "version": "v8.0.8", + "version": "8.x-dev", "source": { "type": "git", "url": "https://github.com/orchestral/testbench.git", - "reference": "782516d438d97ab0d24a96bfdd28794208110077" + "reference": "cbffafa8ec884d30e237572c9b88820d4f86bcb4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench/zipball/782516d438d97ab0d24a96bfdd28794208110077", - "reference": "782516d438d97ab0d24a96bfdd28794208110077", + "url": "https://api.github.com/repos/orchestral/testbench/zipball/cbffafa8ec884d30e237572c9b88820d4f86bcb4", + "reference": "cbffafa8ec884d30e237572c9b88820d4f86bcb4", "shasum": "" }, "require": { "composer-runtime-api": "^2.2", "fakerphp/faker": "^1.21", - "laravel/framework": ">=10.3.3 <10.4.0", + "laravel/framework": ">=10.3.3 <10.5.0 || 10.x-dev", "mockery/mockery": "^1.5.1", - "orchestra/testbench-core": ">=8.0.5 <8.1.0", + "orchestra/testbench-core": ">=8.1.0 <8.2.0 || 8.x-dev", "php": "^8.1", "phpunit/phpunit": "^9.6 || ^10.0.7", "spatie/laravel-ray": "^1.32", @@ -6880,22 +6880,22 @@ ], "support": { "issues": "https://github.com/orchestral/testbench/issues", - "source": "https://github.com/orchestral/testbench/tree/v8.0.8" + "source": "https://github.com/orchestral/testbench/tree/8.x" }, - "time": "2023-03-10T00:51:18+00:00" + "time": "2023-03-17T13:48:06+00:00" }, { "name": "orchestra/testbench-core", - "version": "v8.0.5", + "version": "8.x-dev", "source": { "type": "git", "url": "https://github.com/orchestral/testbench-core.git", - "reference": "b8364097ee6d6d16c59ea86ce9e138b53935fc2f" + "reference": "0a2e4b10bac32eae7bc4238eee4141cc2b6c1ba2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/b8364097ee6d6d16c59ea86ce9e138b53935fc2f", - "reference": "b8364097ee6d6d16c59ea86ce9e138b53935fc2f", + "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/0a2e4b10bac32eae7bc4238eee4141cc2b6c1ba2", + "reference": "0a2e4b10bac32eae7bc4238eee4141cc2b6c1ba2", "shasum": "" }, "require": { @@ -6907,8 +6907,8 @@ "laravel/framework": "^10.3.3", "laravel/pint": "^1.6", "mockery/mockery": "^1.5.1", - "orchestra/canvas": "^8.0", - "phpstan/phpstan": "^1.10.5", + "orchestra/canvas": "^8.1", + "phpstan/phpstan": "^1.10.7", "phpunit/phpunit": "^9.6 || ^10.0.7", "spatie/laravel-ray": "^1.32", "symfony/process": "^6.2", @@ -6927,6 +6927,7 @@ "symfony/yaml": "Required for CLI Commander (^6.2).", "vlucas/phpdotenv": "Required for CLI Commander (^5.4.1)." }, + "default-branch": true, "bin": [ "testbench" ], @@ -6969,7 +6970,7 @@ "issues": "https://github.com/orchestral/testbench/issues", "source": "https://github.com/orchestral/testbench-core" }, - "time": "2023-03-10T00:01:53+00:00" + "time": "2023-03-17T13:56:10+00:00" }, { "name": "phar-io/manifest", @@ -7084,16 +7085,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.6", + "version": "1.10.7", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "50d089a3e0904b0fe7e2cf2d4fd37d427d64235a" + "reference": "b10ceb526d9607903c5b2673f1fc8775dbe48975" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/50d089a3e0904b0fe7e2cf2d4fd37d427d64235a", - "reference": "50d089a3e0904b0fe7e2cf2d4fd37d427d64235a", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b10ceb526d9607903c5b2673f1fc8775dbe48975", + "reference": "b10ceb526d9607903c5b2673f1fc8775dbe48975", "shasum": "" }, "require": { @@ -7122,8 +7123,11 @@ "static analysis" ], "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.10.6" + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" }, "funding": [ { @@ -7139,7 +7143,7 @@ "type": "tidelift" } ], - "time": "2023-03-09T16:55:12+00:00" + "time": "2023-03-16T15:24:20+00:00" }, { "name": "phpunit/php-code-coverage", diff --git a/src/Drivers/SQL/SQLExpression.php b/src/Drivers/SQL/SQLExpression.php index a03514dfc..6b7aa9b8a 100644 --- a/src/Drivers/SQL/SQLExpression.php +++ b/src/Drivers/SQL/SQLExpression.php @@ -65,7 +65,7 @@ use Flat3\Lodata\NavigationBinding; use Flat3\Lodata\NavigationProperty; use Flat3\Lodata\ReferentialConstraint; -use Flat3\Lodata\Type\Enum; +use Flat3\Lodata\Type; /** * SQL Expression, with its associated parameters @@ -371,7 +371,7 @@ protected function operatorExpression(Operator $node): void case $node instanceof Has: $enum = $right->getValue(); - if ($enum instanceof Enum && $enum->isFlags()) { + if ($enum instanceof Type\Enum && $enum->isFlags()) { $this->pushStatement('&'); $this->evaluate($right); } @@ -420,6 +420,310 @@ protected function functionExpression(Func $node): void } break; + case $node instanceof Func\Type\Cast: + $arguments = $node->getArguments(); + list($arg1, $arg2) = $arguments; + $targetType = null; + + switch ($arg2->getValue()) { + case Type\Binary::identifier: + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLite: + $targetType = 'TEXT'; + break; + + case SQLEntitySet::PostgreSQL: + $targetType = 'bytea'; + break; + + default: + $targetType = 'BINARY'; + break; + } + break; + + case Type\UInt16::identifier: + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLite: + $targetType = 'INTEGER'; + break; + + case SQLEntitySet::SQLServer: + case SQLEntitySet::PostgreSQL: + $targetType = 'SMALLINT'; + break; + + case SQLEntitySet::MySQL: + $targetType = 'UNSIGNED INTEGER'; + break; + } + break; + + case Type\UInt32::identifier: + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::PostgreSQL: + case SQLEntitySet::SQLite: + case SQLEntitySet::SQLServer: + $targetType = 'INTEGER'; + break; + + case SQLEntitySet::MySQL: + $targetType = 'UNSIGNED INTEGER'; + break; + } + break; + + case Type\UInt64::identifier: + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLite: + $targetType = 'INTEGER'; + break; + + case SQLEntitySet::SQLServer: + case SQLEntitySet::PostgreSQL: + $targetType = 'BIGINT'; + break; + + case SQLEntitySet::MySQL: + $targetType = 'UNSIGNED INTEGER'; + break; + } + break; + + case Type\Boolean::identifier: + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLite: + $targetType = 'INTEGER'; + break; + + case SQLEntitySet::MySQL: + $targetType = 'UNSIGNED INTEGER'; + break; + + case SQLEntitySet::SQLServer: + $targetType = 'BIT'; + break; + + case SQLEntitySet::PostgreSQL: + $targetType = 'BOOLEAN'; + break; + + } + break; + + case Type\Date::identifier: + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLite: + $targetType = 'TEXT'; + break; + + case SQLEntitySet::MySQL: + case SQLEntitySet::PostgreSQL: + case SQLEntitySet::SQLServer: + $targetType = 'DATE'; + break; + } + break; + + case Type\DateTimeOffset::identifier: + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLite: + $targetType = 'TEXT'; + break; + + case SQLEntitySet::PostgreSQL: + $targetType = 'TIMESTAMP(3)'; + break; + + case SQLEntitySet::SQLServer: + $targetType = 'DATETIMEOFFSET'; + break; + + case SQLEntitySet::MySQL: + $targetType = 'DATETIME(3)'; + break; + } + break; + + case Type\Decimal::identifier: + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLite: + $targetType = 'REAL'; + break; + + case SQLEntitySet::MySQL: + case SQLEntitySet::PostgreSQL: + case SQLEntitySet::SQLServer: + $targetType = 'DECIMAL(10,10)'; + break; + } + break; + + case Type\Double::identifier: + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLite: + $targetType = 'REAL'; + break; + + case SQLEntitySet::SQLServer: + case SQLEntitySet::PostgreSQL: + $targetType = 'DOUBLE PRECISION'; + break; + + case SQLEntitySet::MySQL: + $targetType = 'DOUBLE'; + break; + } + break; + + case Type\Int16::identifier: + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLite: + $targetType = 'INTEGER'; + break; + + case SQLEntitySet::MySQL: + $targetType = 'SIGNED INTEGER'; + break; + + case SQLEntitySet::SQLServer: + case SQLEntitySet::PostgreSQL: + $targetType = 'SMALLINT'; + break; + } + break; + + case Type\Int32::identifier: + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLServer: + case SQLEntitySet::PostgreSQL: + case SQLEntitySet::SQLite: + $targetType = 'INTEGER'; + break; + + case SQLEntitySet::MySQL: + $targetType = 'SIGNED INTEGER'; + break; + } + break; + + case Type\Int64::identifier: + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLite: + $targetType = 'INTEGER'; + break; + + case SQLEntitySet::MySQL: + $targetType = 'SIGNED INTEGER'; + break; + + case SQLEntitySet::SQLServer: + case SQLEntitySet::PostgreSQL: + $targetType = 'BIGINT'; + break; + } + break; + + case Type\SByte::identifier: + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLite: + $targetType = 'INTEGER'; + break; + + case SQLEntitySet::MySQL: + $targetType = 'SIGNED INTEGER'; + break; + + case SQLEntitySet::PostgreSQL: + $targetType = 'SMALLINT'; + break; + + case SQLEntitySet::SQLServer: + $targetType = 'TINYINT'; + break; + } + break; + + case Type\Single::identifier: + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLite: + case SQLEntitySet::PostgreSQL: + $targetType = 'REAL'; + break; + + case SQLEntitySet::MySQL: + case SQLEntitySet::SQLServer: + $targetType = 'FLOAT'; + break; + } + break; + + case Type\String_::identifier: + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLite: + $targetType = 'TEXT'; + break; + + case SQLEntitySet::PostgreSQL: + case SQLEntitySet::SQLServer: + $targetType = 'VARCHAR'; + break; + + case SQLEntitySet::MySQL: + $targetType = 'CHAR'; + break; + } + break; + + case Type\TimeOfDay::identifier: + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLite: + $targetType = 'TEXT'; + break; + + case SQLEntitySet::PostgreSQL: + case SQLEntitySet::SQLServer: + case SQLEntitySet::MySQL: + $targetType = 'TIME(3)'; + break; + } + break; + + default: + $node->notImplemented(); + } + + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLServer: + $this->pushStatement('CONVERT('); + $this->pushStatement($targetType); + $this->pushComma(); + $this->evaluate($arg1); + $this->pushComma(); + // https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql#date-and-time-styles + $this->pushStatement('120'); + $this->pushStatement(')'); + break; + + case SQLEntitySet::PostgreSQL: + case SQLEntitySet::SQLite: + $this->pushStatement('CAST('); + $this->evaluate($arg1); + $this->pushStatement('AS'); + $this->pushStatement($targetType); + $this->pushStatement(')'); + break; + + case SQLEntitySet::MySQL: + $this->pushStatement('CONVERT('); + $this->evaluate($arg1); + $this->pushComma(); + $this->pushStatement($targetType); + $this->pushStatement(')'); + break; + } + return; + case $node instanceof Node\Func\DateTime\Date: switch ($driver) { case SQLEntitySet::MySQL: @@ -455,7 +759,9 @@ protected function functionExpression(Func $node): void case SQLEntitySet::PostgreSQL: $this->pushStatement("DATE_PART( 'DAY',"); - break; + $this->evaluate($node->getArgument()); + $this->pushStatement('::timestamp)::integer'); + return; case SQLEntitySet::MySQL: $this->pushStatement('DAY('); @@ -484,7 +790,9 @@ protected function functionExpression(Func $node): void case SQLEntitySet::PostgreSQL: $this->pushStatement("DATE_PART( 'HOUR',"); - break; + $this->evaluate($node->getArgument()); + $this->pushStatement('::timestamp)::integer'); + return; case SQLEntitySet::SQLite: $this->pushStatement("CAST( STRFTIME( '%H',"); @@ -505,7 +813,9 @@ protected function functionExpression(Func $node): void case SQLEntitySet::PostgreSQL: $this->pushStatement("DATE_PART( 'MINUTE',"); - break; + $this->evaluate($node->getArgument()); + $this->pushStatement('::timestamp)::integer'); + return; case SQLEntitySet::MySQL: $this->pushStatement('MINUTE('); @@ -534,7 +844,9 @@ protected function functionExpression(Func $node): void case SQLEntitySet::PostgreSQL: $this->pushStatement("DATE_PART( 'MONTH',"); - break; + $this->evaluate($node->getArgument()); + $this->pushStatement('::timestamp)::integer'); + return; case SQLEntitySet::SQLite: $this->pushStatement("CAST( STRFTIME( '%m',"); @@ -579,7 +891,9 @@ protected function functionExpression(Func $node): void case SQLEntitySet::PostgreSQL: $this->pushStatement("DATE_PART( 'SECOND',"); - break; + $this->evaluate($node->getArgument()); + $this->pushStatement('::timestamp)::integer'); + return; case SQLEntitySet::SQLite: $this->pushStatement("CAST( STRFTIME( '%S',"); @@ -630,8 +944,10 @@ protected function functionExpression(Func $node): void break; case SQLEntitySet::PostgreSQL: - $this->pushStatement("DATE_PART( 'YEAR',"); - break; + $this->pushStatement("DATE_PART( 'YEAR', "); + $this->evaluate($node->getArgument()); + $this->pushStatement('::timestamp)::integer'); + return; case SQLEntitySet::SQLite: $this->pushStatement("CAST( STRFTIME( '%Y',"); @@ -828,6 +1144,9 @@ protected function functionExpression(Func $node): void $arg2->setValue($value); $this->evaluate($arg2); return; + + default: + $node->notImplemented(); } $this->addCommaSeparatedArguments($node); @@ -910,12 +1229,31 @@ protected function literalExpression(Literal $node): void case $node instanceof DateTimeOffset: $this->pushStatement('?'); - $this->pushParameter($node->getValue()->get()->format('Y-m-d H:i:s')); + + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLite: + case SQLEntitySet::SQLServer: + $this->pushParameter($node->getValue()->get()->format('Y-m-d H:i:s')); + break; + + default: + $this->pushParameter($node->getValue()->get()->format('Y-m-d H:i:s.v')); + break; + } break; case $node instanceof TimeOfDay: $this->pushStatement('?'); - $this->pushParameter($node->getValue()->get()->format('H:i:s')); + switch ($this->entitySet->getDriver()) { + case SQLEntitySet::SQLite: + case SQLEntitySet::SQLServer: + $this->pushParameter($node->getValue()->get()->format('H:i:s')); + break; + + default: + $this->pushParameter($node->getValue()->get()->format('H:i:s.v')); + break; + } break; case $node instanceof Double: diff --git a/src/Expression/Node/Func/Type/Cast.php b/src/Expression/Node/Func/Type/Cast.php new file mode 100644 index 000000000..1ded242cc --- /dev/null +++ b/src/Expression/Node/Func/Type/Cast.php @@ -0,0 +1,30 @@ +getArguments()[1]->getValue() + ) + ); + } +} diff --git a/src/Expression/Parser/Common.php b/src/Expression/Parser/Common.php index c8b413799..3bbcb0196 100644 --- a/src/Expression/Parser/Common.php +++ b/src/Expression/Parser/Common.php @@ -13,6 +13,7 @@ use Flat3\Lodata\Primitive; use Flat3\Lodata\Type; use Illuminate\Support\Str; +use TypeError; /** * Common expression parser @@ -74,6 +75,13 @@ public static function evaluate(Node $node, ?Entity $entity = null): ?Primitive return null; } break; + + // 5.1.1.4 Canonical Functions + case $node instanceof Node\Func; + if (in_array(null, $argv, true)) { + return null; + } + break; } switch (true) { @@ -466,6 +474,26 @@ public static function evaluate(Node $node, ?Entity $entity = null): ?Primitive case $node instanceof Node\Func\Arithmetic\Round: self::assertTypes($node, $args, [Type\Numeric::class]); return $arg0 ? new $args[0](round($arg0)) : null; + + // 5.1.1.10 Type functions + case $node instanceof Node\Func\Type\Cast: + self::assertTypes($node, $args, [Primitive::class, Type\String_::class]); + + foreach ([ + Type\Binary::class, Type\Boolean::class, Type\Byte::class, Type\Date::class, + Type\DateTimeOffset::class, Type\Decimal::class, Type\Double::class, Type\Duration::class, + Type\Guid::class, Type\Int16::class, Type\Int32::class, Type\Int64::class, + Type\SByte::class, Type\Single::class, Type\String_::class, Type\TimeOfDay::class, + Type\UInt16::class, Type\UInt32::class, Type\UInt64::class, + ] as $type) { + if ($type::identifier === $argv[1]) { + try { + return new $type($arg0); + } catch (TypeError $e) { + return null; + } + } + } } throw new NotImplementedException(); diff --git a/src/Expression/Parser/Filter.php b/src/Expression/Parser/Filter.php index 740fafa9f..13d11b109 100644 --- a/src/Expression/Parser/Filter.php +++ b/src/Expression/Parser/Filter.php @@ -54,6 +54,7 @@ class Filter extends Common // Unary Node\Operator\Comparison\Not_::class, + Node\Func\Type\Cast::class, // Multiplicative Node\Operator\Arithmetic\Mul::class, diff --git a/tests/Filter/Database.php b/tests/Filter/Database.php index 8a943a70b..feaf8f83b 100644 --- a/tests/Filter/Database.php +++ b/tests/Filter/Database.php @@ -46,18 +46,31 @@ public function test_filter_floor() public function test_filter_substring_1() { - $this->markTestSkippedForDriver(SQLEntitySet::SQLite); + if (version_compare(PHP_VERSION, '7.4', '<')) { + $this->markTestSkippedForDriver(SQLEntitySet::SQLite); + } parent::test_filter_substring_1(); } public function test_filter_substring_2() { - $this->markTestSkippedForDriver(SQLEntitySet::SQLite); + if (version_compare(PHP_VERSION, '7.4', '<')) { + $this->markTestSkippedForDriver(SQLEntitySet::SQLite); + } parent::test_filter_substring_2(); } + public function test_filter_cast() + { + if (version_compare(PHP_VERSION, '7.4', '<')) { + $this->markTestSkippedForDriver(SQLEntitySet::SQLite); + } + + parent::test_filter_cast(); + } + public function test_filter_any() { $this->markTestSkippedForDriver(SQLEntitySet::SQLite); diff --git a/tests/Filter/Filter.php b/tests/Filter/Filter.php index 846665715..39ab0cb06 100644 --- a/tests/Filter/Filter.php +++ b/tests/Filter/Filter.php @@ -708,4 +708,22 @@ public function test_filter_time_lt() ->select('name,open_time') ); } + + public function test_filter_cast() + { + $this->assertJsonResponseSnapshot( + (new Request) + ->filter("substring(cast(dob, 'Edm.String'), 0, 6) eq '2000-0'") + ->path($this->entitySetPath) + ); + } + + public function test_filter_search() + { + $this->assertJsonResponseSnapshot( + (new Request) + ->filter("(contains(tolower(cast(name, 'Edm.String')),'alpha')) or (contains(tolower(cast(dob, 'Edm.String')),'alpha'))") + ->path($this->entitySetPath) + ); + } } diff --git a/tests/Helpers/StreamingJsonMatches.php b/tests/Helpers/StreamingJsonMatches.php index c7bf14338..4397fe66b 100644 --- a/tests/Helpers/StreamingJsonMatches.php +++ b/tests/Helpers/StreamingJsonMatches.php @@ -39,13 +39,13 @@ protected function _fail($other, string $description, ComparisonFailure $compari $decodedOther = json_decode($other); if (json_last_error()) { - parent::fail($other, $description); + $this->fail($other, $description); } $decodedValue = json_decode($this->value); if (json_last_error()) { - parent::fail($other, $description); + $this->fail($other, $description); } $comparisonFailure = new ComparisonFailure( @@ -57,6 +57,6 @@ protected function _fail($other, string $description, ComparisonFailure $compari ); } - parent::fail($other, $description, $comparisonFailure); + $this->fail($other, $description, $comparisonFailure); } } \ No newline at end of file diff --git a/tests/Helpers/StreamingJsonMatches/StreamingJsonMatches80.php b/tests/Helpers/StreamingJsonMatches/StreamingJsonMatches80.php index a9b71a035..0f65ad9a7 100644 --- a/tests/Helpers/StreamingJsonMatches/StreamingJsonMatches80.php +++ b/tests/Helpers/StreamingJsonMatches/StreamingJsonMatches80.php @@ -11,6 +11,6 @@ class StreamingJsonMatches80 extends StreamingJsonMatches { public function fail($other, $description, ComparisonFailure $comparisonFailure = null): void { - $this->fail($other, $description, $comparisonFailure); + $this->_fail($other, $description, $comparisonFailure); } } diff --git a/tests/Helpers/StreamingJsonMatches/StreamingJsonMatches81.php b/tests/Helpers/StreamingJsonMatches/StreamingJsonMatches81.php index 7a492e056..a9edb2f47 100644 --- a/tests/Helpers/StreamingJsonMatches/StreamingJsonMatches81.php +++ b/tests/Helpers/StreamingJsonMatches/StreamingJsonMatches81.php @@ -11,6 +11,8 @@ class StreamingJsonMatches81 extends StreamingJsonMatches { public function fail($other, string $description, ComparisonFailure $comparisonFailure = null): never { - $this->fail($other, $description, $comparisonFailure); + $this->_fail($other, $description, $comparisonFailure); + + throw new \Exception(); } } diff --git a/tests/Parser/CastingTest.php b/tests/Parser/CastingTest.php new file mode 100644 index 000000000..9a0325170 --- /dev/null +++ b/tests/Parser/CastingTest.php @@ -0,0 +1,238 @@ +assertCast([2, 'sqlsrv' => '2'], "cast('2', 'Edm.Int32')"); + } + + public function test_02() + { + $this->assertCast([1, 'sqlsrv' => '1'], "cast('1', 'Edm.Int32')"); + } + + public function test_03() + { + $this->assertCast('1', "cast(1, 'Edm.String')"); + } + + public function test_04() + { + $this->assertCast([1, 'pgsql' => true, 'sqlsrv' => '1'], "cast(1, 'Edm.Boolean')"); + } + + public function test_05() + { + $this->assertCast([0, 'pgsql' => false, 'sqlsrv' => '0'], "cast(0, 'Edm.Boolean')"); + } + + public function test_06() + { + $this->assertCast('2000-01-01', "cast('2000-01-01', 'Edm.Date')"); + } + + public function test_07() + { + $this->assertCast( + [ + '2001-01-01 09:01:02.000', + 'sqlite' => '2001-01-01T09:01:02+00:00', + 'pgsql' => '2001-01-01 09:01:02', + 'sqlsrv' => '2001-01-01 09:01:02.0000000 +00:00', + ], + "cast('2001-01-01T09:01:02+00:00', 'Edm.DateTimeOffset')" + ); + } + + public function test_08() + { + $this->assertCast([2.0, 'pgsql' => '2', 'sqlsrv' => '2.0'], "cast(2, 'Edm.Double')"); + } + + public function test_09() + { + $this->assertCast(NotImplementedException::class, "cast('P1D', 'Edm.Duration')"); + } + + public function test_10() + { + $this->assertCast(NotImplementedException::class, "cast('0cfa779c-c41d-11ed-967e-b3bff6c61c95', 'Edm.Guid')"); + } + + public function test_11() + { + $this->assertCast([23, 'sqlsrv' => '23'], "cast('23', 'Edm.Int16')"); + } + + public function test_12() + { + $this->assertCast([233333, 'sqlsrv' => '233333'], "cast('233333', 'Edm.Int32')"); + } + + public function test_13() + { + $this->assertCast([23333333333333, 'sqlsrv' => '23333333333333'], "cast('23333333333333', 'Edm.Int64')"); + } + + public function test_14() + { + $this->assertCast([2, 'sqlsrv' => '2'], "cast('2', 'Edm.SByte')"); + } + + public function test_15() + { + $this->assertCast([2.0, 'pgsql' => '2', 'sqlsrv' => '2.0'], "cast(2, 'Edm.Single')"); + } + + public function test_16() + { + $this->assertCast([2.2, 'pgsql' => '2.2', 'sqlsrv' => '2.2000000000000002'], "cast('2.2', 'Edm.Single')"); + } + + public function test_17() + { + $this->assertCast([ + '23:23:23', + 'mysql' => '23:23:23.000', + 'sqlsrv' => '23:23:23.000' + ], "cast('23:23:23', 'Edm.TimeOfDay')"); + } + + public function test_18() + { + $this->assertCast('2001', "cast(year(2001-01-01T09:01:02.400Z), 'Edm.String')"); + } + + public function test_19() + { + $this->assertCast([-2, 'mysql' => '18446744073709551614', 'sqlsrv' => '-2'], "cast('-2', 'UInt32')"); + } + + public function test_20() + { + $this->assertCast([-99, 'mysql' => '18446744073709551517', 'sqlsrv' => '-99'], "cast('-99', 'UInt64')"); + } + + public function test_21() + { + $this->assertCast([-2, 'mysql' => '18446744073709551614', 'sqlsrv' => '-2'], "cast('-2', 'UInt16')"); + } + + public function test_22() + { + $this->assertCast(null, "cast(null, 'Edm.String')"); + } + + public function test_23() + { + $this->assertCast(null, "cast(null, 'Edm.Boolean')"); + } + + public function test_24() + { + $this->assertCast([ + '2001-01-01 09:01:02.400', + 'sqlite' => '2001-01-01 09:01:02', + 'sqlsrv' => '2001-01-01 09:01:02' + ], "cast(2001-01-01T09:01:02.400Z, 'Edm.String')"); + } + + public function test_25() + { + $this->assertCast([2001, 'sqlsrv' => '2001'], "year(cast('2001-01-01T14:14:00+00:00', 'Edm.DateTimeOffset'))"); + } + + public function test_26() + { + $this->assertCast('2000', "cast(2000, 'Edm.String')"); + } + + public function test_27() + { + $this->assertCast( + '2001-01-01', + "cast(2001-01-01, 'Edm.String')" + ); + } + + public function test_28() + { + $this->assertCast( + ['2001-01-01', 'sqlite' => '2001-01-01 09:01:02'], + "cast(2001-01-01T09:01:02.400Z, 'Edm.Date')" + ); + } + + public function test_29() + { + $this->assertCast( + ['2001-01-01 09:01:02', 'mysql' => '09:01:02.400', 'pgsql' => '09:01:02.4', 'sqlsrv' => '09:01:02.000'], + "cast(2001-01-01T09:01:02.400Z, 'Edm.TimeOfDay')" + ); + } + + public function test_30() + { + $this->assertCast(null, "cast(null, 'Edm.String')"); + } + + public function test_31() + { + $this->assertCast(['hello', 'sqlsrv' => QueryException::class], "cast('hello', 'Edm.Binary')"); + } + + protected function assertCast($expected, string $expression) + { + $set = new SQLEntitySet('test', new EntityType('test')); + $parser = $set->getFilterParser(); + + if (is_array($expected)) { + $expected = array_key_exists($set->getDriver(), $expected) ? $expected[$set->getDriver()] : $expected[0]; + } + + if (is_a($expected, \Exception::class, true)) { + $this->expectException($expected); + } + + $container = new SQLExpression($set); + $parser->pushEntitySet($set); + $tree = $parser->generateTree($expression); + $container->evaluate($tree); + + $result = Arr::first(DB::selectOne('SELECT '.$container->getStatement(), $container->getParameters())); + + if (is_resource($result)) { + $result = stream_get_contents($result); + } + + if (version_compare(PHP_VERSION, '8.1', '<')) { + switch (true) { + case is_float($expected): + $expected = number_format($expected, 1, '.', ''); + break; + + case is_null($expected): + break; + + default: + $expected = (string) $expected; + break; + } + } + + $this->assertSame($expected, $result); + } +} diff --git a/tests/Parser/CommonExpressionTest.php b/tests/Parser/CommonExpressionTest.php index 555571be4..31548b7b6 100644 --- a/tests/Parser/CommonExpressionTest.php +++ b/tests/Parser/CommonExpressionTest.php @@ -693,7 +693,7 @@ public function test_141() public function test_141a() { - $this->assertSameExpression(0, "length(null)"); + $this->assertNullExpression("length(null)"); } public function test_142() @@ -913,6 +913,152 @@ public function test_192() $this->assertSameExpression(5.0, 'round(4.5)'); } + public function test_200() + { + $this->assertSameExpression(1, "cast('1', 'Edm.Int32')"); + } + + public function test_201() + { + $this->assertSameExpression('1', "cast(1, 'Edm.String')"); + } + + public function test_202() + { + $this->assertTrueExpression("cast('true', 'Edm.Boolean')"); + } + + public function test_203() + { + $this->assertFalseExpression("cast('false', 'Edm.Boolean')"); + } + + public function test_204() + { + $this->assertSameExpression('2000-01-01', "cast('2000-01-01', 'Edm.Date')"); + } + + public function test_205() + { + $this->assertSameExpression( + '2001-01-01T09:01:02+00:00', + "cast('2001-01-01T09:01:02+00:00', 'Edm.DateTimeOffset')" + ); + } + + public function test_206() + { + $this->assertSameExpression(2.0, "cast(2, 'Edm.Double')"); + } + + public function test_207() + { + $this->assertSameExpression(86400.0, "cast('P1D', 'Edm.Duration')"); + } + + public function test_208() + { + $this->assertSameExpression( + '0CFA779C-C41D-11ED-967E-B3BFF6C61C95', + "cast('0cfa779c-c41d-11ed-967e-b3bff6c61c95', 'Edm.Guid')" + ); + } + + public function test_209() + { + $this->assertSameExpression(23, "cast('23', 'Edm.Int16')"); + } + + public function test_210() + { + $this->assertSameExpression(233333, "cast('233333', 'Edm.Int32')"); + } + + public function test_211() + { + $this->assertSameExpression(23333333333333, "cast('23333333333333', 'Edm.Int64')"); + } + + public function test_212() + { + $this->assertSameExpression(2, "cast('2', 'Edm.SByte')"); + } + + public function test_213() + { + $this->assertSameExpression(2.0, "cast(2, 'Edm.Single')"); + } + + public function test_214() + { + $this->assertSameExpression(2.2, "cast('2.2', 'Edm.Single')"); + } + + public function test_215() + { + $this->assertSameExpression('23:23:23.000000', "cast('23:23:23', 'Edm.TimeOfDay')"); + } + + public function test_220() + { + $this->assertSameExpression('2001', "cast(year(2001-01-01T09:01:02.400Z), 'Edm.String')"); + } + + public function test_221() + { + $this->assertSameExpression(4294967294, "cast('-2', 'UInt32')"); + } + + public function test_222() + { + $this->assertSameExpression(99, "cast('-99', 'UInt64')"); + } + + public function test_223() + { + $this->assertSameExpression(65534, "cast('-2', 'UInt16')"); + } + + public function test_231() + { + $this->assertNullExpression("cast(null, 'Edm.String')"); + } + + public function test_232() + { + $this->assertNullExpression("cast(null, 'Edm.Boolean')"); + } + + public function test_233() + { + $this->assertSameExpression('2001-01-01 09:01:02', "cast(2001-01-01T09:01:02.400Z, 'Edm.String')"); + } + + public function test_234() + { + $this->assertSameExpression(2001, "year(cast('2001-01-01T14:14:00+00:00', 'Edm.DateTimeOffset'))"); + } + + public function test_240() + { + $this->assertSameExpression('2000', "cast(2000, 'Edm.String')"); + } + + public function test_241() + { + $this->assertSameExpression('2001-01-01 00:00:00', "cast(2001-01-01, 'Edm.String')"); + } + + public function test_242() + { + $this->assertSameExpression('2001-01-01', "cast(2001-01-01T09:01:02.400Z, 'Edm.Date')"); + } + + public function test_243() + { + $this->assertSameExpression('09:01:02.400000', "cast(2001-01-01T09:01:02.400Z, 'Edm.TimeOfDay')"); + } + public function evaluate(string $expression) { $parser = new Filter(); diff --git a/tests/Setup/InvalidModelTest.php b/tests/Setup/InvalidModelTest.php index 1eee32fc1..b493bc69b 100644 --- a/tests/Setup/InvalidModelTest.php +++ b/tests/Setup/InvalidModelTest.php @@ -15,6 +15,7 @@ class InvalidModelTest extends TestCase public function testMissingPrimaryKey() { if ($this->getConnection()->getDriverName() !== SQLEntitySet::SQLite) { + $this->expectNotToPerformAssertions(); return; } diff --git a/tests/__snapshots__/Filter/EloquentTest__test_filter_cast__1.json b/tests/__snapshots__/Filter/EloquentTest__test_filter_cast__1.json new file mode 100644 index 000000000..25af303c1 --- /dev/null +++ b/tests/__snapshots__/Filter/EloquentTest__test_filter_cast__1.json @@ -0,0 +1,22 @@ +{ + "@context": "http://localhost/odata/$metadata#Passengers", + "value": [ + { + "id": 1, + "flight_id": 1, + "name": "Alpha", + "dob": "2000-01-01T04:04:04+00:00", + "age": 4, + "chips": true, + "dq": "2000-01-01", + "in_role": "P1DT0S", + "open_time": "05:05:05.000000", + "colour": "Green", + "sock_colours": "Green,Blue", + "emails": [ + "alpha@example.com", + "alpha@beta.com" + ] + } + ] +} diff --git a/tests/__snapshots__/Filter/EloquentTest__test_filter_search__1.json b/tests/__snapshots__/Filter/EloquentTest__test_filter_search__1.json new file mode 100644 index 000000000..25af303c1 --- /dev/null +++ b/tests/__snapshots__/Filter/EloquentTest__test_filter_search__1.json @@ -0,0 +1,22 @@ +{ + "@context": "http://localhost/odata/$metadata#Passengers", + "value": [ + { + "id": 1, + "flight_id": 1, + "name": "Alpha", + "dob": "2000-01-01T04:04:04+00:00", + "age": 4, + "chips": true, + "dq": "2000-01-01", + "in_role": "P1DT0S", + "open_time": "05:05:05.000000", + "colour": "Green", + "sock_colours": "Green,Blue", + "emails": [ + "alpha@example.com", + "alpha@beta.com" + ] + } + ] +} diff --git a/tests/__snapshots__/Filter/KeyedCollectionTest__test_filter_cast__1.json b/tests/__snapshots__/Filter/KeyedCollectionTest__test_filter_cast__1.json new file mode 100644 index 000000000..a5e712292 --- /dev/null +++ b/tests/__snapshots__/Filter/KeyedCollectionTest__test_filter_cast__1.json @@ -0,0 +1,22 @@ +{ + "@context": "http://localhost/odata/$metadata#passengers", + "value": [ + { + "id": "alpha", + "name": "Alpha", + "age": 4, + "dob": "2000-01-01T04:04:04+00:00", + "chips": true, + "dq": "2000-01-01", + "in_role": "P1DT0S", + "open_time": "05:05:05.000000", + "flight_id": 1, + "colour": "Green", + "sock_colours": "Green,Blue", + "emails": [ + "alpha@example.com", + "alpha@beta.com" + ] + } + ] +} diff --git a/tests/__snapshots__/Filter/KeyedCollectionTest__test_filter_search__1.json b/tests/__snapshots__/Filter/KeyedCollectionTest__test_filter_search__1.json new file mode 100644 index 000000000..a5e712292 --- /dev/null +++ b/tests/__snapshots__/Filter/KeyedCollectionTest__test_filter_search__1.json @@ -0,0 +1,22 @@ +{ + "@context": "http://localhost/odata/$metadata#passengers", + "value": [ + { + "id": "alpha", + "name": "Alpha", + "age": 4, + "dob": "2000-01-01T04:04:04+00:00", + "chips": true, + "dq": "2000-01-01", + "in_role": "P1DT0S", + "open_time": "05:05:05.000000", + "flight_id": 1, + "colour": "Green", + "sock_colours": "Green,Blue", + "emails": [ + "alpha@example.com", + "alpha@beta.com" + ] + } + ] +} diff --git a/tests/__snapshots__/Filter/NumericCollectionTest__test_filter_cast__1.json b/tests/__snapshots__/Filter/NumericCollectionTest__test_filter_cast__1.json new file mode 100644 index 000000000..0db62dc7a --- /dev/null +++ b/tests/__snapshots__/Filter/NumericCollectionTest__test_filter_cast__1.json @@ -0,0 +1,22 @@ +{ + "@context": "http://localhost/odata/$metadata#passengers", + "value": [ + { + "id": 0, + "name": "Alpha", + "age": 4, + "dob": "2000-01-01T04:04:04+00:00", + "chips": true, + "dq": "2000-01-01", + "in_role": "P1DT0S", + "open_time": "05:05:05.000000", + "flight_id": 1, + "colour": "Green", + "sock_colours": "Green,Blue", + "emails": [ + "alpha@example.com", + "alpha@beta.com" + ] + } + ] +} diff --git a/tests/__snapshots__/Filter/NumericCollectionTest__test_filter_search__1.json b/tests/__snapshots__/Filter/NumericCollectionTest__test_filter_search__1.json new file mode 100644 index 000000000..0db62dc7a --- /dev/null +++ b/tests/__snapshots__/Filter/NumericCollectionTest__test_filter_search__1.json @@ -0,0 +1,22 @@ +{ + "@context": "http://localhost/odata/$metadata#passengers", + "value": [ + { + "id": 0, + "name": "Alpha", + "age": 4, + "dob": "2000-01-01T04:04:04+00:00", + "chips": true, + "dq": "2000-01-01", + "in_role": "P1DT0S", + "open_time": "05:05:05.000000", + "flight_id": 1, + "colour": "Green", + "sock_colours": "Green,Blue", + "emails": [ + "alpha@example.com", + "alpha@beta.com" + ] + } + ] +} diff --git a/tests/__snapshots__/Filter/SQLTest__test_filter_cast__1.json b/tests/__snapshots__/Filter/SQLTest__test_filter_cast__1.json new file mode 100644 index 000000000..e6a3c366b --- /dev/null +++ b/tests/__snapshots__/Filter/SQLTest__test_filter_cast__1.json @@ -0,0 +1,22 @@ +{ + "@context": "http://localhost/odata/$metadata#passengers", + "value": [ + { + "id": 1, + "name": "Alpha", + "age": 4, + "dob": "2000-01-01T04:04:04+00:00", + "chips": true, + "dq": "2000-01-01", + "in_role": "P1DT0S", + "open_time": "05:05:05.000000", + "flight_id": 1, + "colour": "Green", + "sock_colours": "Green,Blue", + "emails": [ + "alpha@example.com", + "alpha@beta.com" + ] + } + ] +} diff --git a/tests/__snapshots__/Filter/SQLTest__test_filter_search__1.json b/tests/__snapshots__/Filter/SQLTest__test_filter_search__1.json new file mode 100644 index 000000000..e6a3c366b --- /dev/null +++ b/tests/__snapshots__/Filter/SQLTest__test_filter_search__1.json @@ -0,0 +1,22 @@ +{ + "@context": "http://localhost/odata/$metadata#passengers", + "value": [ + { + "id": 1, + "name": "Alpha", + "age": 4, + "dob": "2000-01-01T04:04:04+00:00", + "chips": true, + "dq": "2000-01-01", + "in_role": "P1DT0S", + "open_time": "05:05:05.000000", + "flight_id": 1, + "colour": "Green", + "sock_colours": "Green,Blue", + "emails": [ + "alpha@example.com", + "alpha@beta.com" + ] + } + ] +} diff --git a/tests/__snapshots__/Parser/FilterTest__test_40__2.txt b/tests/__snapshots__/Parser/FilterTest__test_40__2.txt index 7f07e828a..cdfc3b25d 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_40__2.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_40__2.txt @@ -1,3 +1,3 @@ expression: origin eq 2000-01-01T12:34:59Z result: ( `flights`.`origin` = ? ) -parameters: 2000-01-01 12:34:59 +parameters: 2000-01-01 12:34:59.000 diff --git a/tests/__snapshots__/Parser/FilterTest__test_40__3.txt b/tests/__snapshots__/Parser/FilterTest__test_40__3.txt index 83667af97..83fc569ac 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_40__3.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_40__3.txt @@ -1,3 +1,3 @@ expression: origin eq 2000-01-01T12:34:59Z result: ( "flights"."origin" = ? ) -parameters: 2000-01-01 12:34:59 +parameters: 2000-01-01 12:34:59.000 diff --git a/tests/__snapshots__/Parser/FilterTest__test_41__2.txt b/tests/__snapshots__/Parser/FilterTest__test_41__2.txt index a7f4bba6e..8369a51b4 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_41__2.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_41__2.txt @@ -1,3 +1,3 @@ expression: origin eq 04:11:12 result: ( `flights`.`origin` = ? ) -parameters: 04:11:12 +parameters: 04:11:12.000 diff --git a/tests/__snapshots__/Parser/FilterTest__test_41__3.txt b/tests/__snapshots__/Parser/FilterTest__test_41__3.txt index d07d6219f..c8c4dd7bc 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_41__3.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_41__3.txt @@ -1,3 +1,3 @@ expression: origin eq 04:11:12 result: ( "flights"."origin" = ? ) -parameters: 04:11:12 +parameters: 04:11:12.000 diff --git a/tests/__snapshots__/Parser/FilterTest__test_48__3.txt b/tests/__snapshots__/Parser/FilterTest__test_48__3.txt index 0940de942..c1d3caf62 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_48__3.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_48__3.txt @@ -1,3 +1,3 @@ expression: day(origin) eq 4 -result: ( DATE_PART( 'DAY', "flights"."origin" ) = ? ) +result: ( DATE_PART( 'DAY', "flights"."origin" ::timestamp)::integer = ? ) parameters: 4 diff --git a/tests/__snapshots__/Parser/FilterTest__test_49__3.txt b/tests/__snapshots__/Parser/FilterTest__test_49__3.txt index 194b58d2a..9ca21fb3c 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_49__3.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_49__3.txt @@ -1,3 +1,3 @@ expression: hour(origin) eq 3 -result: ( DATE_PART( 'HOUR', "flights"."origin" ) = ? ) +result: ( DATE_PART( 'HOUR', "flights"."origin" ::timestamp)::integer = ? ) parameters: 3 diff --git a/tests/__snapshots__/Parser/FilterTest__test_4a__3.txt b/tests/__snapshots__/Parser/FilterTest__test_4a__3.txt index 48c7d84a0..271f96fb1 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_4a__3.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_4a__3.txt @@ -1,3 +1,3 @@ expression: minute(origin) eq 33 -result: ( DATE_PART( 'MINUTE', "flights"."origin" ) = ? ) +result: ( DATE_PART( 'MINUTE', "flights"."origin" ::timestamp)::integer = ? ) parameters: 33 diff --git a/tests/__snapshots__/Parser/FilterTest__test_4b__3.txt b/tests/__snapshots__/Parser/FilterTest__test_4b__3.txt index c62d3b33a..70cd4466f 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_4b__3.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_4b__3.txt @@ -1,3 +1,3 @@ expression: month(origin) eq 11 -result: ( DATE_PART( 'MONTH', "flights"."origin" ) = ? ) +result: ( DATE_PART( 'MONTH', "flights"."origin" ::timestamp)::integer = ? ) parameters: 11 diff --git a/tests/__snapshots__/Parser/FilterTest__test_4c__2.txt b/tests/__snapshots__/Parser/FilterTest__test_4c__2.txt index f223daacc..5f93c395d 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_4c__2.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_4c__2.txt @@ -1,3 +1,3 @@ expression: now() eq 10:00:00 result: ( NOW( ) = ? ) -parameters: 10:00:00 +parameters: 10:00:00.000 diff --git a/tests/__snapshots__/Parser/FilterTest__test_4c__3.txt b/tests/__snapshots__/Parser/FilterTest__test_4c__3.txt index f223daacc..5f93c395d 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_4c__3.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_4c__3.txt @@ -1,3 +1,3 @@ expression: now() eq 10:00:00 result: ( NOW( ) = ? ) -parameters: 10:00:00 +parameters: 10:00:00.000 diff --git a/tests/__snapshots__/Parser/FilterTest__test_4d__3.txt b/tests/__snapshots__/Parser/FilterTest__test_4d__3.txt index 624411001..f54d3265c 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_4d__3.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_4d__3.txt @@ -1,3 +1,3 @@ expression: second(origin) eq 44 -result: ( DATE_PART( 'SECOND', "flights"."origin" ) = ? ) +result: ( DATE_PART( 'SECOND', "flights"."origin" ::timestamp)::integer = ? ) parameters: 44 diff --git a/tests/__snapshots__/Parser/FilterTest__test_4e__2.txt b/tests/__snapshots__/Parser/FilterTest__test_4e__2.txt index b698f5803..441e3116d 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_4e__2.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_4e__2.txt @@ -1,3 +1,3 @@ expression: time(origin) eq 10:00:00 result: ( TIME( `flights`.`origin` ) = ? ) -parameters: 10:00:00 +parameters: 10:00:00.000 diff --git a/tests/__snapshots__/Parser/FilterTest__test_4e__3.txt b/tests/__snapshots__/Parser/FilterTest__test_4e__3.txt index 1022f5b27..8c720d090 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_4e__3.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_4e__3.txt @@ -1,3 +1,3 @@ expression: time(origin) eq 10:00:00 result: ( ( "flights"."origin" )::time = ? ) -parameters: 10:00:00 +parameters: 10:00:00.000 diff --git a/tests/__snapshots__/Parser/FilterTest__test_4f__3.txt b/tests/__snapshots__/Parser/FilterTest__test_4f__3.txt index 80a82fedd..1d16008f3 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_4f__3.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_4f__3.txt @@ -1,3 +1,3 @@ expression: year(origin) eq 1999 -result: ( DATE_PART( 'YEAR', "flights"."origin" ) = ? ) +result: ( DATE_PART( 'YEAR', "flights"."origin" ::timestamp)::integer = ? ) parameters: 1999 diff --git a/tests/__snapshots__/Parser/FilterTest__test_53__2.txt b/tests/__snapshots__/Parser/FilterTest__test_53__2.txt index 05dba5c08..2dd488561 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_53__2.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_53__2.txt @@ -1,3 +1,3 @@ expression: origin eq 2000-01-01T12:34:59+01:00 result: ( `flights`.`origin` = ? ) -parameters: 2000-01-01 12:34:59 +parameters: 2000-01-01 12:34:59.000 diff --git a/tests/__snapshots__/Parser/FilterTest__test_53__3.txt b/tests/__snapshots__/Parser/FilterTest__test_53__3.txt index 9445833de..6efb41bbd 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_53__3.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_53__3.txt @@ -1,3 +1,3 @@ expression: origin eq 2000-01-01T12:34:59+01:00 result: ( "flights"."origin" = ? ) -parameters: 2000-01-01 12:34:59 +parameters: 2000-01-01 12:34:59.000 diff --git a/tests/__snapshots__/Parser/FilterTest__test_54__2.txt b/tests/__snapshots__/Parser/FilterTest__test_54__2.txt index 873c512f6..8a4613349 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_54__2.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_54__2.txt @@ -1,3 +1,3 @@ expression: origin eq 2000-01-01T12:34:59-01:00 result: ( `flights`.`origin` = ? ) -parameters: 2000-01-01 12:34:59 +parameters: 2000-01-01 12:34:59.000 diff --git a/tests/__snapshots__/Parser/FilterTest__test_54__3.txt b/tests/__snapshots__/Parser/FilterTest__test_54__3.txt index 6420a0cca..49c70bfa6 100644 --- a/tests/__snapshots__/Parser/FilterTest__test_54__3.txt +++ b/tests/__snapshots__/Parser/FilterTest__test_54__3.txt @@ -1,3 +1,3 @@ expression: origin eq 2000-01-01T12:34:59-01:00 result: ( "flights"."origin" = ? ) -parameters: 2000-01-01 12:34:59 +parameters: 2000-01-01 12:34:59.000