Skip to content

Commit

Permalink
Merge pull request #200 from mixcore/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
Smilefounder authored Mar 5, 2020
2 parents ec792b3 + 4cd458f commit e14423c
Show file tree
Hide file tree
Showing 136 changed files with 25,117 additions and 6,743 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ ModelManifest.xml
# Source
.gitignore
src/Mix.Cms.Web.old
src/Mix.Cms.Web/appsettings.json
src/Mix.Cms.Web/appsettings.*.*
src/Mix.Cms.Web/wwwroot/content/*
src/Mix.Cms.Web/wwwroot/Exports/*
src/Mix.Cms.Web/Exports
Expand All @@ -261,4 +261,5 @@ src/Mix.Cms.Web.old/
src/Mix.Cms.Web/wwwroot/edms/

src/portal-app/
src/Mix.Cms.Webbk
src/Mix.Cms.Webbk
src/ref
1 change: 1 addition & 0 deletions src/EntityGraphQL
Submodule EntityGraphQL added at c44bb4
41 changes: 41 additions & 0 deletions src/Mix.Cms.Api.GraphQL/Controllers/GraphqlController.cs
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 src/Mix.Cms.Api.GraphQL/Infrastructure/DbContextExtensions.cs
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);
}
}
55 changes: 55 additions & 0 deletions src/Mix.Cms.Api.GraphQL/Infrastructure/GraphQLQuery.cs
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
)
});
}
}
}
}
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();
}
}
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 src/Mix.Cms.Api.GraphQL/Infrastructure/Models/ColumnMetadata.cs
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 src/Mix.Cms.Api.GraphQL/Infrastructure/Models/DatabaseMetadata.cs
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 src/Mix.Cms.Api.GraphQL/Infrastructure/Models/QueryRequest.cs
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 src/Mix.Cms.Api.GraphQL/Infrastructure/Models/TableMetadata.cs
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 src/Mix.Cms.Api.GraphQL/Infrastructure/Models/TableNameLookup.cs
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);
}
}
}
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);
}
}
}
Loading

0 comments on commit e14423c

Please sign in to comment.