From 931bb04c416d2618843ccacee59ba47b8555b348 Mon Sep 17 00:00:00 2001 From: Martin Kamleithner Date: Sun, 12 Nov 2023 18:09:06 +0000 Subject: [PATCH] extract gql_tristate_value to separate package in order to not pollute gql_exec for users who don't use tristate null --- .github/workflows/dart.yml | 1 + .../fragment_with_scalar_var.var.gql.dart | 2 +- .../hero_with_fragments.var.gql.dart | 2 +- .../multiple_fragments.var.gql.dart | 2 +- .../__generated__/schema.schema.gql.dart | 2 +- .../review_with_date.var.gql.dart | 2 +- .../__generated__/create_review.var.gql.dart | 2 +- codegen/end_to_end_test_tristate/pubspec.yaml | 1 + .../test/operation/variables_test.dart | 2 +- .../test/schema/input_test.dart | 2 +- .../test/schema/scalars_test.dart | 2 +- codegen/gql_build/lib/src/utils/config.dart | 2 +- codegen/gql_build/pubspec.yaml | 1 + codegen/gql_code_builder/lib/src/common.dart | 5 +- .../lib/src/tristate_optionals.dart | 2 +- codegen/gql_code_builder/pubspec.yaml | 1 + codegen/gql_tristate_value/.gitignore | 3 ++ codegen/gql_tristate_value/CHANGELOG.md | 3 ++ codegen/gql_tristate_value/LICENSE | 21 ++++++++ codegen/gql_tristate_value/README.md | 9 ++++ .../gql_tristate_value/analysis_options.yaml | 1 + .../lib/gql_tristate_value.dart | 1 + codegen/gql_tristate_value/lib/src/value.dart | 54 +++++++++++++++++++ codegen/gql_tristate_value/pubspec.yaml | 12 +++++ .../gql_tristate_value/test/value_test.dart | 34 ++++++++++++ links/gql_exec/lib/src/value.dart | 53 ------------------ links/gql_exec/pubspec.yaml | 2 +- 27 files changed, 157 insertions(+), 67 deletions(-) create mode 100644 codegen/gql_tristate_value/.gitignore create mode 100644 codegen/gql_tristate_value/CHANGELOG.md create mode 100644 codegen/gql_tristate_value/LICENSE create mode 100644 codegen/gql_tristate_value/README.md create mode 100644 codegen/gql_tristate_value/analysis_options.yaml create mode 100644 codegen/gql_tristate_value/lib/gql_tristate_value.dart create mode 100644 codegen/gql_tristate_value/lib/src/value.dart create mode 100644 codegen/gql_tristate_value/pubspec.yaml create mode 100644 codegen/gql_tristate_value/test/value_test.dart diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 8e73f44f..e311bd4f 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -18,6 +18,7 @@ jobs: - gql_http_link - gql_websocket_link - gql_transform_link + - gql_tristate_value runs-on: ubuntu-latest container: image: dart:latest diff --git a/codegen/end_to_end_test_tristate/lib/fragments/__generated__/fragment_with_scalar_var.var.gql.dart b/codegen/end_to_end_test_tristate/lib/fragments/__generated__/fragment_with_scalar_var.var.gql.dart index 15d07fff..7832b208 100644 --- a/codegen/end_to_end_test_tristate/lib/fragments/__generated__/fragment_with_scalar_var.var.gql.dart +++ b/codegen/end_to_end_test_tristate/lib/fragments/__generated__/fragment_with_scalar_var.var.gql.dart @@ -8,7 +8,7 @@ import 'package:end_to_end_test_tristate/graphql/__generated__/schema.schema.gql as _i2; import 'package:end_to_end_test_tristate/graphql/__generated__/serializers.gql.dart' as _i3; -import 'package:gql_exec/value.dart' as _i1; +import 'package:gql_tristate_value/gql_tristate_value.dart' as _i1; part 'fragment_with_scalar_var.var.gql.g.dart'; diff --git a/codegen/end_to_end_test_tristate/lib/fragments/__generated__/hero_with_fragments.var.gql.dart b/codegen/end_to_end_test_tristate/lib/fragments/__generated__/hero_with_fragments.var.gql.dart index b780f928..d325d7dc 100644 --- a/codegen/end_to_end_test_tristate/lib/fragments/__generated__/hero_with_fragments.var.gql.dart +++ b/codegen/end_to_end_test_tristate/lib/fragments/__generated__/hero_with_fragments.var.gql.dart @@ -6,7 +6,7 @@ import 'package:built_value/built_value.dart'; import 'package:built_value/serializer.dart'; import 'package:end_to_end_test_tristate/graphql/__generated__/serializers.gql.dart' as _i2; -import 'package:gql_exec/value.dart' as _i1; +import 'package:gql_tristate_value/gql_tristate_value.dart' as _i1; part 'hero_with_fragments.var.gql.g.dart'; diff --git a/codegen/end_to_end_test_tristate/lib/fragments/__generated__/multiple_fragments.var.gql.dart b/codegen/end_to_end_test_tristate/lib/fragments/__generated__/multiple_fragments.var.gql.dart index dfcecb9d..255e3ac0 100644 --- a/codegen/end_to_end_test_tristate/lib/fragments/__generated__/multiple_fragments.var.gql.dart +++ b/codegen/end_to_end_test_tristate/lib/fragments/__generated__/multiple_fragments.var.gql.dart @@ -6,7 +6,7 @@ import 'package:built_value/built_value.dart'; import 'package:built_value/serializer.dart'; import 'package:end_to_end_test_tristate/graphql/__generated__/serializers.gql.dart' as _i2; -import 'package:gql_exec/value.dart' as _i1; +import 'package:gql_tristate_value/gql_tristate_value.dart' as _i1; part 'multiple_fragments.var.gql.g.dart'; diff --git a/codegen/end_to_end_test_tristate/lib/graphql/__generated__/schema.schema.gql.dart b/codegen/end_to_end_test_tristate/lib/graphql/__generated__/schema.schema.gql.dart index 3e7ba076..f89aece8 100644 --- a/codegen/end_to_end_test_tristate/lib/graphql/__generated__/schema.schema.gql.dart +++ b/codegen/end_to_end_test_tristate/lib/graphql/__generated__/schema.schema.gql.dart @@ -10,7 +10,7 @@ import 'package:end_to_end_test_tristate/graphql/__generated__/serializers.gql.d as _i3; import 'package:gql_code_builder/src/serializers/default_scalar_serializer.dart' as _i4; -import 'package:gql_exec/value.dart' as _i1; +import 'package:gql_tristate_value/gql_tristate_value.dart' as _i1; part 'schema.schema.gql.g.dart'; diff --git a/codegen/end_to_end_test_tristate/lib/scalars/__generated__/review_with_date.var.gql.dart b/codegen/end_to_end_test_tristate/lib/scalars/__generated__/review_with_date.var.gql.dart index fdc46beb..71d7cc57 100644 --- a/codegen/end_to_end_test_tristate/lib/scalars/__generated__/review_with_date.var.gql.dart +++ b/codegen/end_to_end_test_tristate/lib/scalars/__generated__/review_with_date.var.gql.dart @@ -8,7 +8,7 @@ import 'package:end_to_end_test_tristate/graphql/__generated__/schema.schema.gql as _i2; import 'package:end_to_end_test_tristate/graphql/__generated__/serializers.gql.dart' as _i3; -import 'package:gql_exec/value.dart' as _i1; +import 'package:gql_tristate_value/gql_tristate_value.dart' as _i1; part 'review_with_date.var.gql.g.dart'; diff --git a/codegen/end_to_end_test_tristate/lib/variables/__generated__/create_review.var.gql.dart b/codegen/end_to_end_test_tristate/lib/variables/__generated__/create_review.var.gql.dart index 79844439..ec863bc3 100644 --- a/codegen/end_to_end_test_tristate/lib/variables/__generated__/create_review.var.gql.dart +++ b/codegen/end_to_end_test_tristate/lib/variables/__generated__/create_review.var.gql.dart @@ -8,7 +8,7 @@ import 'package:end_to_end_test_tristate/graphql/__generated__/schema.schema.gql as _i2; import 'package:end_to_end_test_tristate/graphql/__generated__/serializers.gql.dart' as _i3; -import 'package:gql_exec/value.dart' as _i1; +import 'package:gql_tristate_value/gql_tristate_value.dart' as _i1; part 'create_review.var.gql.g.dart'; diff --git a/codegen/end_to_end_test_tristate/pubspec.yaml b/codegen/end_to_end_test_tristate/pubspec.yaml index 2b12a118..9da7f779 100644 --- a/codegen/end_to_end_test_tristate/pubspec.yaml +++ b/codegen/end_to_end_test_tristate/pubspec.yaml @@ -15,3 +15,4 @@ dev_dependencies: build: ^2.0.0 build_runner: ^2.0.0 test: ^1.16.8 + gql_tristate_value: ^1.0.0 diff --git a/codegen/end_to_end_test_tristate/test/operation/variables_test.dart b/codegen/end_to_end_test_tristate/test/operation/variables_test.dart index 361c4410..12228dc8 100644 --- a/codegen/end_to_end_test_tristate/test/operation/variables_test.dart +++ b/codegen/end_to_end_test_tristate/test/operation/variables_test.dart @@ -1,4 +1,4 @@ -import 'package:gql_exec/value.dart'; +import 'package:gql_tristate_value/gql_tristate_value.dart'; import "package:test/test.dart"; import 'package:end_to_end_test_tristate/graphql/__generated__/schema.schema.gql.dart'; diff --git a/codegen/end_to_end_test_tristate/test/schema/input_test.dart b/codegen/end_to_end_test_tristate/test/schema/input_test.dart index 8107b0ad..1d573e7e 100644 --- a/codegen/end_to_end_test_tristate/test/schema/input_test.dart +++ b/codegen/end_to_end_test_tristate/test/schema/input_test.dart @@ -1,4 +1,4 @@ -import 'package:gql_exec/value.dart'; +import 'package:gql_tristate_value/gql_tristate_value.dart'; import "package:test/test.dart"; import 'package:end_to_end_test_tristate/graphql/__generated__/schema.schema.gql.dart'; diff --git a/codegen/end_to_end_test_tristate/test/schema/scalars_test.dart b/codegen/end_to_end_test_tristate/test/schema/scalars_test.dart index 5f501a36..91fd3c16 100644 --- a/codegen/end_to_end_test_tristate/test/schema/scalars_test.dart +++ b/codegen/end_to_end_test_tristate/test/schema/scalars_test.dart @@ -1,5 +1,5 @@ import 'package:built_collection/built_collection.dart'; -import 'package:gql_exec/value.dart'; +import 'package:gql_tristate_value/gql_tristate_value.dart'; import "package:test/test.dart"; import 'package:end_to_end_test_tristate/graphql/__generated__/schema.schema.gql.dart'; diff --git a/codegen/gql_build/lib/src/utils/config.dart b/codegen/gql_build/lib/src/utils/config.dart index 408b5e3a..d5b7b7b0 100644 --- a/codegen/gql_build/lib/src/utils/config.dart +++ b/codegen/gql_build/lib/src/utils/config.dart @@ -74,7 +74,7 @@ Map enumFallbackMap(final dynamic enumFallbacks) { } TriStateValueConfig triStateOptionalsConfig(Map config) { - final configValue = config["tristate_optionals"]; + final Object? configValue = config["tristate_optionals"]; if (configValue is bool) { return configValue diff --git a/codegen/gql_build/pubspec.yaml b/codegen/gql_build/pubspec.yaml index d034d65a..25cb4472 100644 --- a/codegen/gql_build/pubspec.yaml +++ b/codegen/gql_build/pubspec.yaml @@ -17,6 +17,7 @@ dependencies: gql_code_builder: ^0.8.0 path: ^1.8.0 yaml: ^3.1.0 + gql_tristate_value: ^1.0.0 dev_dependencies: build_test: ^2.0.0 gql_pedantic: ^1.0.2 diff --git a/codegen/gql_code_builder/lib/src/common.dart b/codegen/gql_code_builder/lib/src/common.dart index 2e19f393..890fb2a7 100644 --- a/codegen/gql_code_builder/lib/src/common.dart +++ b/codegen/gql_code_builder/lib/src/common.dart @@ -3,6 +3,7 @@ import "package:code_builder/code_builder.dart"; import "package:collection/collection.dart"; import "package:gql/ast.dart"; import "package:gql_code_builder/src/config/tristate_optionals_config.dart"; +import "package:gql_code_builder/src/tristate_optionals.dart"; import "../source.dart"; @@ -213,8 +214,8 @@ Method buildOptionalGetter({ final optionalGetter = baseGetter.rebuild((b) => b ..returns = TypeReference((b2) => b2 ..isNullable = true - ..url = "package:gql_exec/value.dart" - ..symbol = "Value" + ..url = valueTypeUrl + ..symbol = valueTypeSymbol ..types.add((baseGetter.returns as TypeReference) .rebuild((b3) => b3..isNullable = false)))); return optionalGetter; diff --git a/codegen/gql_code_builder/lib/src/tristate_optionals.dart b/codegen/gql_code_builder/lib/src/tristate_optionals.dart index 592093ca..c4d01d99 100644 --- a/codegen/gql_code_builder/lib/src/tristate_optionals.dart +++ b/codegen/gql_code_builder/lib/src/tristate_optionals.dart @@ -262,7 +262,7 @@ String _generateTypeCast(TypeReference ref, Allocator allocator) { } const valueTypeSymbol = "Value"; -const valueTypeUrl = "package:gql_exec/value.dart"; +const valueTypeUrl = "package:gql_tristate_value/gql_tristate_value.dart"; final valueTypeRef = TypeReference( (b) => b diff --git a/codegen/gql_code_builder/pubspec.yaml b/codegen/gql_code_builder/pubspec.yaml index 91eb3376..2c9bf75d 100644 --- a/codegen/gql_code_builder/pubspec.yaml +++ b/codegen/gql_code_builder/pubspec.yaml @@ -13,6 +13,7 @@ dependencies: gql: ^1.0.0 gql_exec: ^1.0.0 path: ^1.8.0 + gql_tristate_value: ^1.0.0 dev_dependencies: build_runner: ^2.1.0 gql_pedantic: ^1.0.2 diff --git a/codegen/gql_tristate_value/.gitignore b/codegen/gql_tristate_value/.gitignore new file mode 100644 index 00000000..3a857904 --- /dev/null +++ b/codegen/gql_tristate_value/.gitignore @@ -0,0 +1,3 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ diff --git a/codegen/gql_tristate_value/CHANGELOG.md b/codegen/gql_tristate_value/CHANGELOG.md new file mode 100644 index 00000000..effe43c8 --- /dev/null +++ b/codegen/gql_tristate_value/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/codegen/gql_tristate_value/LICENSE b/codegen/gql_tristate_value/LICENSE new file mode 100644 index 00000000..2da6dcfa --- /dev/null +++ b/codegen/gql_tristate_value/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018-present, GQL Dart + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/codegen/gql_tristate_value/README.md b/codegen/gql_tristate_value/README.md new file mode 100644 index 00000000..a16e30e3 --- /dev/null +++ b/codegen/gql_tristate_value/README.md @@ -0,0 +1,9 @@ + +A `Value` class used to represent the three possible states: +- absence of a value +- presence of a value that is `null` +- presence of a non-null value + +This class is used by the generated code for GraphQL variables and input types that are nullable +in order to distinguish between the absence of a value and the presence of a `null` value, typically +used for "update" Mutations. diff --git a/codegen/gql_tristate_value/analysis_options.yaml b/codegen/gql_tristate_value/analysis_options.yaml new file mode 100644 index 00000000..572dd239 --- /dev/null +++ b/codegen/gql_tristate_value/analysis_options.yaml @@ -0,0 +1 @@ +include: package:lints/recommended.yaml diff --git a/codegen/gql_tristate_value/lib/gql_tristate_value.dart b/codegen/gql_tristate_value/lib/gql_tristate_value.dart new file mode 100644 index 00000000..1a21bcf8 --- /dev/null +++ b/codegen/gql_tristate_value/lib/gql_tristate_value.dart @@ -0,0 +1 @@ +export 'src/value.dart'; diff --git a/codegen/gql_tristate_value/lib/src/value.dart b/codegen/gql_tristate_value/lib/src/value.dart new file mode 100644 index 00000000..9029a173 --- /dev/null +++ b/codegen/gql_tristate_value/lib/src/value.dart @@ -0,0 +1,54 @@ +/// A nullable value that may or may not be present. +/// This is used to represent three possible states: +/// - The value is absent. It will not be serialized. +/// - The value is present and null. It will be serialized as null. +/// - The value is present and non-null. It will be serialized as the value. +sealed class Value { + const Value._(); + + /// The value is absent. It will not be serialized. + const factory Value.absent() = AbsentValue; + + /// The value is present. It may still be be null. + /// If the value is null, it will be serialized as null. + /// If the value is non-null, it will be serialized as the value. + const factory Value.present(T? value) = PresentValue; + + /// Returns the value if present (no matter if null or non-null), otherwise throws a [StateError]. + T? get requireValue => switch (this) { + PresentValue(:final value) => value, + AbsentValue() => throw StateError("Value is absent"), + }; + + /// return the value if present and non-null, otherwise null. + /// this is useful for cases where you don't care between the value being absent or null. + T? get valueOrNull => switch (this) { + PresentValue(:final value) => value, + AbsentValue() => null, + }; + + bool get isPresent => switch (this) { + PresentValue() => true, + AbsentValue() => false, + }; +} + +class AbsentValue extends Value { + const AbsentValue() : super._(); +} + +class PresentValue extends Value { + final T? value; + + const PresentValue(this.value) : super._(); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is PresentValue && + runtimeType == other.runtimeType && + value == other.value; + + @override + int get hashCode => value.hashCode; +} diff --git a/codegen/gql_tristate_value/pubspec.yaml b/codegen/gql_tristate_value/pubspec.yaml new file mode 100644 index 00000000..940f9682 --- /dev/null +++ b/codegen/gql_tristate_value/pubspec.yaml @@ -0,0 +1,12 @@ +name: gql_tristate_value +version: 1.0.0 +description: A wrapper class for representing a value that can be absent, present and null, or present and non-null. +repository: https://github.com/gql-dart/gql +environment: + sdk: '>=3.0.0 <4.0.0' +dev_dependencies: + test: ^1.16.8 +topics: + - graphql + - gql + - codegen diff --git a/codegen/gql_tristate_value/test/value_test.dart b/codegen/gql_tristate_value/test/value_test.dart new file mode 100644 index 00000000..7cf49418 --- /dev/null +++ b/codegen/gql_tristate_value/test/value_test.dart @@ -0,0 +1,34 @@ +import 'package:gql_tristate_value/gql_tristate_value.dart'; +import 'package:test/test.dart'; + +void main() { + test("requireValue on absent throws", () { + final absent = const AbsentValue(); + + expect(() => absent.requireValue, throwsA(isA())); + }); + + test("requireValue on present returns value", () { + final present = Value.present(42); + + expect(present.requireValue, equals(42)); + }); + + test("requireValue on null returns null", () { + final nullValue = Value.present(null); + + expect(nullValue.requireValue, isNull); + }); + + test("valueOrNull on absent returns null", () { + final absent = const AbsentValue(); + + expect(absent.valueOrNull, isNull); + }); + + test("valueOrNull on present returns value", () { + final present = Value.present(42); + + expect(present.valueOrNull, equals(42)); + }); +} diff --git a/links/gql_exec/lib/src/value.dart b/links/gql_exec/lib/src/value.dart index ddb9f53e..8b137891 100644 --- a/links/gql_exec/lib/src/value.dart +++ b/links/gql_exec/lib/src/value.dart @@ -1,54 +1 @@ -/// A nullable value that may or may not be present. -/// This is used to represent three possible states: -/// - The value is absent. It will not be serialized. -/// - The value is present and null. It will be serialized as null. -/// - The value is present and non-null. It will be serialized as the value. -sealed class Value { - const Value._(); - /// The value is absent. It will not be serialized. - const factory Value.absent() = AbsentValue; - - /// The value is present. It may still be be null. - /// If the value is null, it will be serialized as null. - /// If the value is non-null, it will be serialized as the value. - const factory Value.present(T value) = PresentValue; - - /// Returns the value if present (no matter if null or non-null), otherwise throws a [StateError]. - T? get requireValue => switch (this) { - PresentValue(:final value) => value, - AbsentValue() => throw StateError("Value is absent"), - }; - - /// return the value if present and non-null, otherwise null. - /// this is useful for cases where you don't care between the value being absent or null. - T? get valueOrNull => switch (this) { - PresentValue(:final value) => value, - AbsentValue() => null, - }; - - bool get isPresent => switch (this) { - PresentValue() => true, - AbsentValue() => false, - }; -} - -class AbsentValue extends Value { - const AbsentValue() : super._(); -} - -class PresentValue extends Value { - final T? value; - - const PresentValue(this.value) : super._(); - - @override - bool operator ==(Object other) => - identical(this, other) || - other is PresentValue && - runtimeType == other.runtimeType && - value == other.value; - - @override - int get hashCode => value.hashCode; -} diff --git a/links/gql_exec/pubspec.yaml b/links/gql_exec/pubspec.yaml index 9136d8ee..16c5f325 100644 --- a/links/gql_exec/pubspec.yaml +++ b/links/gql_exec/pubspec.yaml @@ -1,5 +1,5 @@ name: gql_exec -version: 1.0.0 +version: 1.1.0 description: Basis for GraphQL execution layer to support Link and Client. repository: https://github.com/gql-dart/gql environment: