public SqlQueryContext Build(SqlQueryContext query, IHaveSelectionSet context, string alias) { query.Select($"{alias}.Id"); query.SplitOn <Person>("Id"); var fields = context.GetSelectedFields(); foreach (var kvp in fields) { switch (kvp.Key) { case "firstName": query.Select($"{alias}.FirstName"); break; case "lastName": query.Select($"{alias}.LastName"); break; case "emails": { var emailAlias = $"{alias}Email"; query.LeftJoin($"Email {emailAlias} ON {alias}.Id = {emailAlias}.PersonId"); query = emailQueryBuilder.Build(query, kvp.Value, emailAlias); } break; case "phones": { var phoneAlias = $"{alias}Phone"; query.LeftJoin($"Phone {phoneAlias} ON {alias}.Id = {phoneAlias}.PersonId"); query = phoneQueryBuilder.Build(query, kvp.Value, phoneAlias); } break; } } return(query); }
public SqlQueryContext Build(SqlQueryContext query, IHaveSelectionSet context, string alias) { query.Select($"{alias}.Id"); query.SplitOn <Person>("Id"); foreach (var field in context.GetSelectedFields()) { switch (field.Key.ToLower()) { case "firstname": query.Select($"{alias}.FirstName"); break; case "lastname": query.Select($"{alias}.LastName"); break; case "address": var addressAlias = $"{alias}Address"; query.InnerJoin($"Addresses {addressAlias} on {alias}.AddressId = {addressAlias}.Id"); query = new AddressQuery().Build(query, field.Value, addressAlias); break; } } return(query); }
public SqlQueryContext Build(SqlQueryContext query, IHaveSelectionSet context, string alias) { query.Select($"{alias}.Form_Id"); query.SplitOn <Form>("Form_Id"); var fields = context.GetSelectedFields(); foreach (var kvp in fields) { switch (kvp.Key) { case "identification": query.Select($"{alias}.Identification"); break; case "formCreationDate": query.Select($"{alias}.FormCreationDate"); break; case "formCreationHour": query.Select($"{alias}.FormCreationHour"); break; case "attestationStatus": query.Select($"{alias}.AttestationStatus"); break; case "typeForm": query.Select($"{alias}.TypeForm"); break; case "employerDeclarations": { var employerDeclarationAlias = $"{alias}EmployerDeclaration"; query.LeftJoin($"EmployerDeclaration {employerDeclarationAlias} ON {alias}.Form_Id = {employerDeclarationAlias}.Form_Id"); query = _employerDeclarationBuilder.Build(query, kvp.Value, employerDeclarationAlias); } break; } } return(query); }
public SqlQueryContext Build(SqlQueryContext query, IHaveSelectionSet context, string alias) { query.Select($"{alias}.Id"); query.SplitOn <City>("Id"); foreach (var field in context.GetSelectedFields()) { switch (field.Key.ToLower()) { case "name": query.Select($"{alias}.Name"); break; case "zipcode": query.Select($"{alias}.ZipCode"); break; case "country": var countryAlias = $"{alias}Country"; query.InnerJoin($"Countries {countryAlias} on {alias}.CountryId = {countryAlias}.Id"); query = new CountryQuery().Build(query, field.Value, countryAlias); break; } } return(query); }
public SqlQueryContext Build(SqlQueryContext query, IHaveSelectionSet context, string alias) { query.Select($"{alias}.Id"); query.SplitOn <Company>("Id"); var fields = context.GetSelectedFields(); if (fields.ContainsKey("name")) { query.Select($"{alias}.Name"); } if (fields.ContainsKey("emails")) { var companyEmailAlias = $"{alias}CompanyEmail"; var emailAlias = $"{alias}Email"; query .LeftJoin($"CompanyEmail {companyEmailAlias} ON {alias}.Id = {companyEmailAlias}.PersonId") .LeftJoin($"Email {emailAlias} ON {companyEmailAlias}.EmailId = {emailAlias}.Id"); query = emailQueryBuilder.Build(query, fields["emails"], emailAlias); } if (fields.ContainsKey("phones")) { var companyPhoneAlias = $"{alias}CompanyPhone"; var phoneAlias = $"{alias}Phone"; query .LeftJoin($"CompanyPhone {companyPhoneAlias} ON {alias}.Id = {companyPhoneAlias}.PersonId") .LeftJoin($"Phone {phoneAlias} ON {companyPhoneAlias}.PhoneId = {phoneAlias}.Id"); query = phoneQueryBuilder.Build(query, fields["phones"], phoneAlias); } return(query); }
public SqlQueryContext Build(SqlQueryContext query, IHaveSelectionSet context, string alias) { query.Select($"{alias}.Id"); query.SplitOn <Person>("Id"); var fields = context.GetSelectedFields(); if (fields.ContainsKey("firstName")) { query.Select($"{alias}.FirstName"); } if (fields.ContainsKey("lastName")) { query.Select($"{alias}.LastName"); } if (fields.ContainsKey("companies")) { var personCompanies = $"{alias}PersonCompany"; var companyAlias = $"{alias}Company"; query .LeftJoin($"PersonCompany {personCompanies} ON {alias}.Id = {personCompanies}.PersonId") .LeftJoin($"Company {companyAlias} ON {personCompanies}.CompanyId = {companyAlias}.Id"); query = emailQueryBuilder.Build(query, fields["companies"], companyAlias); } if (fields.ContainsKey("emails")) { var personEmailAlias = $"{alias}PersonEmail"; var emailAlias = $"{alias}Email"; query .LeftJoin($"PersonEmail {personEmailAlias} ON {alias}.Id = {personEmailAlias}.PersonId") .LeftJoin($"Email {emailAlias} ON {personEmailAlias}.EmailId = {emailAlias}.Id"); query = emailQueryBuilder.Build(query, fields["emails"], emailAlias); } if (fields.ContainsKey("phones")) { var personPhoneAlias = $"{alias}PersonPhone"; var phoneAlias = $"{alias}Phone"; query .LeftJoin($"PersonPhone {personPhoneAlias} ON {alias}.Id = {personPhoneAlias}.PersonId") .LeftJoin($"Phone {phoneAlias} ON {personPhoneAlias}.PhoneId = {phoneAlias}.Id"); query = phoneQueryBuilder.Build(query, fields["phones"], phoneAlias); } if (fields.ContainsKey("supervisor")) { var supervisorAlias = $"{alias}Supervisor"; query.LeftJoin($"Person {supervisorAlias} ON {alias}.SupervisorId = {supervisorAlias}.Id"); query = Build(query, fields["supervisor"], supervisorAlias); } if (fields.ContainsKey("careerCounselor")) { var careerCounselorAlias = $"{alias}CareerCounselor"; query.LeftJoin($"Person {careerCounselorAlias} ON {alias}.CareerCounselorId = {careerCounselorAlias}.Id"); query = Build(query, fields["careerCounselor"], careerCounselorAlias); } return(query); }
/// <summary> /// Returns the inline fragment for the specified entity within the GraphQL selection. /// </summary> /// <typeparam name="TEntityType">The type of entity to retrieve.</typeparam> /// <param name="selectionSet">The GraphQL selection set.</param> /// <returns>The inline framgent associated with the entity.</returns> public static InlineFragment GetInlineFragment <TEntityType>(this IHaveSelectionSet selectionSet) { return(selectionSet .SelectionSet? .Selections? .OfType <InlineFragment>() .Where(f => f.Type?.Name == typeof(TEntityType).Name) .FirstOrDefault()); }
/// <summary> /// Returns a map of selected fields, keyed by the field name. /// </summary> /// <param name="haveSelectionSet">The GraphQL selection set container.</param> /// <returns>A dictionary whose key is the field name, and value is the field contents.</returns> public static IDictionary <string, Field> GetSelectedFields(this IHaveSelectionSet haveSelectionSet) { var fields = haveSelectionSet .SelectionSet .Selections .OfType <Field>() .ToDictionary(field => field.Name); return(fields); }
public Task <IEnumerable <object> > GetAsync( IHaveSelectionSet context, EntityMetadataContext metadata) { return(Task.FromResult(Enumerable.Range(1, 10).Select(e => { var instance = Activator.CreateInstance(metadata.Type); return instance; }))); }
/// <summary> /// For a node with a selection set, returns a list of variable references along with what input type each were referenced for. /// </summary> public List <VariableUsage> GetVariables(IHaveSelectionSet node) { var usages = new List <VariableUsage>(); var info = new TypeInfo(Schema); var listener = new MatchingNodeVisitor <VariableReference, (List <VariableUsage> usages, TypeInfo info)>((usages, info), (varRef, __, state) => state.usages.Add(new VariableUsage(varRef, state.info.GetInputType()))); new BasicVisitor(info, listener).Visit(node, this); return(usages); }
private static string[] GetSelectedFields(this IHaveSelectionSet field) { var fields = field .SelectionSet .Selections .OfType <Field>() .Where(p => !p.SelectionSet.Selections.Any()) .Select(p => p.Name.ToPascalCase()).ToArray(); return(fields); }
/// <summary> /// Returns a map of selected fields, keyed by the field name. /// </summary> /// <param name="selectionSet">The GraphQL selection set container.</param> /// <returns>A dictionary whose key is the field name, and value is the field contents.</returns> public static IDictionary <string, Field> GetSelectedFields(this IHaveSelectionSet selectionSet) { if (selectionSet != null) { var fields = selectionSet .SelectionSet .Selections .OfType <Field>() .ToDictionary(field => field.Name, StringComparer.OrdinalIgnoreCase); return(fields); } return(null); }
public SqlQueryContext Build(SqlQueryContext query, IHaveSelectionSet context, string alias) { query.Select($"{alias}.Id"); query.SplitOn <Person>("Id"); var fields = context.GetSelectedFields(); foreach (var kvp in fields) { switch (kvp.Key) { case "firstName": query.Select($"{alias}.FirstName"); break; case "lastName": query.Select($"{alias}.LastName"); break; case "emails": { var emailAlias = $"{alias}Email"; query.LeftJoin($"Email {emailAlias} ON {alias}.Id = {emailAlias}.PersonId"); query = emailQueryBuilder.Build(query, kvp.Value, emailAlias); } break; case "phones": { var phoneAlias = $"{alias}Phone"; query.LeftJoin($"Phone {phoneAlias} ON {alias}.Id = {phoneAlias}.PersonId"); query = phoneQueryBuilder.Build(query, kvp.Value, phoneAlias); } break; } } if (fields.ContainsKey("supervisor")) { var supervisorAlias = $"{alias}Supervisor"; query.LeftJoin($"Person {supervisorAlias} ON {alias}.SupervisorId = {supervisorAlias}.Id"); query = Build(query, fields["supervisor"], supervisorAlias); } if (fields.ContainsKey("careerCounselor")) { var careerCounselorAlias = $"{alias}CareerCounselor"; query.LeftJoin($"Person {careerCounselorAlias} ON {alias}.CareerCounselorId = {careerCounselorAlias}.Id"); query = Build(query, fields["careerCounselor"], careerCounselorAlias); } return(query); }
public SqlQueryContext Build(SqlQueryContext query, IHaveSelectionSet context, string alias) { // Always get the ID of the email query.Select($"{alias}.Id"); // Tell Dapper where the Email class begins (at the Id we just selected) query.SplitOn <Email>("Id"); var fields = context.GetSelectedFields(); if (fields.ContainsKey("address")) { query.Select($"{alias}.Address"); } return(query); }
public SqlQueryContext Build(SqlQueryContext query, IHaveSelectionSet context, string alias) { query.Select($"{alias}.Id"); query.SplitOn <Email>("Id"); var fields = context.GetSelectedFields(); foreach (var kvp in fields) { switch (kvp.Key) { case "address": query.Select($"{alias}.Address"); break; } } return(query); }
public List <VariableUsage> GetVariables(IHaveSelectionSet node) { var usages = new List <VariableUsage>(); var info = new TypeInfo(Schema); var listener = new EnterLeaveListener(_ => { _.Match <VariableReference>( varRef => usages.Add(new VariableUsage(varRef, info.GetInputType())) ); }); var visitor = new BasicVisitor(info, listener); visitor.Visit(node); return(usages); }
/// <summary> /// Builds an entity mapper for the given entity type. /// </summary> /// <typeparam name="TEntityType">The type of entity to be mapped.</typeparam> /// <param name="resolve">A function that, given one or more entities, resolves to an entity instance to which child entities will be added.</param> /// <param name="selectionSet">The GraphQL selection set (optional).</param> /// <param name="splitOn">The types the query is split on.</param> /// <param name="shouldFilterDuplicates">True if duplicate objects should be filtered, false otherwise.</param> /// <returns>A Dapper mapping function.</returns> public Func <object[], TEntityType> Build <TEntityType>( Func <TEntityType, TEntityType, TEntityType> resolve = null, IHaveSelectionSet selectionSet = null, List <Type> splitOn = null, bool shouldFilterDuplicates = true) where TEntityType : class { if (resolve == null) { // A non-resolver, always resolves to the next object provided. resolve = (previous, current) => current; } // Build an entity mapper for the given type var mapper = serviceProvider.GetService(typeof(IEntityMapper <TEntityType>)) as IEntityMapper <TEntityType>; if (mapper == null) { throw new InvalidOperationException($"Could not find a mapper for type {typeof(IEntityMapper<TEntityType>).Name}"); } TEntityType entity = null; // Setup the mapper to properly resolve its entity mapper.ResolveEntity = e => resolve(entity, e); return(objs => { // Map the object var next = mapper.Map(objs, selectionSet, splitOn); // Return null if we are returning a duplicate object if (shouldFilterDuplicates && object.ReferenceEquals(next, entity)) { return null; } // Save a reference to the entity entity = next; // And, return it return entity; }); }
public SqlQueryContext Build(SqlQueryContext query, IHaveSelectionSet context, string alias) { query.Select($"{alias}.Id"); query.SplitOn <Phone>("Id"); var fields = context.GetSelectedFields(); foreach (var kvp in fields) { switch (kvp.Key) { case "number": query.Select($"{alias}.Number"); break; case "type": query.Select($"{alias}.Type"); break; } } return(query); }
public SqlQueryContext Build(SqlQueryContext query, IHaveSelectionSet context, string alias) { query.Select($"{alias}.EmployerDeclaration_Id"); query.SplitOn <EmployerDeclaration>("EmployerDeclaration_Id"); var fields = context.GetSelectedFields(); foreach (var kvp in fields) { switch (kvp.Key) { case "quarter": query.Select($"{alias}.Quarter"); break; case "CompanyID": query.Select($"{alias}.CompanyID"); break; case "EmployerDeclaration_Id": query.Select($"{alias}.EmployerDeclaration_Id"); break; } } return(query); }
public SqlQueryContext Build(SqlQueryContext query, IHaveSelectionSet context, string alias) { query.Select($"{alias}.Id"); query.SplitOn <Country>("Id"); foreach (var field in context.GetSelectedFields()) { switch (field.Key.ToLower()) { case "name": query.Select($"{alias}.Name"); break; case "isocode": query.Select($"{alias}.IsoCode"); break; } } return(query); }
/// <summary> /// Builds an entity mapper for the given entity type. /// </summary> /// <typeparam name="TEntityType">The type of entity to be mapped.</typeparam> /// <param name="resolve">A function that compares two values on the entity for equality, usually comparing primary keys.</param> /// <param name="selectionSet">The GraphQL selection set (optional).</param> /// <param name="splitOn">The types the query is split on.</param> /// <returns>A Dapper mapping function.</returns> public Func <object[], TEntityType> Build <TEntityType>( Func <TEntityType, object> selector, IHaveSelectionSet selectionSet = null, List <Type> splitOn = null) where TEntityType : class { var resolve = new Func <TEntityType, TEntityType, TEntityType>( (previous, current) => { TEntityType result = current; if (previous != null) { // Compare against values on the objects (usually a primary key) result = object.Equals(selector(previous), selector(current)) ? previous : current; } return(result); } ); // Build the mapper return(Build(resolve, selectionSet, splitOn)); }
public override Form Map(object[] objs, IHaveSelectionSet selectionSet = null, List <Type> splitOn = null) { Form employee = null; foreach (var obj in objs) { if (employee == null && obj is Form p) { employee = ResolveEntity(p); continue; } if (obj is EmployerDeclaration employerDeclaration && employee.EmployerDeclarations != null) { var employerDeclarationMapper = _entityMapperFactory.Build <EmployerDeclaration>( employerDeclarations => (employerDeclarations.EmployerDeclaration_Id), selectionSet, splitOn ); var result = employerDeclarationMapper(objs); if (!employee.EmployerDeclarations.Any(declaration => declaration.EmployerDeclaration_Id == employerDeclaration.EmployerDeclaration_Id)) { employee.EmployerDeclarations.Add(result); } else { var declaration = employee.EmployerDeclarations.FirstOrDefault(x => x.EmployerDeclaration_Id == result.EmployerDeclaration_Id); if (declaration != null) { ((List <NaturalPerson>)declaration.NaturalPersons).AddRange(result.NaturalPersons); } } } } return(employee); }
public SqlQueryContext Build(SqlQueryContext query, IHaveSelectionSet context, string alias) { query.Select($"{alias}.Id"); query.SplitOn <Address>("Id"); foreach (var field in context.GetSelectedFields()) { switch (field.Key.ToLower()) { case "street": query.Select($"{alias}.Street"); break; case "city": var cityAlias = $"{alias}City"; query.InnerJoin($"Cities {cityAlias} on {alias}.CityId = {cityAlias}.Id"); query = new CityQuery().Build(query, field.Value, cityAlias); break; } } return(query); }
public override EmployerDeclaration Map(object[] objs, IHaveSelectionSet selectionSet = null, List <Type> splitOn = null) { EmployerDeclaration declaration = null; foreach (var obj in objs) { if (declaration == null && obj is EmployerDeclaration p) { declaration = ResolveEntity(p); } //if (obj is NaturalPerson naturalPerson && declaration != null && declaration.NaturalPersons != null) //{ // var naturalPersonMapper = _entityMapperFactory.Build<NaturalPerson>( // naaturalPerson => (naaturalPerson.NaturalPerson_Id), // selectionSet, // splitOn // ); // var result = naturalPersonMapper(objs); // if (!declaration.NaturalPersons.Any(_ => _.NaturalPerson_Id == naturalPerson.NaturalPerson_Id)) // declaration.NaturalPersons.Add(result); // else // { // //var person = declaration.NaturalPersons.FirstOrDefault(x => // // x.NaturalPerson_Id == result.NaturalPerson_Id); // //if (person != null) // //{ // // ((List<WorkerRecord>)person.WorkerRecords).AddRange(result.WorkerRecords); // //} // } //} } return(declaration); }
/// <summary> /// Maps a row of data to an entity. /// </summary> /// <param name="objs">A row objects to be mapped.</param> /// <param name="selectionSet">The GraphQL selection set (optional).</param> /// <param name="splitOn">The types the query is split on.</param> /// <returns>The mapped entity, or null if the entity has previously been returned.</returns> public abstract TEntityType Map( object[] objs, IHaveSelectionSet selectionSet = null, List <Type> splitOn = null);
public override Person Map( object[] objs, IHaveSelectionSet selectionSet = null, List <Type> splitOn = null) { Person person = null; foreach (var obj in objs) { if (person == null && obj is Person p) { person = ResolveEntity(p); continue; } if (obj is Email email && // Eliminate duplicates !person.Emails.Any(e => e.Address == email.Address)) { person.Emails.Add(email); continue; } if (obj is Phone phone && // Eliminate duplicates !person.Phones.Any(ph => ph.Number == phone.Number)) { person.Phones.Add(phone); continue; } } if (selectionSet != null) { var fields = selectionSet.GetSelectedFields(); int supervisorIndex = -1; // Start at 1 to skip the "first" person object in the list, // which is the person we just mapped. int startingIndex = 1; // NOTE: order matters here, if both supervisor // and careerCounselor exist, then supervisor must appear // first in the list. This order is guaranteed in PersonQueryBuilder. if (fields.ContainsKey("supervisor")) { supervisorIndex = splitOn.IndexOf(typeof(Person), startingIndex); if (supervisorIndex >= 0) { person.Supervisor = objs[supervisorIndex] as Person; } } if (fields.ContainsKey("careerCounselor")) { var careerCounselorIndex = splitOn.IndexOf(typeof(Person), Math.Max(startingIndex, supervisorIndex + 1)); if (careerCounselorIndex >= 0) { person.CareerCounselor = objs[careerCounselorIndex] as Person; } } } return(person); }
/// <summary> /// Maps the next object from Dapper. /// </summary> /// <typeparam name="TItemType">The item type to be mapped.</typeparam> /// <param name="context">The context used to map object from Dapper.</param> /// <param name="fieldNames">The names of one or more GraphQL fields associated with the item.</param> /// <param name="entityMapper">An optional entity mapper. This is used to map complex objects from Dapper mapping results.</param> /// <returns>The mapped item.</returns> public TItemType Next <TItemType>( IEnumerable <string> fieldNames, Func <IDictionary <string, Field>, IHaveSelectionSet, IHaveSelectionSet> getSelectionSet, IEntityMapper <TItemType> entityMapper = null) where TItemType : class { if (fieldNames == null) { throw new ArgumentNullException(nameof(fieldNames)); } if (ItemEnumerator == null || SplitOnEnumerator == null) { throw new NotSupportedException("Cannot call Next() before calling Start()"); } lock (LockObject) { var keys = fieldNames.Intersect(CurrentSelectionSet.Keys); if (keys.Any()) { TItemType item = default(TItemType); while ( ItemEnumerator.MoveNext() && SplitOnEnumerator.MoveNext()) { // Whether a non-null object exists at this position or not, // the SplitOn is expecting this type here, so we will yield it. if (SplitOnEnumerator.Current == typeof(TItemType)) { item = ItemEnumerator.Current as TItemType; break; } } if (entityMapper != null) { // Determine where the next entity mapper will get its selection set from IHaveSelectionSet selectionSet = getSelectionSet(CurrentSelectionSet, SelectionSet); var nextContext = new EntityMapContext { Items = Items.Skip(MappedCount), SelectionSet = selectionSet, SplitOn = SplitOn.Skip(MappedCount), }; using (nextContext) { item = entityMapper.Map(nextContext); // Update enumerators to skip past items already mapped var mappedCount = nextContext.MappedCount; MappedCount += nextContext.MappedCount; int i = 0; while ( // Less 1, the next time we iterate we // will advance by 1 as part of the iteration. i < mappedCount - 1 && ItemEnumerator.MoveNext() && SplitOnEnumerator.MoveNext()) { i++; } } } else { MappedCount++; } return(item); } } return(default(TItemType)); }
public IEnumerable<VariableUsage> GetVariables(IHaveSelectionSet node) { var usages = new List<VariableUsage>(); var info = new TypeInfo(Schema); var listener = new EnterLeaveListener(_ => { _.Match<VariableReference>( varRef => usages.Add(new VariableUsage {Node = varRef, Type = info.GetInputType()}) ); }); var visitor = new BasicVisitor(info, listener); visitor.Visit(node); return usages; }
private static SqlGenerationContext GenerateSQL( IHaveSelectionSet context, EntityMetadataContext metadata, SqlGenerationContext sqlContext = null, SQLOperation operation = SQLOperation.SELECT, int level = 0, string parentAlias = null, EntityMetadataRelation relationMetadata = null) { if (sqlContext == null) { sqlContext = new SqlGenerationContext(); } var key = metadata.Keys.Values.ToArray(); var schema = metadata.CustomMetadata.TryGetValue(Globals.CUSTOM_METADATA_SCHEMA, out var customSchema) ? customSchema : "dbo"; var table = metadata.CustomMetadata.TryGetValue(Globals.CUSTOM_METADATA_TABLE, out var customTable) ? customTable : metadata.Type.Name; var queriedFields = context.GetSelectedFields(); var alias = GetAlias(level); var entityFields = metadata.Included.Keys .Select(f => f.ToLower()) .Intersect(queriedFields.Keys) .Select(f => new { field = $"{f}", exp = $"{alias}.[{f}]" }) .ToArray(); sqlContext.SelectFields.AddRange(entityFields); sqlContext.SplitOnTypes.Add(metadata.Type); if (level > 0) { sqlContext.SplitOnFields.Add(entityFields.First().field); } if (operation == SQLOperation.SELECT) { sqlContext.Sql = $"SELECT %fields% FROM [{schema}].[{table}] {alias}"; foreach (var field in queriedFields) { if (metadata.Relations.TryGetValue(field.Key.ToLower(), out var relation)) { sqlContext.Relations.Add(relation); GenerateSQL( field.Value, relation.EntityRight, sqlContext, operation: SQLOperation.JOIN, level: level + 1, parentAlias: alias, relationMetadata: relation ); } } } else if (operation == SQLOperation.JOIN) { if (relationMetadata.IsCollection) { sqlContext.Sql += $" LEFT JOIN [{schema}].[{table}] {alias} ON {ManyForeignKeyCriteria(parentAlias, alias, relationMetadata)}"; } else { sqlContext.Sql += $" LEFT JOIN [{schema}].[{table}] {alias} ON {SingleForeignKeyCriteria(parentAlias, alias, relationMetadata)}"; } } if (level == 0) { sqlContext.Sql = sqlContext.Sql.Replace("%fields%", string.Join(",", sqlContext.SelectFields.Select(x => x.exp))); } return(sqlContext); }
public SqlQueryContext Build(SqlQueryContext query, IHaveSelectionSet context, string alias) { var mergedAlias = $"{alias}Merged"; // Deduplicate the person query.LeftJoin($"Person {mergedAlias} ON {alias}.MergedToPersonId = {mergedAlias}.MergedToPersonId"); query.Select($"{alias}.Id", $"{alias}.MergedToPersonId"); query.SplitOn <Person>("Id"); var fields = QueryBuilderHelper.CollectFields(context.SelectionSet); if (QueryBuilderHelper.IsConnection(context.SelectionSet)) { query.Select($"{alias}.CreateDate"); } if (fields.ContainsKey("firstName")) { query.Select($"{mergedAlias}.FirstName"); } if (fields.ContainsKey("lastName")) { query.Select($"{mergedAlias}.LastName"); } if (fields.ContainsKey("companies")) { var personCompanyAlias = $"{alias}PersonCompany"; var companyAlias = $"{alias}Company"; query .LeftJoin($"PersonCompany {personCompanyAlias} ON {mergedAlias}.Id = {personCompanyAlias}.PersonId") .LeftJoin($"Company {companyAlias} ON {personCompanyAlias}.CompanyId = {companyAlias}.Id"); query = companyQueryBuilder.Build(query, fields["companies"], companyAlias); } if (fields.ContainsKey("emails")) { var personEmailAlias = $"{alias}PersonEmail"; var emailAlias = $"{alias}Email"; query .LeftJoin($"PersonEmail {personEmailAlias} ON {mergedAlias}.Id = {personEmailAlias}.PersonId") .LeftJoin($"Email {emailAlias} ON {personEmailAlias}.EmailId = {emailAlias}.Id"); query = emailQueryBuilder.Build(query, fields["emails"], emailAlias); } if (fields.ContainsKey("phones")) { var personPhoneAlias = $"{alias}PersonPhone"; var phoneAlias = $"{alias}Phone"; query .LeftJoin($"PersonPhone {personPhoneAlias} ON {mergedAlias}.Id = {personPhoneAlias}.PersonId") .LeftJoin($"Phone {phoneAlias} ON {personPhoneAlias}.PhoneId = {phoneAlias}.Id"); query = phoneQueryBuilder.Build(query, fields["phones"], phoneAlias); } if (fields.ContainsKey("supervisor")) { var supervisorAlias = $"{alias}Supervisor"; query.LeftJoin($"Person {supervisorAlias} ON {mergedAlias}.SupervisorId = {supervisorAlias}.Id"); query = Build(query, fields["supervisor"], supervisorAlias); } if (fields.ContainsKey("careerCounselor")) { var careerCounselorAlias = $"{alias}CareerCounselor"; query.LeftJoin($"Person {careerCounselorAlias} ON {mergedAlias}.CareerCounselorId = {careerCounselorAlias}.Id"); query = Build(query, fields["careerCounselor"], careerCounselorAlias); } return(query); }
public async Task <IEnumerable <dynamic> > GetAsync( IHaveSelectionSet context, EntityMetadataContext metadata) { using (var connection = connectionFactory()) { var sql = GenerateSQL(context, metadata); HashSet <object>[] mapping = Enumerable.Range(1, sql.SplitOnTypes.Count()) .Select(x => new HashSet <object>()) .ToArray(); List <dynamic>[] objectCache = Enumerable.Range(1, sql.SplitOnTypes.Count()) .Select(x => new List <dynamic>()) .ToArray(); object[] lastEntities = new dynamic[sql.SplitOnTypes.Count()]; (await connection.QueryAsync <dynamic>( sql.Sql, sql.SplitOnTypes.ToArray(), splitOn: string.Join(",", sql.SplitOnFields), map: (entities) => { object result = entities[0]; int i = 0; foreach (var entity in entities) { var entityKey = i == 0 ? metadata.PrimaryKey(entity) : sql.Relations[i - 1].EntityRight.PrimaryKey(entity); if (mapping[i].Contains(entityKey)) { if (i == 0) { result = null; } } else { if (lastEntities[i] != null) { if (i < objectCache.Length - 1) { foreach (var obj in objectCache[i + 1]) { if (sql.Relations[i].IsCollection) { sql.Relations[i].Add(lastEntities[i], obj); } else { sql.Relations[i].Set(lastEntities[i], obj); } } objectCache[i + 1].Clear(); mapping[i + 1].Clear(); } } objectCache[i].Add(entity); mapping[i].Add(entityKey); lastEntities[i] = entity; } i++; } return(result); } )).ToArray(); int idx = 0; foreach (var entity in lastEntities) { if (entity != null) { if (idx < objectCache.Length - 1) { foreach (var obj in objectCache[idx + 1]) { if (sql.Relations[idx].IsCollection) { sql.Relations[idx].Add(entity, obj); } else { sql.Relations[idx].Set(entity, obj); } } objectCache[idx + 1].Clear(); } } idx++; } return(objectCache[0]); } }