-
-
Notifications
You must be signed in to change notification settings - Fork 207
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #200 from mixcore/develop
Develop
- Loading branch information
Showing
136 changed files
with
25,117 additions
and
6,743 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submodule EntityGraphQL
added at
c44bb4
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using System.Threading.Tasks; | ||
using GraphQL; | ||
using GraphQL.Types; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Mix.Cms.Lib.Models.Cms; | ||
using Mix.Cms.Api.GraphQL.Infrastructure.Models; | ||
|
||
namespace Mix.Cms.Api.GraphQL.Controllers | ||
{ | ||
[Route("api/graphql")] | ||
[ApiController] | ||
public class GraphqlController : ControllerBase | ||
{ | ||
private static readonly Schema graphQLSchema; | ||
static GraphqlController() | ||
{ | ||
var dbContext = new MixCmsContext(); | ||
var tableNameLookup = new TableNameLookup(); | ||
var metaDatabase = new DatabaseMetadata(dbContext, tableNameLookup); | ||
var schema = new Schema { Query = new Mix.Cms.Api.GraphQL.Infrastructure.GraphQLQuery(dbContext, metaDatabase, tableNameLookup) }; | ||
schema.Initialize(); | ||
graphQLSchema = schema; | ||
} | ||
[HttpPost] | ||
public async Task<ActionResult> Get([FromBody] QueryRequest query) | ||
{ | ||
var result = await new DocumentExecuter().ExecuteAsync( | ||
new ExecutionOptions() | ||
{ | ||
Schema = graphQLSchema, | ||
Query = query.Query | ||
} | ||
).ConfigureAwait(false); | ||
if (result.Errors?.Count > 0) | ||
{ | ||
return BadRequest(result.Errors); | ||
} | ||
return Ok(result); | ||
} | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
src/Mix.Cms.Api.GraphQL/Infrastructure/DbContextExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using Microsoft.EntityFrameworkCore; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Threading.Tasks; | ||
|
||
namespace Mix.Cms.Api.GraphQL.Infrastructure | ||
{ | ||
public static class DbContextExtensions | ||
{ | ||
public static IQueryable Query(this DbContext context, string entityName) => | ||
context.Query(context.Model.FindEntityType(entityName).ClrType); | ||
static readonly MethodInfo SetMethod = typeof(DbContext).GetMethod(nameof(DbContext.Set)); | ||
public static IQueryable Query(this DbContext context, Type entityType) => | ||
(IQueryable)SetMethod.MakeGenericMethod(entityType).Invoke(context, null); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
using GraphQL.Types; | ||
using Microsoft.EntityFrameworkCore; | ||
using Mix.Cms.Api.GraphQL.Infrastructure.Interfaces; | ||
using System; | ||
using System.Linq; | ||
using System.Reflection; | ||
|
||
namespace Mix.Cms.Api.GraphQL.Infrastructure | ||
{ | ||
public class GraphQLQuery : ObjectGraphType<object> | ||
{ | ||
private IDatabaseMetadata _dbMetadata; | ||
private ITableNameLookup _tableNameLookup; | ||
private DbContext _dbContext; | ||
public GraphQLQuery( | ||
DbContext dbContext, | ||
IDatabaseMetadata dbMetadata, | ||
ITableNameLookup tableNameLookup) | ||
{ | ||
_dbMetadata = dbMetadata; | ||
_tableNameLookup = tableNameLookup; | ||
_dbContext = dbContext; | ||
Name = "Query"; | ||
var assem = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.ManifestModule.Name == "Mix.Cms.Lib.dll"); | ||
|
||
foreach (var metaTable in _dbMetadata.GetTableMetadatas()) | ||
{ | ||
var type = assem.GetType(metaTable.AssemblyFullName); | ||
var tableType = new TableType(metaTable, type); | ||
var friendlyTableName = metaTable.TableName; | ||
// _tableNameLookup.GetFriendlyName(metaTable.TableName); | ||
AddField(new FieldType | ||
{ | ||
Name = friendlyTableName, | ||
Type = tableType.GetType(), | ||
ResolvedType = tableType, | ||
Resolver = new MyFieldResolver(metaTable, _dbContext), | ||
Arguments = new QueryArguments(tableType.TableArgs) | ||
}); | ||
// lets add key to get list of current table | ||
var listType = new ListGraphType(tableType); | ||
AddField(new FieldType | ||
{ | ||
Name = $"{friendlyTableName}_list", | ||
Type = listType.GetType(), | ||
ResolvedType = listType, | ||
Resolver = new MyFieldResolver(metaTable, _dbContext), | ||
Arguments = new QueryArguments( | ||
tableType.TableArgs | ||
) | ||
}); | ||
} | ||
} | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
src/Mix.Cms.Api.GraphQL/Infrastructure/Interfaces/IDatabaseMetadata.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.EntityFrameworkCore.Metadata; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
|
||
namespace Mix.Cms.Api.GraphQL.Infrastructure.Interfaces | ||
{ | ||
public interface IDatabaseMetadata | ||
{ | ||
void ReloadMetadata(); | ||
IEnumerable<TableMetadata> GetTableMetadatas(); | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
src/Mix.Cms.Api.GraphQL/Infrastructure/Interfaces/ITableNameLookup.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
|
||
namespace Mix.Cms.Api.GraphQL.Infrastructure.Interfaces | ||
{ | ||
public interface ITableNameLookup | ||
{ | ||
bool InsertKeyName(string friendlyName); | ||
string GetFriendlyName(string correctName); | ||
} | ||
|
||
} |
13 changes: 13 additions & 0 deletions
13
src/Mix.Cms.Api.GraphQL/Infrastructure/Models/ColumnMetadata.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
|
||
namespace Mix.Cms.Api.GraphQL.Infrastructure | ||
{ | ||
public class ColumnMetadata | ||
{ | ||
public string ColumnName { get; set; } | ||
public string DataType { get; set; } | ||
} | ||
} |
61 changes: 61 additions & 0 deletions
61
src/Mix.Cms.Api.GraphQL/Infrastructure/Models/DatabaseMetadata.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.EntityFrameworkCore.Metadata; | ||
using Mix.Cms.Api.GraphQL.Infrastructure.Interfaces; | ||
using System.Collections.Generic; | ||
|
||
namespace Mix.Cms.Api.GraphQL.Infrastructure.Models | ||
{ | ||
public sealed class DatabaseMetadata : IDatabaseMetadata | ||
{ | ||
private readonly DbContext _dbContext; | ||
private readonly ITableNameLookup _tableNameLookup; | ||
private string _databaseName; | ||
private IEnumerable<TableMetadata> _tables; | ||
public DatabaseMetadata(DbContext dbContext, ITableNameLookup tableNameLookup) | ||
{ | ||
_dbContext = dbContext; | ||
_tableNameLookup = tableNameLookup; | ||
_databaseName = _dbContext.Database.GetDbConnection().Database; | ||
if (_tables == null) | ||
ReloadMetadata(); | ||
} | ||
public IEnumerable<TableMetadata> GetTableMetadatas() | ||
{ | ||
if (_tables == null) | ||
return new List<TableMetadata>(); return _tables; | ||
} | ||
public void ReloadMetadata() | ||
{ | ||
_tables = FetchTableMetaData(); | ||
} | ||
private IReadOnlyList<TableMetadata> FetchTableMetaData() | ||
{ | ||
var metaTables = new List<TableMetadata>(); | ||
foreach (var entityType in _dbContext.Model.GetEntityTypes()) | ||
{ | ||
var tableName = entityType.GetTableName(); | ||
metaTables.Add(new TableMetadata | ||
{ | ||
TableName = tableName, | ||
AssemblyFullName = entityType.ClrType.FullName, | ||
Columns = GetColumnsMetadata(entityType) | ||
}); | ||
_tableNameLookup.InsertKeyName(tableName); | ||
} | ||
|
||
return metaTables; | ||
} | ||
private IReadOnlyList<ColumnMetadata> GetColumnsMetadata(IEntityType entityType) | ||
{ | ||
var tableColumns = new List<ColumnMetadata>(); foreach (var propertyType in entityType.GetProperties()) | ||
{ | ||
tableColumns.Add(new ColumnMetadata | ||
{ | ||
ColumnName = propertyType.GetColumnName(), | ||
DataType = propertyType.GetColumnType() | ||
}); | ||
} | ||
return tableColumns; | ||
} | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
src/Mix.Cms.Api.GraphQL/Infrastructure/Models/QueryRequest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using Newtonsoft.Json.Linq; | ||
|
||
namespace Mix.Cms.Api.GraphQL.Infrastructure.Models | ||
{ | ||
public class QueryRequest | ||
{ | ||
public string OperationName { get; set; } | ||
public string NamedQuery { get; set; } | ||
public string Query { get; set; } | ||
public JObject Variables { get; set; } | ||
} | ||
|
||
} |
14 changes: 14 additions & 0 deletions
14
src/Mix.Cms.Api.GraphQL/Infrastructure/Models/TableMetadata.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
|
||
namespace Mix.Cms.Api.GraphQL.Infrastructure | ||
{ | ||
public class TableMetadata | ||
{ | ||
public string TableName { get; set; } | ||
public string AssemblyFullName { get; set; } | ||
public IEnumerable<ColumnMetadata> Columns { get; set; } | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
src/Mix.Cms.Api.GraphQL/Infrastructure/Models/TableNameLookup.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
using Mix.Cms.Api.GraphQL.Infrastructure.Interfaces; | ||
using System; | ||
using System.Collections.Generic; | ||
|
||
namespace Mix.Cms.Api.GraphQL.Infrastructure.Models | ||
{ | ||
public class TableNameLookup : ITableNameLookup | ||
{ | ||
private IDictionary<string, string> _lookupTable = new Dictionary<string, string>(); public bool InsertKeyName(string correctName) | ||
{ | ||
if (!_lookupTable.ContainsKey(correctName)) | ||
{ | ||
var friendlyName = CanonicalName(correctName); | ||
_lookupTable.Add(correctName, friendlyName); | ||
return true; | ||
} | ||
return false; | ||
} | ||
public string GetFriendlyName(string correctName) | ||
{ | ||
if (!_lookupTable.TryGetValue(correctName, out string value)) | ||
throw new Exception($"Could not get {correctName} out of the list."); | ||
return value; | ||
} | ||
private string CanonicalName(string correctName) | ||
{ | ||
var index = correctName.LastIndexOf("_"); var result = correctName.Substring( | ||
index + 1, | ||
correctName.Length - index - 1); return Char.ToLowerInvariant(result[0]) + result.Substring(1); | ||
} | ||
} | ||
} |
83 changes: 83 additions & 0 deletions
83
src/Mix.Cms.Api.GraphQL/Infrastructure/Resolvers/MyFieldResolver.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
using GraphQL; | ||
using GraphQL.Resolvers; | ||
using GraphQL.Types; | ||
using Microsoft.EntityFrameworkCore; | ||
using Mix.Cms.Lib.Extensions; | ||
using Mix.Domain.Data.Repository; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Linq.Dynamic.Core; | ||
using System.Linq.Expressions; | ||
using System.Reflection; | ||
using System.Threading.Tasks; | ||
|
||
namespace Mix.Cms.Api.GraphQL.Infrastructure | ||
{ | ||
public class MyFieldResolver: IFieldResolver | ||
{ | ||
private TableMetadata _tableMetadata; | ||
private Type _type; | ||
//private DefaultModelRepository<DbContext _repo; | ||
private DbContext _dbContext; | ||
public MyFieldResolver(TableMetadata tableMetadata, DbContext dbContext) | ||
{ | ||
_tableMetadata = tableMetadata; | ||
_dbContext = dbContext; | ||
} | ||
public object Resolve(ResolveFieldContext context) | ||
{ | ||
var queryable = _dbContext.Query(_tableMetadata.AssemblyFullName); | ||
|
||
// Get filters | ||
string predicates = string.Empty; | ||
int paramsCount = -1; | ||
var filters = context.Arguments.Where(c => c.Key != "first" && c.Key != "offset"); | ||
object[] args = new object[filters.Count()]; | ||
LambdaExpression lamda = null; | ||
|
||
foreach (var item in filters) | ||
{ | ||
paramsCount++; | ||
if (!string.IsNullOrEmpty(predicates)) | ||
{ | ||
predicates += " and "; | ||
} | ||
args[paramsCount] = item.Value; | ||
predicates += $"{item.Key.ToTitleCase()} == @{paramsCount}"; | ||
|
||
} | ||
|
||
if (context.FieldName.Contains("_list")) | ||
{ | ||
var first = context.Arguments["first"] != null ? | ||
context.GetArgument("first", int.MaxValue) : int.MaxValue; | ||
var offset = context.Arguments["offset"] != null ? | ||
context.GetArgument("offset", 0) : 0; | ||
|
||
if (paramsCount >= 0) | ||
{ | ||
|
||
queryable = queryable.Where(lamda); | ||
} | ||
|
||
return queryable.Skip(offset).Take(first).ToDynamicList<object>(); | ||
} | ||
else | ||
{ | ||
return paramsCount >= 0 ? queryable.FirstOrDefault(predicates, args) : null; | ||
} | ||
} | ||
protected LambdaExpression GetLambda(string propName, bool isGetDefault = false) | ||
{ | ||
var parameter = Expression.Parameter(_type); | ||
var prop = Array.Find(_type.GetProperties(), p => p.Name == propName); | ||
if (prop == null && isGetDefault) | ||
{ | ||
propName = _type.GetProperties().FirstOrDefault()?.Name; | ||
} | ||
var memberExpression = Expression.Property(parameter, propName); | ||
return Expression.Lambda(memberExpression, parameter); | ||
} | ||
} | ||
} |
Oops, something went wrong.