Skip to content

Commit e210fb2

Browse files
seantleonardSean Leonard
andauthored
Dev/seleonar/incr metadata client providers (#12)
* Merged PR 649012: Generalize ClientProvider, ConfigurationProvider, and DB Connection Configuration Introducing changes to abstract out DatabaseCredentials, ClientProvider with changes to accomodate this in the ConfigurationProvider and Startup classes. Configuration files updated to accommodate interpreting database type during startup and configuration initialization. # Why this change is needed The first step in extending the POC to be compatible with SQL Database is through generalizing the database credentials classes, the clientproviders, and configuration provider. # How Describe how the change works. ##Startup class - Infers DatabaseType from _appsettings.json_ . The DatabaseType determines the implementation of _IClientProvider_. ##IDatabaseCredentials interface - created to capture overlap between SQL and Cosmos connections which is the ConnectionString. I chose _ConnectionString_ over _EndpointURL_ as the interface member because connectionstring is a superset of endpointurl for both database types. Can leave database specific details such as username, password, access keys to the specific class implementations. Future work to accommodate Postgres TBD because Postgres requires connectionstring to be built. ##IClientProvider interface - Created to capture overlap between clients. ClientProvider class must implement getClient(). Client initialization adhering to initial Cosmos POC model of Singletons. - Generic interface types expected: - SQL: SqlConnection - Cosmos: CosmosClient - Current PR utilizes Cosmos implementation of Singleton for connection. I want to get E2E working here first before optimizing further for collection of connections, which is implemented in SQLREST project. ##ConfigurationProvider - On initialization, the instance (Singleton enforced) reads from _appsettings.json_ to determine which DbCredential to create. ##Appsettings.json - Added proposed new db configuration structure to be read in by the configuration provider and startup class. The config specifies the database type to instruct which credentials class to implement (SQL/Cosmos). - Specific credentials classes created to accommodate future need to build the connection string. ``` json "DatabaseConnection": { "DatabaseType": "COSMOS", "Credentials": { "ServerEndpointUrl": "", "AuthorizationKey": "", "Container": "", "Database": "", "ConnectionString": "" } } ``` # Test Integration testing by calling REST endpoint to add and query schema. Addition test class written for ClientProvider to validate opening SQL connection succeeds. # Checklist - [X] Build and run test locally. - [ ] Check code coverage report and make sure that there are test coverage for your change. - [X] Link work item to this change. - [ ] Update the design/functional docs. added README to the section on testing Related work items: #1333552 * Merged PR 654028: Create FileMetadataStoreProvider to read GraphQL config from file #Summary Initial work to create FileMetadataStoreProvider, enables reading JSON config from file. Renamed interface to IMetadataStoreProvider. Sample Config.json for runtime config. Gitignore updated to ignore /vs folder. Added two simple integration tests for new fileprovider. # Why this change is needed The first step in extending the POC to be compatible with SQL Database is through generalizing the database credentials classes, the clientproviders, and configuration provider. # How Describe how the change works. ##IMetadataStoreProvider - Files which had previously referenced the interface as MetadataStoreProvider now reference the renamed interface __IMetadataStoreProvider__ ##FileMetadataStoreProvider - Implemented to act us underlying storage of configuration data assuming that configuration is only read once at startup. In this case, the class constructor is responsible for reading the file, storing the GraphQL schema string and saving the Resolvers as key/value pairs into a collection. The Get() calls are similar to the cachedmetadatastoreprovider where a dictionary is used to keep track of resolvername:resolvervalue. ##config.json - Added simplified skeleton of GraphQL configuration file as agreed on during architecture meetings: 1 file with schema and resolvers embedded ``` json { "GraphQLSchema": "", "Resolvers": [ { "engine": "SQL", "name": "bookById", "database": "", "container": "", "parametrizedQuery": "SELECT * from r WHERE r.id = @arg.id", "operationType": "READ_ITEM" }, { "name": "authorById" } ] } ``` ##.gitignore Updated to not track __vs/__ folders within the project, for sanity. # Test Integration testing done by creating MetadataProviderTests class: - Getting schema from config - Getting resolver from config # Checklist - [X] Build and run test locally. - [X] Check code coverage report and make sure that there are test coverage for your change. - [X] Link work item to this change. - [ ] Update the design/functional docs. added README to the section on testing Related work items: #1333554 * Cherrypick FileMetadataProvider and SQL Client Provider + add classdiagram files for visualizing code. * Removed unused IConfigurationProvider file * Addressing PR comments. Renaming Sql references to MSSQL. Adding schema.gql file for development purposes with corresponding logic. Updated class summaries. * Further updates to address comments. PascalCase db types, updated TestBase to pull relavant cosmos config for Query/Mutation simple tests. updated class summary spelling. * PascalCase dbtype in appsettings.json * Removed class diagrams. Added vscode related configuration to correctly run. Also removed implementation/demo specific config.json values. Updated gitignore to not track bin and obj directories. Co-authored-by: Sean Leonard <[email protected]>
1 parent 3a62c56 commit e210fb2

27 files changed

+505
-76
lines changed

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,9 @@ Cosmos.GraphQL.Service/Cosmos.GraphQL.Service.Tests/bin/*
55
Cosmos.GraphQL.Service/Cosmos.GraphQL.Service.Tests/obj/*
66
Cosmos.GraphQL.Service/Cosmos.GraphQL.Service.Tests/.idea/*
77

8-
98
*/.idea/*
9+
10+
# Visual Studio 2015 cache/options directory
11+
.vs/
12+
/Microsoft.Sql.Rest/bin/Debug/net5.0
13+
/Microsoft.Sql.Rest/obj

Cosmos.GraphQL.Service/Cosmos.GraphQL.Service.Tests/Cosmos.GraphQL.Service.Tests.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
<ItemGroup>
1010
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
1111
<PackageReference Include="Moq" Version="4.16.1" />
12-
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
13-
<PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
12+
<PackageReference Include="MSTest.TestAdapter" Version="2.2.6" />
13+
<PackageReference Include="MSTest.TestFramework" Version="2.2.6" />
1414
<PackageReference Include="coverlet.collector" Version="1.3.0" />
1515
</ItemGroup>
1616

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using Cosmos.GraphQL.Service.Resolvers;
2+
using Microsoft.Data.SqlClient;
3+
using Microsoft.VisualStudio.TestTools.UnitTesting;
4+
using System;
5+
using System.Data;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
11+
namespace Cosmos.GraphQL.Service.Tests
12+
{
13+
[TestClass]
14+
public class MSSQLClientProviderTests
15+
{
16+
private IClientProvider<SqlConnection> _clientProvider;
17+
public MSSQLClientProviderTests()
18+
{
19+
_clientProvider = new MSSQLClientProvider();
20+
}
21+
/// <summary>
22+
/// Ensure a connection is successfully opened within the [Database]ClientProvider,
23+
/// given a valid connection string.
24+
/// </summary>
25+
[TestMethod]
26+
public void TestOpenConnection()
27+
{
28+
SqlConnection connection = _clientProvider.getClient();
29+
connection.Open();
30+
Console.WriteLine("ServerVersion: {0}", connection.ServerVersion);
31+
Console.WriteLine("State: {0}", connection.State);
32+
Assert.IsTrue(connection.State.Equals(ConnectionState.Open));
33+
connection.Dispose();
34+
}
35+
}
36+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Cosmos.GraphQL.Services;
7+
using Microsoft.VisualStudio.TestTools.UnitTesting;
8+
9+
namespace Cosmos.GraphQL.Service.Tests
10+
{
11+
[TestClass]
12+
public class MetadataProviderTests
13+
{
14+
IMetadataStoreProvider _fileProvider;
15+
16+
public MetadataProviderTests()
17+
{
18+
_fileProvider = new FileMetadataStoreProvider();
19+
}
20+
21+
[TestMethod]
22+
public void TestGetSchema()
23+
{
24+
Assert.IsNotNull(_fileProvider.GetGraphQLSchema());
25+
}
26+
27+
[TestMethod]
28+
public void TestGetResolver()
29+
{
30+
Assert.IsNotNull(_fileProvider.GetQueryResolver("authorById"));
31+
}
32+
}
33+
}

Cosmos.GraphQL.Service/Cosmos.GraphQL.Service.Tests/SchemaTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public class SchemaTests
1919
public async Task TestAddSchemaAsync()
2020
{
2121
CosmosClientProvider clientProvider = new CosmosClientProvider();
22-
MetadataStoreProvider metadataStoreProvider = new CachedMetadataStoreProvider(new DocumentMetadataStoreProvider(clientProvider));
22+
IMetadataStoreProvider metadataStoreProvider = new CachedMetadataStoreProvider(new DocumentMetadataStoreProvider(clientProvider));
2323
QueryEngine queryEngine = new QueryEngine(clientProvider, metadataStoreProvider);
2424
MutationEngine mutationEngine = new MutationEngine(clientProvider, metadataStoreProvider);
2525
GraphQLService graphQLService = new GraphQLService(queryEngine, mutationEngine, clientProvider, metadataStoreProvider);

Cosmos.GraphQL.Service/Cosmos.GraphQL.Service.Tests/TestBase.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Cosmos.GraphQL.Service.Controllers;
1+
using Cosmos.GraphQL.Service.configurations;
2+
using Cosmos.GraphQL.Service.Controllers;
23
using Cosmos.GraphQL.Service.Models;
34
using Cosmos.GraphQL.Service.Resolvers;
45
using Cosmos.GraphQL.Services;
@@ -20,7 +21,7 @@ public class TestBase
2021
{
2122
internal GraphQLService graphQLService;
2223
internal CosmosClientProvider clientProvider;
23-
internal MetadataStoreProvider metadataStoreProvider;
24+
internal IMetadataStoreProvider metadataStoreProvider;
2425
internal QueryEngine queryEngine;
2526
internal MutationEngine mutationEngine;
2627
internal GraphQLController controller;
@@ -36,7 +37,10 @@ private void Init()
3637
clientProvider = new CosmosClientProvider();
3738
string uid = Guid.NewGuid().ToString();
3839
dynamic sourceItem = TestHelper.GetItem(uid);
39-
clientProvider.getCosmosContainer().CreateItemAsync(sourceItem, new PartitionKey(uid)); // TODO: Make it sync
40+
CosmosCredentials creds = (CosmosCredentials)ConfigurationProvider.getInstance().Creds;
41+
string databaseName = creds.Database;
42+
string containerId = creds.Container;
43+
clientProvider.getClient().GetContainer(databaseName,containerId).CreateItemAsync(sourceItem, new PartitionKey(uid));
4044
metadataStoreProvider = new CachedMetadataStoreProvider(new DocumentMetadataStoreProvider(clientProvider));
4145

4246
queryEngine = new QueryEngine(clientProvider, metadataStoreProvider);
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
// Use IntelliSense to find out which attributes exist for C# debugging
9+
// Use hover for the description of the existing attributes
10+
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
11+
"name": ".NET Core Launch (web)",
12+
"type": "coreclr",
13+
"request": "launch",
14+
"preLaunchTask": "build",
15+
// If you have changed target frameworks, make sure to update the program path.
16+
"program": "${workspaceFolder}/bin/Debug/net5.0/Cosmos.GraphQL.Service.dll",
17+
"args": [],
18+
"cwd": "${workspaceFolder}",
19+
"stopAtEntry": false,
20+
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
21+
"serverReadyAction": {
22+
"action": "openExternally",
23+
"uriFormat": "%s/ui/graphiql",
24+
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
25+
},
26+
"env": {
27+
"ASPNETCORE_ENVIRONMENT": "Development"
28+
},
29+
"sourceFileMap": {
30+
"/Views": "${workspaceFolder}/Views"
31+
}
32+
},
33+
{
34+
"name": ".NET Core Attach",
35+
"type": "coreclr",
36+
"request": "attach"
37+
}
38+
]
39+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"label": "build",
6+
"command": "dotnet",
7+
"type": "process",
8+
"args": [
9+
"build",
10+
"${workspaceFolder}/Cosmos.GraphQL.Service.csproj",
11+
"/property:GenerateFullPaths=true",
12+
"/consoleloggerparameters:NoSummary"
13+
],
14+
"problemMatcher": "$msCompile"
15+
},
16+
{
17+
"label": "publish",
18+
"command": "dotnet",
19+
"type": "process",
20+
"args": [
21+
"publish",
22+
"${workspaceFolder}/Cosmos.GraphQL.Service.csproj",
23+
"/property:GenerateFullPaths=true",
24+
"/consoleloggerparameters:NoSummary"
25+
],
26+
"problemMatcher": "$msCompile"
27+
},
28+
{
29+
"label": "watch",
30+
"command": "dotnet",
31+
"type": "process",
32+
"args": [
33+
"watch",
34+
"run",
35+
"${workspaceFolder}/Cosmos.GraphQL.Service.csproj",
36+
"/property:GenerateFullPaths=true",
37+
"/consoleloggerparameters:NoSummary"
38+
],
39+
"problemMatcher": "$msCompile"
40+
}
41+
]
42+
}

Cosmos.GraphQL.Service/Cosmos.GraphQL.Service/Cosmos.GraphQL.Service.csproj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,31 @@
44
<TargetFramework>net5.0</TargetFramework>
55
</PropertyGroup>
66

7+
<ItemGroup>
8+
<None Remove="schema.gql" />
9+
</ItemGroup>
10+
11+
<ItemGroup>
12+
<Content Include="schema.gql">
13+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
14+
</Content>
15+
</ItemGroup>
16+
717
<ItemGroup>
818
<PackageReference Include="GraphQL" Version="4.5.0" />
919
<PackageReference Include="GraphQL.Server.Ui.GraphiQL" Version="5.0.2" />
1020
<PackageReference Include="GraphQL.SystemTextJson" Version="4.5.0" />
1121
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.18.0" />
1222
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.10.0-3.final" />
23+
<PackageReference Include="Microsoft.Data.SqlClient" Version="3.0.0" />
1324
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0-preview.3.21201.4" />
1425
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0-preview.3.21201.4" />
26+
<PackageReference Include="MSTest.TestAdapter" Version="2.2.6" />
27+
<PackageReference Include="MSTest.TestFramework" Version="2.2.6" />
1528
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
1629
</ItemGroup>
30+
<ItemGroup>
31+
<ProjectCapability Include="CSharp;Managed;ClassDesigner" />
32+
</ItemGroup>
1733

1834
</Project>

Cosmos.GraphQL.Service/Cosmos.GraphQL.Service/Resolvers/CosmosClientProvider.cs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,22 @@
55

66
namespace Cosmos.GraphQL.Service.Resolvers
77
{
8-
public class CosmosClientProvider
8+
public class CosmosClientProvider : IClientProvider<CosmosClient>
99
{
1010
private static CosmosClient _cosmosClient;
1111
private static readonly object syncLock = new object();
1212

1313
private static void init()
1414
{
15-
var cred = ConfigurationProvider.getInstance().cred;
15+
var cred = ConfigurationProvider.getInstance().Creds;
16+
_cosmosClient = new CosmosClientBuilder(cred.ConnectionString).WithContentResponseOnWrite(true).Build();
17+
}
1618

17-
_cosmosClient = new CosmosClientBuilder(cred.EndpointUrl, cred.AuthorizationKey).WithContentResponseOnWrite(true).Build();
18-
// _cosmosClient = new CosmosClient(cred.EndpointUrl, cred.AuthorizationKey).
19+
public CosmosClient getClient()
20+
{
21+
return getCosmosClient();
1922
}
20-
23+
2124
public CosmosClient getCosmosClient()
2225
{
2326
if (_cosmosClient == null)
@@ -33,13 +36,6 @@ public CosmosClient getCosmosClient()
3336

3437
return _cosmosClient;
3538
}
36-
37-
public Container getCosmosContainer()
38-
{
39-
return getCosmosClient().GetDatabase(ConfigurationProvider.getInstance().databaseName)
40-
.GetContainer(ConfigurationProvider.getInstance().containerName);
41-
42-
}
4339
}
4440

4541
}

0 commit comments

Comments
 (0)