From 53087fd6a4c37674132cee9785f3a9fb32781971 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Fri, 8 Sep 2023 08:57:28 +0400 Subject: [PATCH] feat(graphql/@searchBy): Scout support for `NotIn` operator (`laravel/scout:>=10.3.0` required). --- packages/graphql/composer.json | 1 + .../src/SearchBy/Directives/DirectiveTest.php | 14 +- ...-expected-scout\342\211\24510.3.0.graphql" | 2352 +++++++++++++++++ .../SearchBy/Operators/Comparison/NotIn.php | 24 +- .../Operators/Comparison/NotInTest.php | 110 + .../Operators/Traits/ScoutSupport.php | 16 +- 6 files changed, 2507 insertions(+), 10 deletions(-) create mode 100644 "packages/graphql/src/SearchBy/Directives/DirectiveTest~full-expected-scout\342\211\24510.3.0.graphql" diff --git a/packages/graphql/composer.json b/packages/graphql/composer.json index 039b4ccea..bc42e1336 100644 --- a/packages/graphql/composer.json +++ b/packages/graphql/composer.json @@ -20,6 +20,7 @@ "require": { "php": "^8.1|^8.2", "ext-mbstring": "*", + "composer/semver": "^3.2", "laravel/framework": "^9.21.0|^10.0.0", "nuwave/lighthouse": "^6.5.0", "lastdragon-ru/lara-asp-core": "self.version", diff --git a/packages/graphql/src/SearchBy/Directives/DirectiveTest.php b/packages/graphql/src/SearchBy/Directives/DirectiveTest.php index 9b73712b8..f89202c33 100644 --- a/packages/graphql/src/SearchBy/Directives/DirectiveTest.php +++ b/packages/graphql/src/SearchBy/Directives/DirectiveTest.php @@ -3,6 +3,8 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives; use Closure; +use Composer\InstalledVersions; +use Composer\Semver\VersionParser; use Exception; use GraphQL\Language\AST\TypeDefinitionNode; use GraphQL\Language\Parser; @@ -360,9 +362,15 @@ public static function dataProviderManipulateArgDefinition(): array { return [ 'full' => [ static function (self $test): GraphQLExpected { - return (new GraphQLExpected( - $test::getTestData()->file('~full-expected.graphql'), - )); + $satisfies = static function (string $version): bool { + return InstalledVersions::satisfies(new VersionParser(), 'laravel/scout', $version); + }; + $file = match (true) { + $satisfies('>=10.3.0') => '~full-expected-scout≥10.3.0.graphql', + default => '~full-expected.graphql', + }; + + return new GraphQLExpected($test::getTestData()->file($file)); }, '~full.graphql', static function (TestCase $test): void { diff --git "a/packages/graphql/src/SearchBy/Directives/DirectiveTest~full-expected-scout\342\211\24510.3.0.graphql" "b/packages/graphql/src/SearchBy/Directives/DirectiveTest~full-expected-scout\342\211\24510.3.0.graphql" new file mode 100644 index 000000000..1fd95c913 --- /dev/null +++ "b/packages/graphql/src/SearchBy/Directives/DirectiveTest~full-expected-scout\342\211\24510.3.0.graphql" @@ -0,0 +1,2352 @@ +""" +Use Input as Search Conditions for the current Builder. +""" +directive @searchBy +on + | ARGUMENT_DEFINITION + +""" +Marks that field/definition should be excluded from search. +""" +directive @searchByIgnored +on + | ENUM + | FIELD_DEFINITION + | INPUT_FIELD_DEFINITION + | INPUT_OBJECT + | OBJECT + | SCALAR + +directive @searchByOperatorAllOf +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorAnyOf +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorBetween +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorBitwiseAnd +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorBitwiseLeftShift +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorBitwiseOr +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorBitwiseRightShift +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorBitwiseXor +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorCondition +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorContains +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorEndsWith +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorEqual +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorGreaterThan +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorGreaterThanOrEqual +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorIn +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorIsNotNull +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorIsNull +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorLessThan +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorLessThanOrEqual +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorLike +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorNot +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorNotBetween +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorNotEqual +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorNotIn +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorNotLike +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorProperty +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorRelation +on + | ENUM + | FIELD_DEFINITION + | INPUT_FIELD_DEFINITION + | SCALAR + +directive @searchByOperatorStartsWith +on + | ENUM + | INPUT_FIELD_DEFINITION + | SCALAR + +""" +Extends the list of operators by the operators from the specified `type`. +""" +directive @searchByOperators( + type: String! +) +on + | ENUM + | SCALAR + +enum EnumA { + one + two +} + +enum EnumIgnored +@searchByIgnored +{ + one +} + +enum SearchByTypeFlag { + yes +} + +""" +Conditions for the related objects (`has()`/`doesntHave()`) for `input NestedA`. + +See also: +* https://laravel.com/docs/eloquent-relationships#querying-relationship-existence +* https://laravel.com/docs/eloquent-relationships#querying-relationship-absence +""" +input SearchByComplexRelationNestedA { + """ + Count conditions. + """ + count: SearchByScalarInt + + """ + Alias for `count: {greaterThanOrEqual: 1}`. Will be ignored if `count` used. + """ + exists: Boolean + + """ + Alias for `count: {lessThan: 1}`. Will be ignored if `count` used. + """ + notExists: Boolean! = false + + """ + Additional conditions. + """ + where: SearchByConditionNestedA +} + +""" +Conditions for the related objects (`has()`/`doesntHave()`) for `input NestedB`. + +See also: +* https://laravel.com/docs/eloquent-relationships#querying-relationship-existence +* https://laravel.com/docs/eloquent-relationships#querying-relationship-absence +""" +input SearchByComplexRelationNestedB { + """ + Count conditions. + """ + count: SearchByScalarInt + + """ + Alias for `count: {greaterThanOrEqual: 1}`. Will be ignored if `count` used. + """ + exists: Boolean + + """ + Alias for `count: {lessThan: 1}`. Will be ignored if `count` used. + """ + notExists: Boolean! = false + + """ + Additional conditions. + """ + where: SearchByConditionNestedB +} + +""" +Conditions for the related objects (`has()`/`doesntHave()`) for `input NestedC`. + +See also: +* https://laravel.com/docs/eloquent-relationships#querying-relationship-existence +* https://laravel.com/docs/eloquent-relationships#querying-relationship-absence +""" +input SearchByComplexRelationNestedC { + """ + Count conditions. + """ + count: SearchByScalarInt + + """ + Alias for `count: {greaterThanOrEqual: 1}`. Will be ignored if `count` used. + """ + exists: Boolean + + """ + Alias for `count: {lessThan: 1}`. Will be ignored if `count` used. + """ + notExists: Boolean! = false + + """ + Additional conditions. + """ + where: SearchByConditionNestedC +} + +""" +Conditions for the related objects (`has()`/`doesntHave()`) for `type ObjectNested`. + +See also: +* https://laravel.com/docs/eloquent-relationships#querying-relationship-existence +* https://laravel.com/docs/eloquent-relationships#querying-relationship-absence +""" +input SearchByComplexRelationObjectNested { + """ + Count conditions. + """ + count: SearchByScalarInt + + """ + Alias for `count: {greaterThanOrEqual: 1}`. Will be ignored if `count` used. + """ + exists: Boolean + + """ + Alias for `count: {lessThan: 1}`. Will be ignored if `count` used. + """ + notExists: Boolean! = false + + """ + Additional conditions. + """ + where: SearchByConditionObjectNested +} + +""" +Available conditions for `input InputA` (only one property allowed at a time). +""" +input SearchByConditionInputA { + """ + All of the conditions must be true. + """ + allOf: [SearchByConditionInputA!] + @searchByOperatorAllOf + + """ + Any of the conditions must be true. + """ + anyOf: [SearchByConditionInputA!] + @searchByOperatorAnyOf + + """ + Property condition. + """ + booleanScalar: SearchByScalarBooleanOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + booleanScalarNotNull: SearchByScalarBoolean + @searchByOperatorProperty + + """ + Property condition. + """ + customScalar: SearchByScalarDateOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + customScalarList: SearchByScalarDate + @searchByOperatorProperty + + """ + Property condition. + """ + customScalarNonNull: SearchByScalarDate + @searchByOperatorProperty + + """ + Property condition. + """ + customScalarOperators: SearchByScalarScalarCustomOrNull + @searchByOperatorProperty + + """ + Description should be used. + """ + description: SearchByScalarIDOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + enum: SearchByEnumEnumAOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + enumNotNull: SearchByEnumEnumA + @searchByOperatorProperty + + """ + Property condition. + """ + fieldRenamed: SearchByScalarIDOrNull + @searchByOperatorProperty + @rename( + attribute: "renamed" + ) + + """ + Property condition. + """ + floatScalar: SearchByScalarFloatOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + floatScalarNotNull: SearchByScalarFloat + @searchByOperatorProperty + + """ + Property condition. + """ + idScalar: SearchByScalarIDOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + idScalarNotNull: SearchByScalarID + @searchByOperatorProperty + + """ + Property condition. + """ + intScalar: SearchByScalarIntOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + intScalarNotNull: SearchByScalarInt + @searchByOperatorProperty + + """ + Relationship condition. + """ + nested: SearchByComplexRelationNestedA + @searchByOperatorRelation + + """ + Relationship condition. + """ + nestedNotNull: SearchByComplexRelationNestedA + @searchByOperatorRelation + + """ + Not. + """ + not: SearchByConditionInputA + @searchByOperatorNot + + """ + Property condition. + """ + stringScalar: SearchByScalarStringOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + stringScalarNotNull: SearchByScalarString + @searchByOperatorProperty +} + +""" +Available conditions for `input InputB` (only one property allowed at a time). +""" +input SearchByConditionInputB { + """ + All of the conditions must be true. + """ + allOf: [SearchByConditionInputB!] + @searchByOperatorAllOf + + """ + Any of the conditions must be true. + """ + anyOf: [SearchByConditionInputB!] + @searchByOperatorAnyOf + + """ + Property condition. + """ + id: SearchByScalarIDOrNull + @searchByOperatorProperty + + """ + Not. + """ + not: SearchByConditionInputB + @searchByOperatorNot +} + +""" +Available conditions for `input NestedA` (only one property allowed at a time). +""" +input SearchByConditionNestedA { + """ + All of the conditions must be true. + """ + allOf: [SearchByConditionNestedA!] + @searchByOperatorAllOf + + """ + Any of the conditions must be true. + """ + anyOf: [SearchByConditionNestedA!] + @searchByOperatorAnyOf + + """ + Relationship condition. + """ + nested: SearchByComplexRelationNestedA + @searchByOperatorRelation + + """ + Not. + """ + not: SearchByConditionNestedA + @searchByOperatorNot + + """ + Property condition. + """ + value: SearchByScalarStringOrNull + @searchByOperatorProperty +} + +""" +Available conditions for `input NestedB` (only one property allowed at a time). +""" +input SearchByConditionNestedB { + """ + All of the conditions must be true. + """ + allOf: [SearchByConditionNestedB!] + @searchByOperatorAllOf + + """ + Any of the conditions must be true. + """ + anyOf: [SearchByConditionNestedB!] + @searchByOperatorAnyOf + + """ + Relationship condition. + """ + nested: SearchByComplexRelationNestedC + @searchByOperatorRelation + + """ + Not. + """ + not: SearchByConditionNestedB + @searchByOperatorNot +} + +""" +Available conditions for `input NestedC` (only one property allowed at a time). +""" +input SearchByConditionNestedC { + """ + All of the conditions must be true. + """ + allOf: [SearchByConditionNestedC!] + @searchByOperatorAllOf + + """ + Any of the conditions must be true. + """ + anyOf: [SearchByConditionNestedC!] + @searchByOperatorAnyOf + + """ + Relationship condition. + """ + nested: SearchByComplexRelationNestedB + @searchByOperatorRelation + + """ + Not. + """ + not: SearchByConditionNestedC + @searchByOperatorNot +} + +""" +Available conditions for `type Object` (only one property allowed at a time). +""" +input SearchByConditionObject { + """ + All of the conditions must be true. + """ + allOf: [SearchByConditionObject!] + @searchByOperatorAllOf + + """ + Any of the conditions must be true. + """ + anyOf: [SearchByConditionObject!] + @searchByOperatorAnyOf + + """ + Property condition. + """ + booleanScalar: SearchByScalarBooleanOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + booleanScalarNotNull: SearchByScalarBoolean + @searchByOperatorProperty + + """ + Property condition. + """ + customScalar: SearchByScalarDateOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + customScalarList: SearchByScalarDate + @searchByOperatorProperty + + """ + Property condition. + """ + customScalarNonNull: SearchByScalarDate + @searchByOperatorProperty + + """ + Property condition. + """ + customScalarOperators: SearchByScalarScalarCustomOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + description: SearchByScalarIDOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + enum: SearchByEnumEnumAOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + enumNotNull: SearchByEnumEnumA + @searchByOperatorProperty + + """ + Property condition. + """ + fieldRenamed: SearchByScalarIDOrNull + @searchByOperatorProperty + @rename( + attribute: "renamed" + ) + + """ + Property condition. + """ + floatScalar: SearchByScalarFloatOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + floatScalarNotNull: SearchByScalarFloat + @searchByOperatorProperty + + """ + Property condition. + """ + idScalar: SearchByScalarIDOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + idScalarNotNull: SearchByScalarID + @searchByOperatorProperty + + """ + Property condition. + """ + intScalar: SearchByScalarIntOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + intScalarNotNull: SearchByScalarInt + @searchByOperatorProperty + + """ + Relationship condition. + """ + nested: SearchByComplexRelationObjectNested + @searchByOperatorRelation + + """ + Relationship condition. + """ + nestedNotNull: SearchByComplexRelationObjectNested + @searchByOperatorRelation + + """ + Not. + """ + not: SearchByConditionObject + @searchByOperatorNot + + """ + Property condition. + """ + stringScalar: SearchByScalarStringOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + stringScalarNotNull: SearchByScalarString + @searchByOperatorProperty +} + +""" +Available conditions for `interface ObjectInterface` (only one property allowed at a time). +""" +input SearchByConditionObjectInterface { + """ + All of the conditions must be true. + """ + allOf: [SearchByConditionObjectInterface!] + @searchByOperatorAllOf + + """ + Any of the conditions must be true. + """ + anyOf: [SearchByConditionObjectInterface!] + @searchByOperatorAnyOf + + """ + Property condition. + """ + booleanScalar: SearchByScalarBooleanOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + booleanScalarNotNull: SearchByScalarBoolean + @searchByOperatorProperty + + """ + Property condition. + """ + customScalar: SearchByScalarDateOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + customScalarList: SearchByScalarDate + @searchByOperatorProperty + + """ + Property condition. + """ + customScalarNonNull: SearchByScalarDate + @searchByOperatorProperty + + """ + Property condition. + """ + customScalarOperators: SearchByScalarScalarCustomOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + description: SearchByScalarIDOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + enum: SearchByEnumEnumAOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + enumNotNull: SearchByEnumEnumA + @searchByOperatorProperty + + """ + Property condition. + """ + fieldRenamed: SearchByScalarIDOrNull + @searchByOperatorProperty + @rename( + attribute: "renamed" + ) + + """ + Property condition. + """ + floatScalar: SearchByScalarFloatOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + floatScalarNotNull: SearchByScalarFloat + @searchByOperatorProperty + + """ + Property condition. + """ + idScalar: SearchByScalarIDOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + idScalarNotNull: SearchByScalarID + @searchByOperatorProperty + + """ + Property condition. + """ + intScalar: SearchByScalarIntOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + intScalarNotNull: SearchByScalarInt + @searchByOperatorProperty + + """ + Relationship condition. + """ + nested: SearchByComplexRelationObjectNested + @searchByOperatorRelation + + """ + Relationship condition. + """ + nestedNotNull: SearchByComplexRelationObjectNested + @searchByOperatorRelation + + """ + Not. + """ + not: SearchByConditionObjectInterface + @searchByOperatorNot + + """ + Property condition. + """ + stringScalar: SearchByScalarStringOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + stringScalarNotNull: SearchByScalarString + @searchByOperatorProperty +} + +""" +Available conditions for `type ObjectNested` (only one property allowed at a time). +""" +input SearchByConditionObjectNested { + """ + All of the conditions must be true. + """ + allOf: [SearchByConditionObjectNested!] + @searchByOperatorAllOf + + """ + Any of the conditions must be true. + """ + anyOf: [SearchByConditionObjectNested!] + @searchByOperatorAnyOf + + """ + Relationship condition. + """ + nested: SearchByComplexRelationObjectNested + @searchByOperatorRelation + + """ + Not. + """ + not: SearchByConditionObjectNested + @searchByOperatorNot + + """ + Property condition. + """ + value: SearchByScalarStringOrNull + @searchByOperatorProperty +} + +""" +Available operators for `enum EnumA` (only one operator allowed at a time). +""" +input SearchByEnumEnumA { + """ + Equal (`=`). + """ + equal: EnumA + @searchByOperatorEqual + + """ + Within a set of values. + """ + in: [EnumA!] + @searchByOperatorIn + + """ + Not Equal (`!=`). + """ + notEqual: EnumA + @searchByOperatorNotEqual + + """ + Outside a set of values. + """ + notIn: [EnumA!] + @searchByOperatorNotIn +} + +""" +Available operators for `enum EnumA` (only one operator allowed at a time). +""" +input SearchByEnumEnumAOrNull { + """ + Equal (`=`). + """ + equal: EnumA + @searchByOperatorEqual + + """ + Within a set of values. + """ + in: [EnumA!] + @searchByOperatorIn + + """ + Is NOT NULL? + """ + isNotNull: SearchByTypeFlag + @searchByOperatorIsNotNull + + """ + Is NULL? + """ + isNull: SearchByTypeFlag + @searchByOperatorIsNull + + """ + Not Equal (`!=`). + """ + notEqual: EnumA + @searchByOperatorNotEqual + + """ + Outside a set of values. + """ + notIn: [EnumA!] + @searchByOperatorNotIn +} + +""" +Available operators for `scalar Boolean` (only one operator allowed at a time). +""" +input SearchByScalarBoolean { + """ + Equal (`=`). + """ + equal: Boolean + @searchByOperatorEqual + + """ + Not Equal (`!=`). + """ + notEqual: Boolean + @searchByOperatorNotEqual +} + +""" +Available operators for `scalar Boolean` (only one operator allowed at a time). +""" +input SearchByScalarBooleanOrNull { + """ + Equal (`=`). + """ + equal: Boolean + @searchByOperatorEqual + + """ + Is NOT NULL? + """ + isNotNull: SearchByTypeFlag + @searchByOperatorIsNotNull + + """ + Is NULL? + """ + isNull: SearchByTypeFlag + @searchByOperatorIsNull + + """ + Not Equal (`!=`). + """ + notEqual: Boolean + @searchByOperatorNotEqual +} + +""" +Available operators for `scalar Date` (only one operator allowed at a time). +""" +input SearchByScalarDate { + """ + Equal (`=`). + """ + equal: Date + @searchByOperatorEqual +} + +""" +Available operators for `scalar Date` (only one operator allowed at a time). +""" +input SearchByScalarDateOrNull { + """ + Equal (`=`). + """ + equal: Date + @searchByOperatorEqual + + """ + Is NOT NULL? + """ + isNotNull: SearchByTypeFlag + @searchByOperatorIsNotNull + + """ + Is NULL? + """ + isNull: SearchByTypeFlag + @searchByOperatorIsNull +} + +""" +Available operators for `scalar Float` (only one operator allowed at a time). +""" +input SearchByScalarFloat { + """ + Within a range. + """ + between: SearchByTypeRangeFloat + @searchByOperatorBetween + + """ + Equal (`=`). + """ + equal: Float + @searchByOperatorEqual + + """ + Greater than (`>`). + """ + greaterThan: Float + @searchByOperatorGreaterThan + + """ + Greater than or equal to (`>=`). + """ + greaterThanOrEqual: Float + @searchByOperatorGreaterThanOrEqual + + """ + Within a set of values. + """ + in: [Float!] + @searchByOperatorIn + + """ + Less than (`<`). + """ + lessThan: Float + @searchByOperatorLessThan + + """ + Less than or equal to (`<=`). + """ + lessThanOrEqual: Float + @searchByOperatorLessThanOrEqual + + """ + Outside a range. + """ + notBetween: SearchByTypeRangeFloat + @searchByOperatorNotBetween + + """ + Not Equal (`!=`). + """ + notEqual: Float + @searchByOperatorNotEqual + + """ + Outside a set of values. + """ + notIn: [Float!] + @searchByOperatorNotIn +} + +""" +Available operators for `scalar Float` (only one operator allowed at a time). +""" +input SearchByScalarFloatOrNull { + """ + Within a range. + """ + between: SearchByTypeRangeFloat + @searchByOperatorBetween + + """ + Equal (`=`). + """ + equal: Float + @searchByOperatorEqual + + """ + Greater than (`>`). + """ + greaterThan: Float + @searchByOperatorGreaterThan + + """ + Greater than or equal to (`>=`). + """ + greaterThanOrEqual: Float + @searchByOperatorGreaterThanOrEqual + + """ + Within a set of values. + """ + in: [Float!] + @searchByOperatorIn + + """ + Is NOT NULL? + """ + isNotNull: SearchByTypeFlag + @searchByOperatorIsNotNull + + """ + Is NULL? + """ + isNull: SearchByTypeFlag + @searchByOperatorIsNull + + """ + Less than (`<`). + """ + lessThan: Float + @searchByOperatorLessThan + + """ + Less than or equal to (`<=`). + """ + lessThanOrEqual: Float + @searchByOperatorLessThanOrEqual + + """ + Outside a range. + """ + notBetween: SearchByTypeRangeFloat + @searchByOperatorNotBetween + + """ + Not Equal (`!=`). + """ + notEqual: Float + @searchByOperatorNotEqual + + """ + Outside a set of values. + """ + notIn: [Float!] + @searchByOperatorNotIn +} + +""" +Available operators for `scalar ID` (only one operator allowed at a time). +""" +input SearchByScalarID { + """ + Equal (`=`). + """ + equal: ID + @searchByOperatorEqual + + """ + Within a set of values. + """ + in: [ID!] + @searchByOperatorIn + + """ + Not Equal (`!=`). + """ + notEqual: ID + @searchByOperatorNotEqual + + """ + Outside a set of values. + """ + notIn: [ID!] + @searchByOperatorNotIn +} + +""" +Available operators for `scalar ID` (only one operator allowed at a time). +""" +input SearchByScalarIDOrNull { + """ + Equal (`=`). + """ + equal: ID + @searchByOperatorEqual + + """ + Within a set of values. + """ + in: [ID!] + @searchByOperatorIn + + """ + Is NOT NULL? + """ + isNotNull: SearchByTypeFlag + @searchByOperatorIsNotNull + + """ + Is NULL? + """ + isNull: SearchByTypeFlag + @searchByOperatorIsNull + + """ + Not Equal (`!=`). + """ + notEqual: ID + @searchByOperatorNotEqual + + """ + Outside a set of values. + """ + notIn: [ID!] + @searchByOperatorNotIn +} + +""" +Available operators for `scalar Int` (only one operator allowed at a time). +""" +input SearchByScalarInt { + """ + Within a range. + """ + between: SearchByTypeRangeInt + @searchByOperatorBetween + + """ + Bitwise AND (`&`). + """ + bitwiseAnd: Int + @searchByOperatorBitwiseAnd + + """ + Bitwise Left shift (`<<`). + """ + bitwiseLeftShift: Int + @searchByOperatorBitwiseLeftShift + + """ + Bitwise OR (`|`). + """ + bitwiseOr: Int + @searchByOperatorBitwiseOr + + """ + Bitwise Right shift (`>>`). + """ + bitwiseRightShift: Int + @searchByOperatorBitwiseRightShift + + """ + Bitwise XOR (`^`). + """ + bitwiseXor: Int + @searchByOperatorBitwiseXor + + """ + Equal (`=`). + """ + equal: Int + @searchByOperatorEqual + + """ + Greater than (`>`). + """ + greaterThan: Int + @searchByOperatorGreaterThan + + """ + Greater than or equal to (`>=`). + """ + greaterThanOrEqual: Int + @searchByOperatorGreaterThanOrEqual + + """ + Within a set of values. + """ + in: [Int!] + @searchByOperatorIn + + """ + Less than (`<`). + """ + lessThan: Int + @searchByOperatorLessThan + + """ + Less than or equal to (`<=`). + """ + lessThanOrEqual: Int + @searchByOperatorLessThanOrEqual + + """ + Outside a range. + """ + notBetween: SearchByTypeRangeInt + @searchByOperatorNotBetween + + """ + Not Equal (`!=`). + """ + notEqual: Int + @searchByOperatorNotEqual + + """ + Outside a set of values. + """ + notIn: [Int!] + @searchByOperatorNotIn +} + +""" +Available operators for `scalar Int` (only one operator allowed at a time). +""" +input SearchByScalarIntOrNull { + """ + Within a range. + """ + between: SearchByTypeRangeInt + @searchByOperatorBetween + + """ + Bitwise AND (`&`). + """ + bitwiseAnd: Int + @searchByOperatorBitwiseAnd + + """ + Bitwise Left shift (`<<`). + """ + bitwiseLeftShift: Int + @searchByOperatorBitwiseLeftShift + + """ + Bitwise OR (`|`). + """ + bitwiseOr: Int + @searchByOperatorBitwiseOr + + """ + Bitwise Right shift (`>>`). + """ + bitwiseRightShift: Int + @searchByOperatorBitwiseRightShift + + """ + Bitwise XOR (`^`). + """ + bitwiseXor: Int + @searchByOperatorBitwiseXor + + """ + Equal (`=`). + """ + equal: Int + @searchByOperatorEqual + + """ + Greater than (`>`). + """ + greaterThan: Int + @searchByOperatorGreaterThan + + """ + Greater than or equal to (`>=`). + """ + greaterThanOrEqual: Int + @searchByOperatorGreaterThanOrEqual + + """ + Within a set of values. + """ + in: [Int!] + @searchByOperatorIn + + """ + Is NOT NULL? + """ + isNotNull: SearchByTypeFlag + @searchByOperatorIsNotNull + + """ + Is NULL? + """ + isNull: SearchByTypeFlag + @searchByOperatorIsNull + + """ + Less than (`<`). + """ + lessThan: Int + @searchByOperatorLessThan + + """ + Less than or equal to (`<=`). + """ + lessThanOrEqual: Int + @searchByOperatorLessThanOrEqual + + """ + Outside a range. + """ + notBetween: SearchByTypeRangeInt + @searchByOperatorNotBetween + + """ + Not Equal (`!=`). + """ + notEqual: Int + @searchByOperatorNotEqual + + """ + Outside a set of values. + """ + notIn: [Int!] + @searchByOperatorNotIn +} + +""" +Available operators for `scalar ScalarCustom` (only one operator allowed at a time). +""" +input SearchByScalarScalarCustomOrNull { + """ + Equal (`=`). + """ + equal: ScalarCustom + @searchByOperatorEqual + + """ + Is NOT NULL? + """ + isNotNull: SearchByTypeFlag + @searchByOperatorIsNotNull + + """ + Is NULL? + """ + isNull: SearchByTypeFlag + @searchByOperatorIsNull + + """ + Less than (`<`). + """ + lessThan: ScalarCustom + @searchByOperatorLessThan + + """ + Less than or equal to (`<=`). + """ + lessThanOrEqual: ScalarCustom + @searchByOperatorLessThanOrEqual + + """ + Not Equal (`!=`). + """ + notEqual: ScalarCustom + @searchByOperatorNotEqual +} + +""" +Available operators for `scalar String` (only one operator allowed at a time). +""" +input SearchByScalarString { + """ + Contains. + """ + contains: String + @searchByOperatorContains + + """ + Ends with a string. + """ + endsWith: String + @searchByOperatorEndsWith + + """ + Equal (`=`). + """ + equal: String + @searchByOperatorEqual + + """ + Within a set of values. + """ + in: [String!] + @searchByOperatorIn + + """ + Like. + """ + like: String + @searchByOperatorLike + + """ + Not Equal (`!=`). + """ + notEqual: String + @searchByOperatorNotEqual + + """ + Outside a set of values. + """ + notIn: [String!] + @searchByOperatorNotIn + + """ + Not like. + """ + notLike: String + @searchByOperatorNotLike + + """ + Starts with a string. + """ + startsWith: String + @searchByOperatorStartsWith +} + +""" +Available operators for `scalar String` (only one operator allowed at a time). +""" +input SearchByScalarStringOrNull { + """ + Contains. + """ + contains: String + @searchByOperatorContains + + """ + Ends with a string. + """ + endsWith: String + @searchByOperatorEndsWith + + """ + Equal (`=`). + """ + equal: String + @searchByOperatorEqual + + """ + Within a set of values. + """ + in: [String!] + @searchByOperatorIn + + """ + Is NOT NULL? + """ + isNotNull: SearchByTypeFlag + @searchByOperatorIsNotNull + + """ + Is NULL? + """ + isNull: SearchByTypeFlag + @searchByOperatorIsNull + + """ + Like. + """ + like: String + @searchByOperatorLike + + """ + Not Equal (`!=`). + """ + notEqual: String + @searchByOperatorNotEqual + + """ + Outside a set of values. + """ + notIn: [String!] + @searchByOperatorNotIn + + """ + Not like. + """ + notLike: String + @searchByOperatorNotLike + + """ + Starts with a string. + """ + startsWith: String + @searchByOperatorStartsWith +} + +""" +Available conditions for `input InputA` (only one property allowed at a time). +""" +input SearchByScoutConditionInputA { + """ + All of the conditions must be true. + """ + allOf: [SearchByScoutConditionInputA!] + @searchByOperatorAllOf + + """ + Property condition. + """ + booleanScalar: SearchByScoutScalarBooleanOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + booleanScalarNotNull: SearchByScoutScalarBoolean + @searchByOperatorProperty + + """ + Property condition. + """ + customScalar: SearchByScoutScalarDateOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + customScalarList: SearchByScoutScalarDate + @searchByOperatorProperty + + """ + Property condition. + """ + customScalarNonNull: SearchByScoutScalarDate + @searchByOperatorProperty + + """ + Property condition. + """ + customScalarOperators: SearchByScoutScalarScalarCustomOrNull + @searchByOperatorProperty + + """ + Description should be used. + """ + description: SearchByScoutScalarIDOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + enum: SearchByScoutEnumEnumAOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + enumNotNull: SearchByScoutEnumEnumA + @searchByOperatorProperty + + """ + Property condition. + """ + fieldRenamed: SearchByScoutScalarIDOrNull + @searchByOperatorProperty + @rename( + attribute: "renamed" + ) + + """ + Property condition. + """ + floatScalar: SearchByScoutScalarFloatOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + floatScalarNotNull: SearchByScoutScalarFloat + @searchByOperatorProperty + + """ + Property condition. + """ + idScalar: SearchByScoutScalarIDOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + idScalarNotNull: SearchByScoutScalarID + @searchByOperatorProperty + + """ + Property condition. + """ + intScalar: SearchByScoutScalarIntOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + intScalarNotNull: SearchByScoutScalarInt + @searchByOperatorProperty + + """ + Property condition. + """ + nested: SearchByScoutConditionNestedA + @searchByOperatorCondition + + """ + Property condition. + """ + nestedNotNull: SearchByScoutConditionNestedA + @searchByOperatorCondition + + """ + Property condition. + """ + stringScalar: SearchByScoutScalarStringOrNull + @searchByOperatorProperty + + """ + Property condition. + """ + stringScalarNotNull: SearchByScoutScalarString + @searchByOperatorProperty +} + +""" +Available conditions for `input NestedA` (only one property allowed at a time). +""" +input SearchByScoutConditionNestedA { + """ + All of the conditions must be true. + """ + allOf: [SearchByScoutConditionNestedA!] + @searchByOperatorAllOf + + """ + Property condition. + """ + nested: SearchByScoutConditionNestedA + @searchByOperatorCondition + + """ + Property condition. + """ + value: SearchByScoutScalarStringOrNull + @searchByOperatorProperty +} + +""" +Available operators for `enum EnumA` (only one operator allowed at a time). +""" +input SearchByScoutEnumEnumA { + """ + Equal (`=`). + """ + equal: EnumA + @searchByOperatorEqual + + """ + Within a set of values. + """ + in: [EnumA!] + @searchByOperatorIn + + """ + Outside a set of values. + """ + notIn: [EnumA!] + @searchByOperatorNotIn +} + +""" +Available operators for `enum EnumA` (only one operator allowed at a time). +""" +input SearchByScoutEnumEnumAOrNull { + """ + Equal (`=`). + """ + equal: EnumA + @searchByOperatorEqual + + """ + Within a set of values. + """ + in: [EnumA!] + @searchByOperatorIn + + """ + Outside a set of values. + """ + notIn: [EnumA!] + @searchByOperatorNotIn +} + +""" +Available operators for `scalar Boolean` (only one operator allowed at a time). +""" +input SearchByScoutScalarBoolean { + """ + Equal (`=`). + """ + equal: Boolean + @searchByOperatorEqual +} + +""" +Available operators for `scalar Boolean` (only one operator allowed at a time). +""" +input SearchByScoutScalarBooleanOrNull { + """ + Equal (`=`). + """ + equal: Boolean + @searchByOperatorEqual +} + +""" +Available operators for `scalar Date` (only one operator allowed at a time). +""" +input SearchByScoutScalarDate { + """ + Equal (`=`). + """ + equal: Date + @searchByOperatorEqual +} + +""" +Available operators for `scalar Date` (only one operator allowed at a time). +""" +input SearchByScoutScalarDateOrNull { + """ + Equal (`=`). + """ + equal: Date + @searchByOperatorEqual +} + +""" +Available operators for `scalar Float` (only one operator allowed at a time). +""" +input SearchByScoutScalarFloat { + """ + Equal (`=`). + """ + equal: Float + @searchByOperatorEqual + + """ + Within a set of values. + """ + in: [Float!] + @searchByOperatorIn + + """ + Outside a set of values. + """ + notIn: [Float!] + @searchByOperatorNotIn +} + +""" +Available operators for `scalar Float` (only one operator allowed at a time). +""" +input SearchByScoutScalarFloatOrNull { + """ + Equal (`=`). + """ + equal: Float + @searchByOperatorEqual + + """ + Within a set of values. + """ + in: [Float!] + @searchByOperatorIn + + """ + Outside a set of values. + """ + notIn: [Float!] + @searchByOperatorNotIn +} + +""" +Available operators for `scalar ID` (only one operator allowed at a time). +""" +input SearchByScoutScalarID { + """ + Equal (`=`). + """ + equal: ID + @searchByOperatorEqual + + """ + Within a set of values. + """ + in: [ID!] + @searchByOperatorIn + + """ + Outside a set of values. + """ + notIn: [ID!] + @searchByOperatorNotIn +} + +""" +Available operators for `scalar ID` (only one operator allowed at a time). +""" +input SearchByScoutScalarIDOrNull { + """ + Equal (`=`). + """ + equal: ID + @searchByOperatorEqual + + """ + Within a set of values. + """ + in: [ID!] + @searchByOperatorIn + + """ + Outside a set of values. + """ + notIn: [ID!] + @searchByOperatorNotIn +} + +""" +Available operators for `scalar Int` (only one operator allowed at a time). +""" +input SearchByScoutScalarInt { + """ + Equal (`=`). + """ + equal: Int + @searchByOperatorEqual + + """ + Within a set of values. + """ + in: [Int!] + @searchByOperatorIn + + """ + Outside a set of values. + """ + notIn: [Int!] + @searchByOperatorNotIn +} + +""" +Available operators for `scalar Int` (only one operator allowed at a time). +""" +input SearchByScoutScalarIntOrNull { + """ + Equal (`=`). + """ + equal: Int + @searchByOperatorEqual + + """ + Within a set of values. + """ + in: [Int!] + @searchByOperatorIn + + """ + Outside a set of values. + """ + notIn: [Int!] + @searchByOperatorNotIn +} + +""" +Available operators for `scalar ScalarCustom` (only one operator allowed at a time). +""" +input SearchByScoutScalarScalarCustomOrNull { + """ + Equal (`=`). + """ + equal: ScalarCustom + @searchByOperatorEqual +} + +""" +Available operators for `scalar String` (only one operator allowed at a time). +""" +input SearchByScoutScalarString { + """ + Equal (`=`). + """ + equal: String + @searchByOperatorEqual + + """ + Within a set of values. + """ + in: [String!] + @searchByOperatorIn + + """ + Outside a set of values. + """ + notIn: [String!] + @searchByOperatorNotIn +} + +""" +Available operators for `scalar String` (only one operator allowed at a time). +""" +input SearchByScoutScalarStringOrNull { + """ + Equal (`=`). + """ + equal: String + @searchByOperatorEqual + + """ + Within a set of values. + """ + in: [String!] + @searchByOperatorIn + + """ + Outside a set of values. + """ + notIn: [String!] + @searchByOperatorNotIn +} + +input SearchByTypeRangeFloat { + max: Float! + min: Float! +} + +input SearchByTypeRangeInt { + max: Int! + min: Int! +} + +interface A +implements + & C + & F +{ + a( + where: SearchByConditionInputA + ): ID! +} + +interface B { + b( + where: SearchByConditionNestedA + ): ID! +} + +interface C { + c( + where: SearchByConditionInputB + ): ID! +} + +interface F { + f( + where: SearchByConditionObject + @searchBy + ): Object! + @all +} + +interface ObjectInterface { + booleanScalar: Boolean + booleanScalarNotNull: Boolean! + customScalar: Date + customScalarIgnored: DateIgnored + customScalarIgnoredList: [DateIgnored!]! + customScalarIgnoredNonNull: DateIgnored! + customScalarList: [Date!]! + customScalarNonNull: Date! + customScalarOperators: ScalarCustom + + """ + Description should NOT be used. + """ + description: ID + + enum: EnumA + enumEnumIgnoredNotNull: EnumIgnored! + enumIgnored: EnumIgnored + enumNotNull: EnumA! + + fieldRenamed: ID + @rename( + attribute: "renamed" + ) + + """ + Should be ignored + """ + fieldWithArguments( + arg: Int + ): Boolean + + floatScalar: Float + floatScalarNotNull: Float! + idScalar: ID + idScalarNotNull: ID! + + ignored: String + @searchByIgnored + + ignoredType: ObjectIgnored + ignoredTypeList: [ObjectIgnored!]! + ignoredTypeNonNull: ObjectIgnored! + intScalar: Int + intScalarNotNull: Int! + nested: ObjectNested + nestedNotNull: ObjectNested! + + resolver: Float + @field( + resolver: "\\LastDragon_ru\\LaraASP\\GraphQL\\SearchBy\\Directives\\DirectiveTest__Resolver" + ) + + stringScalar: String + stringScalarNotNull: String! + union: ObjectUnion + unionList: [ObjectUnion!]! + unionNonNull: ObjectUnion! +} + +scalar Date +@scalar( + class: "Nuwave\\Lighthouse\\Schema\\Types\\Scalars\\Date" +) + +scalar DateIgnored +@scalar( + class: "Nuwave\\Lighthouse\\Schema\\Types\\Scalars\\Date" +) +@searchByIgnored + +scalar ScalarCustom +@scalar( + class: "Nuwave\\Lighthouse\\Schema\\Types\\Scalars\\Date" +) +@searchByOperators( + type: "Boolean" +) +@searchByOperatorLessThan +@searchByOperatorLessThanOrEqual + +type Object +implements + & ObjectInterface +{ + booleanScalar: Boolean + booleanScalarNotNull: Boolean! + customScalar: Date + customScalarIgnored: DateIgnored + customScalarIgnoredList: [DateIgnored!]! + customScalarIgnoredNonNull: DateIgnored! + customScalarList: [Date!]! + customScalarNonNull: Date! + customScalarOperators: ScalarCustom + + """ + Description should NOT be used. + """ + description: ID + + enum: EnumA + enumEnumIgnoredNotNull: EnumIgnored! + enumIgnored: EnumIgnored + enumNotNull: EnumA! + + fieldRenamed: ID + @rename( + attribute: "renamed" + ) + + """ + Should be ignored + """ + fieldWithArguments( + arg: Int + ): Boolean + + floatScalar: Float + floatScalarNotNull: Float! + idScalar: ID + idScalarNotNull: ID! + + ignored: String + @searchByIgnored + + ignoredType: ObjectIgnored + ignoredTypeList: [ObjectIgnored!]! + ignoredTypeNonNull: ObjectIgnored! + intScalar: Int + intScalarNotNull: Int! + nested: ObjectNested + nestedNotNull: ObjectNested! + + resolver: Float + @field( + resolver: "\\LastDragon_ru\\LaraASP\\GraphQL\\SearchBy\\Directives\\DirectiveTest__Resolver" + ) + + stringScalar: String + stringScalarNotNull: String! + union: ObjectUnion + unionList: [ObjectUnion!]! + unionNonNull: ObjectUnion! +} + +type ObjectIgnored +@searchByIgnored +{ + value: String +} + +type ObjectNested { + nested: ObjectNested + value: String +} + +type Query +implements + & A + & B +{ + a( + where: SearchByConditionInputA + @searchBy + ): ID! + @all + + b( + where: SearchByConditionNestedA + @searchBy + ): ID! + @all + + c( + where: SearchByConditionInputB + @searchBy + ): ID! + @all + + d( + where: SearchByConditionNestedB + @searchBy + ): ID! + @all + + e( + search: String + @search + + where: SearchByScoutConditionInputA + @searchBy + ): ID! + @all + + f( + where: SearchByConditionObject + @searchBy + ): Object! + @all + + g( + where: SearchByConditionObjectInterface + @searchBy + ): Object! + @all +} + +union ObjectUnion = + | Object + | ObjectNested diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotIn.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotIn.php index 75398d329..ba7fc0da9 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotIn.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotIn.php @@ -4,15 +4,19 @@ use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Query\Builder as QueryBuilder; +use Laravel\Scout\Builder as ScoutBuilder; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeProvider; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeSource; use LastDragon_ru\LaraASP\GraphQL\Builder\Exceptions\OperatorUnsupportedBuilder; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; use LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\BaseOperator; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Traits\ScoutSupport; use Nuwave\Lighthouse\Execution\Arguments\Argument; class NotIn extends BaseOperator { + use ScoutSupport; + public static function getName(): string { return 'notIn'; } @@ -25,15 +29,23 @@ public function getFieldType(TypeProvider $provider, TypeSource $source): string return "[{$source->getTypeName()}!]"; } + protected function getScoutVersion(): ?string { + return '>=10.3.0'; + } + public function call(Handler $handler, object $builder, Property $property, Argument $argument): object { - if (!($builder instanceof EloquentBuilder || $builder instanceof QueryBuilder)) { - throw new OperatorUnsupportedBuilder($this, $builder); - } + $property = $property->getParent(); + $value = (array) $argument->toPlain(); - $property = (string) $property->getParent(); - $value = $argument->toPlain(); + if ($builder instanceof EloquentBuilder || $builder instanceof QueryBuilder) { + $builder->whereNotIn((string) $property, $value); + } elseif ($builder instanceof ScoutBuilder) { + $property = $this->getFieldResolver()->getField($builder->model, $property); - $builder->whereNotIn($property, $value); + $builder->whereNotIn($property, $value); + } else { + throw new OperatorUnsupportedBuilder($this, $builder); + } return $builder; } diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotInTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotInTest.php index f7fca8181..8db13c463 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotInTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotInTest.php @@ -3,9 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; +use Composer\InstalledVersions; +use Illuminate\Database\Eloquent\Model; +use Laravel\Scout\Builder as ScoutBuilder; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\ScoutBuilderDataProvider; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; @@ -13,6 +18,9 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; +use function sprintf; + /** * @internal * @@ -44,6 +52,47 @@ public function testCall( self::assertDatabaseQueryEquals($expected, $builder); } + + /** + * @dataProvider dataProviderCallScout + * + * @param array $expected + * @param Closure(static): ScoutBuilder $builderFactory + * @param Closure(static): Argument $argumentFactory + * @param Closure():FieldResolver|null $resolver + */ + public function testCallScout( + array $expected, + Closure $builderFactory, + Property $property, + Closure $argumentFactory, + Closure $resolver = null, + ): void { + // Prepare + if ($resolver) { + $this->override(FieldResolver::class, $resolver); + } + + // Supported? + $operator = $this->app->make(NotInTest_Operator::class); + + if (!$operator->isScoutSupported()) { + self::markTestSkipped(sprintf( + 'Minimum version of `laravel/scout` should be `%s`, `%s` installed.', + $operator->getScoutVersion(), + InstalledVersions::getPrettyVersion('laravel/scout'), + )); + } + + // Test + $property = $property->getChild('operator name should be ignored'); + $argument = $argumentFactory($this); + $search = Mockery::mock(Handler::class); + $builder = $builderFactory($this); + $builder = $operator->call($search, $builder, $property, $argument); + + self::assertScoutQueryEquals($expected, $builder); + } // // @@ -78,5 +127,66 @@ static function (self $test): Argument { ]), ))->getData(); } + + /** + * @return array + */ + public static function dataProviderCallScout(): array { + return (new CompositeDataProvider( + new ScoutBuilderDataProvider(), + new ArrayDataProvider([ + 'property' => [ + [ + 'whereNotIns' => [ + 'path.to.property' => [1, 2, 3], + ], + ], + new Property('path', 'to', 'property'), + static function (self $test): Argument { + return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); + }, + null, + ], + 'property with resolver' => [ + [ + 'whereNotIns' => [ + 'properties/path/to/property' => [1, 2, 3], + ], + ], + new Property('path', 'to', 'property'), + static function (self $test): Argument { + return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); + }, + static function (): FieldResolver { + return new class() implements FieldResolver { + /** + * @inheritDoc + */ + public function getField(Model $model, Property $property): string { + return 'properties/'.implode('/', $property->getPath()); + } + }; + }, + ], + ]), + ))->getData(); + } // } + +// @phpcs:disable PSR1.Classes.ClassDeclaration.MultipleClasses +// @phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps + +/** + * @internal + * @noinspection PhpMultipleClassesDeclarationsInOneFile + */ +class NotInTest_Operator extends NotIn { + public function isScoutSupported(): bool { + return parent::isScoutSupported(); + } + + public function getScoutVersion(): ?string { + return parent::getScoutVersion(); + } +} diff --git a/packages/graphql/src/SearchBy/Operators/Traits/ScoutSupport.php b/packages/graphql/src/SearchBy/Operators/Traits/ScoutSupport.php index 8b63485e5..b35b8e2d7 100644 --- a/packages/graphql/src/SearchBy/Operators/Traits/ScoutSupport.php +++ b/packages/graphql/src/SearchBy/Operators/Traits/ScoutSupport.php @@ -2,6 +2,8 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Traits; +use Composer\InstalledVersions; +use Composer\Semver\VersionParser; use Laravel\Scout\Builder as ScoutBuilder; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver; use LastDragon_ru\LaraASP\GraphQL\SearchBy\Definitions\SearchByOperatorPropertyDirective; @@ -24,6 +26,18 @@ protected function getFieldResolver(): FieldResolver { public function isBuilderSupported(string $builder): bool { return parent::isBuilderSupported($builder) - || is_a($builder, ScoutBuilder::class, true); + || (is_a($builder, ScoutBuilder::class, true) && $this->isScoutSupported()); + } + + protected function isScoutSupported(): bool { + $version = $this->getScoutVersion(); + $supported = $version === null + || InstalledVersions::satisfies(new VersionParser(), 'laravel/scout', $version); + + return $supported; + } + + protected function getScoutVersion(): ?string { + return null; } }