mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-13 19:33:55 +03:00
feat: Make naming-convention
feature generally available
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/10214 GitOrigin-RevId: ad99b6e4ad6dbab2b0c6fa7a09b48dcd4d06ee1f
This commit is contained in:
parent
1ffdff66a9
commit
76936f0972
@ -530,7 +530,7 @@ List of experimental features to be enabled.
|
||||
| **Flag** | `--experimental-features <FEATURES>` |
|
||||
| **Env var** | `HASURA_GRAPHQL_EXPERIMENTAL_FEATURES` |
|
||||
| **Accepted values** | String (Comma-separated list) |
|
||||
| **Options** | `inherited_roles`, `optimize_permission_filters`, `naming_convention`, `streaming_subscriptions`, `apollo_federation`, `hide_update_many_fields`, `bigquery_string_numeric_input`, `hide_aggregation_predicates`, `hide_stream_fields`, `disable_postgres_arrays` |
|
||||
| **Options** | `inherited_roles`, `optimize_permission_filters`, `naming_convention` (deprecated), `streaming_subscriptions`, `apollo_federation`, `hide_update_many_fields`, `bigquery_string_numeric_input`, `hide_aggregation_predicates`, `hide_stream_fields`, `disable_postgres_arrays` |
|
||||
| **Default** | `null` |
|
||||
| **Supported in** | CE, Enterprise Edition, Cloud |
|
||||
|
||||
|
@ -125,20 +125,7 @@ understand which fields are available and how they can be used.
|
||||
Not to worry. Hasura can help us simplify this by allowing us to customize the root-level fields of our sources. This
|
||||
means that we can add a namespace to each database, keeping each set of fields organized.
|
||||
|
||||
To do this, we first need to set an environment variable for our project. In Hasura Cloud, your environment variables
|
||||
are controlled via the project's settings. You can reach these by clicking on the name of your project in the top-right
|
||||
corner of the Console.
|
||||
|
||||
Then, click on the `Env vars` in the project's sidebar and `+ New Env Var` before entering
|
||||
`HASURA_GRAPHQL_EXPERIMENTAL_FEATURES` and setting its value to `naming_convention`:
|
||||
|
||||
<Thumbnail
|
||||
src="/img/resources/use-case/access-layer/add-env-var.png"
|
||||
alt="Adding an environment variable to Hasura"
|
||||
width="1000px"
|
||||
/>
|
||||
|
||||
Finally, head back to the `Data` tab of the Console and choose `Data Manager` in the side bar. Click `Edit` for our
|
||||
To do this, head to the `Data` tab of the Console and choose `Data Manager` in the side bar. Click `Edit` for our
|
||||
`Banking` source:
|
||||
|
||||
<Thumbnail
|
||||
|
@ -24,13 +24,6 @@ import GraphiQLIDE from '@site/src/components/GraphiQLIDE';
|
||||
The Hasura GraphQL Engine generates names for various schema objects (fields, types, arguments, etc.) and the naming
|
||||
convention for these autogenerated names can be customized to suit your needs.
|
||||
|
||||
:::tip Note
|
||||
|
||||
Naming conventions are an experimental feature and can be enabled by adding `naming_convention` to the
|
||||
`HASURA_GRAPHQL_EXPERIMENTAL_FEATURES` environment variable array or with the server flag `--experimental-feature`.
|
||||
|
||||
:::
|
||||
|
||||
:::note Supported from
|
||||
|
||||
Naming conventions are available at version `v2.8.0` and higher.
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 60 KiB |
@ -1,34 +1,11 @@
|
||||
module Hasura.GraphQL.Schema.NamingCase
|
||||
( isGraphqlCase,
|
||||
hasNamingConventionChanged,
|
||||
)
|
||||
where
|
||||
|
||||
import Data.HashSet qualified as Set
|
||||
import Hasura.Prelude
|
||||
import Hasura.RQL.Types.NamingCase
|
||||
import Hasura.Server.Types (ExperimentalFeature (..))
|
||||
|
||||
isGraphqlCase :: NamingCase -> Bool
|
||||
isGraphqlCase GraphqlCase = True
|
||||
isGraphqlCase _ = False
|
||||
|
||||
-- | Check if naming convention has changed
|
||||
-- The value of naming convention depends on whether the naming convention is enabled
|
||||
-- in experimental features and what the default naming convention
|
||||
-- (`HASURA_GRAPHQL_DEFAULT_NAMING_CONVENTION`) is hence use both these values to
|
||||
-- decide if naming convention has changed
|
||||
hasNamingConventionChanged :: (Set.HashSet ExperimentalFeature, NamingCase) -> (Set.HashSet ExperimentalFeature, NamingCase) -> Bool
|
||||
hasNamingConventionChanged (prevExperimentalFeatures, prevDefaultNamingCase) (currExperimentalFeatures, currDefaultNamingCase) =
|
||||
case ((EFNamingConventions `elem` prevExperimentalFeatures, prevDefaultNamingCase), (EFNamingConventions `elem` currExperimentalFeatures, currDefaultNamingCase)) of
|
||||
-- naming convention has been enabled, and the default naming convention is not
|
||||
-- HasuraCase then the naming convention has changed
|
||||
((False, _), (True, GraphqlCase)) -> True
|
||||
-- naming is enabled but the default naming convention changes, then the naming
|
||||
-- convention has changed
|
||||
((True, GraphqlCase), (True, HasuraCase)) -> True
|
||||
((True, HasuraCase), (True, GraphqlCase)) -> True
|
||||
-- graphql-case naming convention has been disabled, then the naming convention
|
||||
-- changes
|
||||
((True, GraphqlCase), (False, _)) -> True
|
||||
_ -> False
|
||||
|
@ -60,7 +60,6 @@ import Data.Word (Word16)
|
||||
import GHC.AssertNF.CPP
|
||||
import GHC.Int (Int64)
|
||||
import Hasura.GraphQL.ParameterizedQueryHash (ParameterizedQueryHash)
|
||||
import Hasura.GraphQL.Schema.NamingCase (hasNamingConventionChanged)
|
||||
import Hasura.GraphQL.Transport.HTTP.Protocol
|
||||
import Hasura.GraphQL.Transport.WebSocket.Protocol
|
||||
import Hasura.Logging qualified as L
|
||||
@ -421,7 +420,7 @@ websocketConnectionReaper getLatestConfig getSchemaCache ws@(WSServer _ userConf
|
||||
hasBigqueryStringNumericInputChanged = bigqueryStringNumericInput currSqlGenCtx /= bigqueryStringNumericInput prevSqlGenCtx
|
||||
hasHideAggregationPredicatesChanged = (EFHideAggregationPredicates `elem` currExperimentalFeatures) && (EFHideAggregationPredicates `elem` prevExperimentalFeatures)
|
||||
hasHideStreamFieldsChanged = (EFHideStreamFields `elem` currExperimentalFeatures) && (EFHideStreamFields `elem` prevExperimentalFeatures)
|
||||
hasDefaultNamingCaseChanged = hasNamingConventionChanged (prevExperimentalFeatures, prevDefaultNamingCase) (currExperimentalFeatures, currDefaultNamingCase)
|
||||
hasDefaultNamingCaseChanged = prevDefaultNamingCase /= currDefaultNamingCase
|
||||
if
|
||||
-- if CORS policy has changed, close all connections
|
||||
| hasCorsPolicyChanged ->
|
||||
|
@ -88,7 +88,6 @@ import Hasura.RQL.Types.EventTrigger
|
||||
import Hasura.RQL.Types.Metadata
|
||||
import Hasura.RQL.Types.Metadata.Backend
|
||||
import Hasura.RQL.Types.Metadata.Object
|
||||
import Hasura.RQL.Types.NamingCase
|
||||
import Hasura.RQL.Types.OpenTelemetry
|
||||
import Hasura.RQL.Types.QueryCollection
|
||||
import Hasura.RQL.Types.Relationships.Remote
|
||||
@ -865,13 +864,10 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
|
||||
-- not forcing the evaluation here results in a measurable negative impact
|
||||
-- on memory residency as measured by our benchmark
|
||||
let !defaultNC = _cdcDefaultNamingConvention dynamicConfig
|
||||
!isNamingConventionEnabled = EFNamingConventions `elem` (_cdcExperimentalFeatures dynamicConfig)
|
||||
!namingConv <-
|
||||
bindA
|
||||
-<
|
||||
if isNamingConventionEnabled
|
||||
then getNamingCase sourceCustomization (namingConventionSupport @b) defaultNC
|
||||
else pure HasuraCase
|
||||
getNamingCase sourceCustomization (namingConventionSupport @b) defaultNC
|
||||
let resolvedCustomization = mkResolvedSourceCustomization sourceCustomization namingConv
|
||||
|
||||
-- sql functions
|
||||
@ -1225,7 +1221,6 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
|
||||
((remoteSchemaInvalidationKeys, orderedRoles, fmap encJToLBS . siRemotes <$> storedIntrospection, _cdcSchemaSampledFeatureFlags dynamicConfig), InsOrdHashMap.elems remoteSchemas)
|
||||
let remoteSchemaCtxMap = HashMap.map fst remoteSchemaMap
|
||||
!defaultNC = _cdcDefaultNamingConvention dynamicConfig
|
||||
!isNamingConventionEnabled = EFNamingConventions `elem` (_cdcExperimentalFeatures dynamicConfig)
|
||||
|
||||
let backendInvalidationKeys = Inc.selectD #_ikBackends invalidationKeys
|
||||
backendCache <- resolveBackendCache -< (backendInvalidationKeys, BackendMap.elems backendConfigs)
|
||||
@ -1239,7 +1234,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
|
||||
Inc.keyed
|
||||
( \_ exists ->
|
||||
AB.dispatchAnyBackendArrow @BackendMetadata @BackendEventTrigger
|
||||
( proc (backendInfoAndSourceMetadata :: BackendInfoAndSourceMetadata b, (dynamicConfig, invalidationKeys, storedIntrospection, defaultNC, isNamingConventionEnabled)) -> do
|
||||
( proc (backendInfoAndSourceMetadata :: BackendInfoAndSourceMetadata b, (dynamicConfig, invalidationKeys, storedIntrospection, defaultNC)) -> do
|
||||
let sourceMetadata = _bcasmSourceMetadata backendInfoAndSourceMetadata
|
||||
sourceName = _smName sourceMetadata
|
||||
sourceInvalidationsKeys = Inc.selectD #_ikSources invalidationKeys
|
||||
@ -1258,7 +1253,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
|
||||
let metadataInvalidationKey = Inc.selectD #_ikMetadata invalidationKeys
|
||||
(tableInputs, _, _) = unzip3 $ map mkTableInputs $ InsOrdHashMap.elems $ _smTables sourceMetadata
|
||||
scNamingConvention = _scNamingConvention $ _smCustomization sourceMetadata
|
||||
!namingConv = if isNamingConventionEnabled then fromMaybe defaultNC scNamingConvention else HasuraCase
|
||||
!namingConv = fromMaybe defaultNC scNamingConvention
|
||||
tablesCoreInfo <-
|
||||
buildTableCache
|
||||
-<
|
||||
@ -1297,7 +1292,7 @@ buildSchemaCacheRule logger env mSchemaRegistryContext = proc (MetadataWithResou
|
||||
$ PartiallyResolvedSource sourceMetadata sourceConfig source tablesCoreInfo eventTriggerInfoMaps
|
||||
)
|
||||
-<
|
||||
(exists, (dynamicConfig, invalidationKeys, storedIntrospection, defaultNC, isNamingConventionEnabled))
|
||||
(exists, (dynamicConfig, invalidationKeys, storedIntrospection, defaultNC))
|
||||
)
|
||||
|)
|
||||
(HashMap.fromList $ InsOrdHashMap.toList backendInfoAndSourceMetadata)
|
||||
|
@ -79,6 +79,8 @@ newtype InstanceId = InstanceId {getInstanceId :: Text}
|
||||
generateInstanceId :: IO InstanceId
|
||||
generateInstanceId = InstanceId <$> generateFingerprint
|
||||
|
||||
{-# DEPRECATED EFNamingConventions "The naming-convention experimental feature is now globally enabled" #-}
|
||||
|
||||
data ExperimentalFeature
|
||||
= EFInheritedRoles
|
||||
| EFOptimizePermissionFilters
|
||||
|
@ -1236,23 +1236,23 @@ mkServeOptionsSpec =
|
||||
rawServeOptions = emptyServeOptionsRaw
|
||||
-- When
|
||||
-- When
|
||||
env = [(UUT._envVar UUT.experimentalFeaturesOption, "inherited_roles,optimize_permission_filters,naming_convention")]
|
||||
env = [(UUT._envVar UUT.experimentalFeaturesOption, "inherited_roles,optimize_permission_filters")]
|
||||
-- Then
|
||||
result = UUT.runWithEnv env (UUT.mkServeOptions @Hasura rawServeOptions)
|
||||
|
||||
fmap (UUT.soExperimentalFeatures) result
|
||||
`Hspec.shouldBe` Right (Set.fromList [Types.EFInheritedRoles, Types.EFOptimizePermissionFilters, Types.EFNamingConventions])
|
||||
`Hspec.shouldBe` Right (Set.fromList [Types.EFInheritedRoles, Types.EFOptimizePermissionFilters])
|
||||
|
||||
Hspec.it "Arg > Env" $ do
|
||||
let -- Given
|
||||
rawServeOptions = emptyServeOptionsRaw {UUT.rsoExperimentalFeatures = Just (Set.fromList [Types.EFInheritedRoles, Types.EFOptimizePermissionFilters, Types.EFNamingConventions])}
|
||||
rawServeOptions = emptyServeOptionsRaw {UUT.rsoExperimentalFeatures = Just (Set.fromList [Types.EFInheritedRoles, Types.EFOptimizePermissionFilters])}
|
||||
-- When
|
||||
env = [(UUT._envVar UUT.experimentalFeaturesOption, "inherited_roles")]
|
||||
-- Then
|
||||
result = UUT.runWithEnv env (UUT.mkServeOptions @Hasura rawServeOptions)
|
||||
|
||||
fmap (UUT.soExperimentalFeatures) result
|
||||
`Hspec.shouldBe` Right (Set.fromList [Types.EFInheritedRoles, Types.EFOptimizePermissionFilters, Types.EFNamingConventions])
|
||||
`Hspec.shouldBe` Right (Set.fromList [Types.EFInheritedRoles, Types.EFOptimizePermissionFilters])
|
||||
|
||||
Hspec.describe "soEventsFetchBatchSize" $ do
|
||||
Hspec.it "Env > Nothing" $ do
|
||||
|
@ -1,158 +0,0 @@
|
||||
- description: create table 1
|
||||
url: /v1/query
|
||||
status: 200
|
||||
response:
|
||||
result_type: CommandOk
|
||||
result:
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
source: pg1
|
||||
sql: |
|
||||
create table author_local(
|
||||
id serial primary key,
|
||||
author_name text unique
|
||||
);
|
||||
INSERT INTO author_local (author_name)
|
||||
VALUES ('Author 1'), ('Author 2');
|
||||
|
||||
- description: track table
|
||||
url: /v1/metadata
|
||||
status: 200
|
||||
response:
|
||||
message: success
|
||||
query:
|
||||
type: pg_track_table
|
||||
args:
|
||||
table: author_local
|
||||
source: pg1
|
||||
|
||||
- description: Simple GraphQL query to fetch items from the source table
|
||||
url: /v1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
author_local:
|
||||
- id: 1
|
||||
author_name: "Author 1"
|
||||
__typename: author_local
|
||||
- id: 2
|
||||
author_name: "Author 2"
|
||||
__typename: author_local
|
||||
query:
|
||||
query: |
|
||||
query {
|
||||
author_local {
|
||||
id
|
||||
author_name
|
||||
__typename
|
||||
}
|
||||
}
|
||||
|
||||
- description: Lookup by pk
|
||||
url: /v1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
author_local_by_pk:
|
||||
id: 1
|
||||
author_name: "Author 1"
|
||||
__typename: author_local
|
||||
query:
|
||||
query: |
|
||||
query {
|
||||
author_local_by_pk(id: 1) {
|
||||
id
|
||||
author_name
|
||||
__typename
|
||||
}
|
||||
}
|
||||
|
||||
- description: Aggregate
|
||||
url: /v1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
author_local_aggregate:
|
||||
__typename: author_local_aggregate
|
||||
aggregate:
|
||||
__typename: author_local_aggregate_fields
|
||||
count: 1
|
||||
query:
|
||||
query: |
|
||||
query MyQuery {
|
||||
author_local_aggregate(where: {author_name: {_eq: "Author 2"}}) {
|
||||
__typename
|
||||
aggregate {
|
||||
__typename
|
||||
count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- description: Insert
|
||||
url: /v1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
insert_author_local:
|
||||
__typename: author_local_mutation_response
|
||||
returning:
|
||||
- __typename: author_local
|
||||
id: 3
|
||||
author_name: Author 3
|
||||
query:
|
||||
query: |
|
||||
mutation MyMutation {
|
||||
insert_author_local(objects: {author_name: "Author 3", id: 3}) {
|
||||
__typename
|
||||
returning {
|
||||
__typename
|
||||
id
|
||||
author_name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- description: Delete by pk
|
||||
url: /v1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
delete_author_local_by_pk:
|
||||
__typename: author_local
|
||||
id: 3
|
||||
author_name: Author 3
|
||||
query:
|
||||
query: |
|
||||
mutation MyMutation {
|
||||
delete_author_local_by_pk(id: 3) {
|
||||
__typename
|
||||
id
|
||||
author_name
|
||||
}
|
||||
}
|
||||
|
||||
- description: untrack table
|
||||
url: /v1/metadata
|
||||
status: 200
|
||||
response:
|
||||
message: success
|
||||
query:
|
||||
type: pg_untrack_table
|
||||
args:
|
||||
table: author_local
|
||||
source: pg1
|
||||
|
||||
- description: drop table
|
||||
url: /v1/query
|
||||
status: 200
|
||||
response:
|
||||
result_type: CommandOk
|
||||
result:
|
||||
query:
|
||||
type: run_sql
|
||||
args:
|
||||
source: pg1
|
||||
sql: |
|
||||
drop table author_local;
|
@ -2,7 +2,6 @@ import pytest
|
||||
|
||||
from validate import check_query_f
|
||||
|
||||
@pytest.mark.hge_env('HASURA_GRAPHQL_EXPERIMENTAL_FEATURES', 'naming_convention')
|
||||
class TestNamingConventions:
|
||||
|
||||
@classmethod
|
||||
@ -19,7 +18,6 @@ class TestNamingConventions:
|
||||
def test_enum_value_convention(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/enum_value_convention.yaml')
|
||||
|
||||
@pytest.mark.hge_env('HASURA_GRAPHQL_EXPERIMENTAL_FEATURES', 'naming_convention')
|
||||
class TestNamingConventionsTypeAndFieldNamesGraphqlDefault:
|
||||
|
||||
@classmethod
|
||||
@ -33,7 +31,6 @@ class TestNamingConventionsTypeAndFieldNamesGraphqlDefault:
|
||||
def test_type_and_field_names(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/type_and_field_names_graphql_default.yaml')
|
||||
|
||||
@pytest.mark.hge_env('HASURA_GRAPHQL_EXPERIMENTAL_FEATURES', 'naming_convention')
|
||||
class TestNamingConventionsTypeAndFieldNamesHasuraDefault:
|
||||
|
||||
@classmethod
|
||||
@ -47,7 +44,6 @@ class TestNamingConventionsTypeAndFieldNamesHasuraDefault:
|
||||
def test_type_and_field_names(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/type_and_field_names_hasura_default.yaml')
|
||||
|
||||
@pytest.mark.hge_env('HASURA_GRAPHQL_EXPERIMENTAL_FEATURES', 'naming_convention')
|
||||
class TestNamingConventionsTypeAndFieldNamesGraphqlDefaultWithPrefixAndSuffix:
|
||||
|
||||
@classmethod
|
||||
@ -67,7 +63,6 @@ class TestNamingConventionsTypeAndFieldNamesGraphqlDefaultWithPrefixAndSuffix:
|
||||
def test_type_and_field_names_with_prefix_and_suffix(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/type_and_field_names_graphql_default_with_prefix_and_suffix.yaml')
|
||||
|
||||
@pytest.mark.hge_env('HASURA_GRAPHQL_EXPERIMENTAL_FEATURES', 'naming_convention')
|
||||
class TestNamingConventionsTypeAndFieldNamesHasuraDefaultWithPrefixAndSuffix:
|
||||
|
||||
@classmethod
|
||||
@ -88,7 +83,6 @@ class TestNamingConventionsTypeAndFieldNamesHasuraDefaultWithPrefixAndSuffix:
|
||||
check_query_f(hge_ctx, self.dir() + '/type_and_field_names_hasura_default_with_prefix_and_suffix.yaml')
|
||||
|
||||
@pytest.mark.backend('mssql')
|
||||
@pytest.mark.hge_env('HASURA_GRAPHQL_EXPERIMENTAL_FEATURES', 'naming_convention')
|
||||
class TestNamingConventionsFailure:
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
@ -120,7 +114,6 @@ class TestNamingConventionsFailure:
|
||||
"error": "sources other than postgres do not support graphql-default as naming convention yet",
|
||||
}
|
||||
|
||||
@pytest.mark.hge_env('HASURA_GRAPHQL_EXPERIMENTAL_FEATURES', 'naming_convention')
|
||||
@pytest.mark.hge_env('HASURA_GRAPHQL_DEFAULT_NAMING_CONVENTION', 'graphql-default')
|
||||
class TestDefaultNamingConvention:
|
||||
|
||||
@ -134,17 +127,3 @@ class TestDefaultNamingConvention:
|
||||
|
||||
def test_default_global_naming_convention(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/default_global_naming_convention.yaml')
|
||||
|
||||
@pytest.mark.hge_env('HASURA_GRAPHQL_EXPERIMENTAL_FEATURES', None) # must be unset
|
||||
class TestNamingConventionWithoutExperimentalFeature:
|
||||
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
return "queries/naming_conventions"
|
||||
|
||||
@pytest.fixture(scope='class', autouse=True)
|
||||
def add_customized_source(self, add_source):
|
||||
add_source('pg1', customization={'naming_convention': 'graphql-default'})
|
||||
|
||||
def test_naming_convention_without_feature_turned_on(self, hge_ctx):
|
||||
check_query_f(hge_ctx, self.dir() + '/naming_convention_without_feature_turned_on.yaml')
|
||||
|
Loading…
Reference in New Issue
Block a user