Пример #1
0
        /// <summary>
        /// Hack the particular query
        /// </summary>
        public bool HackQuery(QueryBuilder builder, SqlStatement sqlStatement, SqlStatement whereClause, PropertyInfo property, String queryPrefix, QueryPredicate predicate, object values, IEnumerable <TableMapping> scopedTables)
        {
            // Hack mnemonic queries
            if (typeof(Concept).IsAssignableFrom(property.PropertyType) && predicate.SubPath == "mnemonic")
            {
                // Has this already been joined?
                var declType    = TableMapping.Get(this.m_mapper.MapModelType(property.DeclaringType));
                var keyProperty = property.PropertyType == typeof(Guid) ? property : property.DeclaringType.GetRuntimeProperty(property.Name + "Key");
                var declProp    = declType.GetColumn(this.m_mapper.MapModelProperty(property.DeclaringType, declType.OrmType, keyProperty));
                if (declProp.ForeignKey == null)
                {
                    return(false);                            // No FK link
                }
                var    tblMap       = TableMapping.Get(this.m_mapper.MapModelType(property.PropertyType));
                var    fkTbl        = TableMapping.Get(declProp.ForeignKey.Table);
                string directFkName = $"{queryPrefix}{fkTbl.TableName}";

                // We have to join to the FK table
                if (!declProp.IsAlwaysJoin)
                {
                    var fkColumn = fkTbl.GetColumn(declProp.ForeignKey.Column);
                    sqlStatement.Append($" INNER JOIN {fkTbl.TableName} AS {directFkName}_{declProp.Name} ON ({queryPrefix}{declType.TableName}.{declProp.Name} = {directFkName}_{declProp.Name}.{fkColumn.Name})");
                    directFkName += $"_{declProp.Name}";
                }

                // We aren't yet joined to our table, we need to join to our table though!!!!
                if (declProp.ForeignKey.Table != tblMap.OrmType)
                {
                    var fkKeyColumn = fkTbl.Columns.FirstOrDefault(o => o.ForeignKey?.Table == tblMap.OrmType && o.Name == tblMap.PrimaryKey.First().Name) ??
                                      tblMap.Columns.FirstOrDefault(o => o.ForeignKey?.Table == fkTbl.OrmType && o.Name == fkTbl.PrimaryKey.First().Name);
                    if (fkKeyColumn == null)
                    {
                        return(false);                     // couldn't find the FK link
                    }
                    // Now we want to filter our FK
                    var tblName = $"{queryPrefix}{declProp.Name}_{tblMap.TableName}";
                    sqlStatement.Append($" INNER JOIN {tblMap.TableName} AS {tblName} ON ({directFkName}.{fkKeyColumn.Name} = {tblName}.{fkKeyColumn.Name})");

                    // Append the where clause
                    whereClause.And(builder.CreateWhereCondition(property.PropertyType, predicate.SubPath, values, $"{queryPrefix}{declProp.Name}_", new List <TableMapping>()
                    {
                        tblMap
                    }));

                    // Add obslt_utc version?
                    if (typeof(IDbBaseData).IsAssignableFrom(tblMap.OrmType))
                    {
                        whereClause.And($"{tblName}.{tblMap.GetColumn(nameof(IDbBaseData.ObsoletionTime)).Name} IS NULL");
                    }
                }

                return(true);
            }
            else
            {
                return(false);
            }
        }
        /// <summary>
        /// Query hack for creation time
        /// </summary>
        public bool HackQuery(QueryBuilder builder, SqlStatement sqlStatement, SqlStatement whereClause, Type tmodel, PropertyInfo property, string queryPrefix, QueryPredicate predicate, object values, IEnumerable <TableMapping> scopedTables, params KeyValuePair <String, object>[] queryFilter)
        {
            if (property.Name == nameof(IBaseEntityData.CreationTime) && typeof(IVersionedEntity).IsAssignableFrom(tmodel)) // filter by first creation time
            {
                // Get the version table (which has
                var ormMap          = scopedTables.SelectMany(o => o.Columns);
                var replacesVersion = ormMap.FirstOrDefault(o => o.SourceProperty.Name == nameof(IDbVersionedData.ReplacesVersionKey));
                var joinCol         = replacesVersion.Table.Columns.FirstOrDefault(o => o.SourceProperty.Name == nameof(IDbVersionedData.Key));

                whereClause.And($"EXISTS (SELECT 1 FROM {replacesVersion.Table.TableName} AS crt{replacesVersion.Table.TableName} WHERE crt{replacesVersion.Table.TableName}.{joinCol.Name} = {queryPrefix}{replacesVersion.Table.TableName}.{joinCol.Name} AND crt{replacesVersion.Table.TableName}.{replacesVersion.Name} IS NULL ");
                whereClause.And(builder.CreateWhereCondition(tmodel, predicate.Path, values, "crt", scopedTables.ToList()));
                whereClause.Append(")");
                return(true);
            }
            return(false);
        }
Пример #3
0
        public bool HackQuery(QueryBuilder builder, SqlStatement sqlStatement, SqlStatement whereClause, Type tmodel, PropertyInfo property, string queryPrefix, QueryPredicate predicate, object values, IEnumerable <TableMapping> scopedTables)
        {
            if (property.Name == "RcptTo" && property.PropertyType.StripGeneric() == typeof(SecurityUser))
            {
                if (predicate.SubPath == "userName")
                {
                    if (!(values is IList))
                    {
                        values = new List <Object>()
                        {
                            values
                        }
                    }
                    ;

                    var    lValues = values as IList;
                    var    secRepo = ApplicationServiceContext.Current.GetService <ISecurityRepositoryService>();
                    Guid[] vals    = lValues.OfType <String>().Select(u => secRepo.GetUser(u)?.Key).OfType <Guid>().ToArray();
                    whereClause.And($"rcptTo IN ({String.Join(",", vals.Select(o => $"X'{BitConverter.ToString(((Guid)o).ToByteArray()).Replace("-", "")}'").ToArray())})");
                    return(true);
                }
                else
                {
                    throw new InvalidOperationException("Cannot map this expression");
                }
            }
            return(false);
        }
    }
Пример #4
0
 /// <summary>
 /// Hack the query
 /// </summary>
 public bool HackQuery(QueryBuilder builder, SqlStatement sqlStatement, SqlStatement whereClause, Type tmodel, PropertyInfo property, string queryPrefix, QueryPredicate predicate, object values, IEnumerable <TableMapping> scopedTables, params KeyValuePair <string, object>[] queryFilter)
 {
     if (typeof(SecurityUser) == tmodel && property.Name == nameof(SecurityUser.UserEntity))
     {
         var userkey         = TableMapping.Get(typeof(DbUserEntity)).GetColumn(nameof(DbUserEntity.SecurityUserKey), false);
         var personSubSelect = builder.CreateQuery <UserEntity>(queryFilter.Select(p => new KeyValuePair <String, Object>(p.Key.Replace("userEntity.", ""), p.Value)), null, userkey);
         var userIdKey       = TableMapping.Get(typeof(DbSecurityUser)).PrimaryKey.FirstOrDefault();
         whereClause.And($"{userIdKey.Name} IN (").Append(personSubSelect).Append(")");
         return(true);
     }
     return(false);
 }
Пример #5
0
        /// <summary>
        /// Get active policies for the specified securable type
        /// </summary>
        public IEnumerable <IPolicyInstance> GetPolicies(object securable)
        {
            List <AdoSecurityPolicyInstance> result = null;


            if (result == null)
            {
                using (DataContext context = this.m_configuration.Provider.GetReadonlyConnection())
                {
                    try
                    {
                        context.Open();


                        // Security device
                        if (securable is Core.Model.Security.SecurityDevice sd)
                        {
                            var query = context.CreateSqlStatement <DbSecurityDevicePolicy>().SelectFrom(typeof(DbSecurityPolicy), typeof(DbSecurityDevicePolicy))
                                        .AutoJoin <DbSecurityPolicy, DbSecurityDevicePolicy>();

                            if (securable is DevicePrincipal dp)
                            {
                                query.AutoJoin <DbSecurityDevice, DbSecurityDevice>()
                                .Where(o => o.PublicId == dp.Identity.Name);

                                var retVal = context.Query <CompositeResult <DbSecurityPolicy, DbSecurityDevicePolicy> >(query)
                                             .AsEnumerable().Select(o => new AdoSecurityPolicyInstance(o.Object2, o.Object1, securable)).ToList();

                                var appClaim = dp.Identities.OfType <Server.Core.Security.ApplicationIdentity>().SingleOrDefault()?.FindAll(SanteDBClaimTypes.Sid).SingleOrDefault() ??
                                               dp.FindAll(SanteDBClaimTypes.SanteDBApplicationIdentifierClaim).SingleOrDefault();

                                // There is an application claim so we want to add the application policies - most restrictive
                                if (appClaim != null)
                                {
                                    var claim = Guid.Parse(appClaim.Value);

                                    var aquery = context.CreateSqlStatement <DbSecurityApplicationPolicy>().SelectFrom(typeof(DbSecurityPolicy), typeof(DbSecurityApplicationPolicy))
                                                 .AutoJoin <DbSecurityPolicy, DbSecurityApplicationPolicy>()
                                                 .Where(o => o.SourceKey == claim);

                                    retVal.AddRange(context.Query <CompositeResult <DbSecurityPolicy, DbSecurityApplicationPolicy> >(aquery).AsEnumerable().Select(o => new AdoSecurityPolicyInstance(o.Object2, o.Object1, securable)));
                                }

                                result = retVal;
                            }
                            else
                            {
                                result = context.Query <CompositeResult <DbSecurityPolicy, DbSecurityDevicePolicy> >(query.Where(o => o.SourceKey == sd.Key))
                                         .AsEnumerable().Select(o => new AdoSecurityPolicyInstance(o.Object2, o.Object1, securable)).ToList();
                            }
                        }
                        else if (securable is Core.Model.Security.SecurityRole sr)
                        {
                            var query = context.CreateSqlStatement <DbSecurityRolePolicy>().SelectFrom(typeof(DbSecurityPolicy), typeof(DbSecurityRolePolicy))
                                        .AutoJoin <DbSecurityPolicy, DbSecurityRolePolicy>()
                                        .Where(o => o.SourceKey == sr.Key);

                            result = context.Query <CompositeResult <DbSecurityPolicy, DbSecurityRolePolicy> >(query)
                                     .AsEnumerable().Select(o => new AdoSecurityPolicyInstance(o.Object2, o.Object1, securable)).ToList();
                        }
                        else if (securable is Core.Model.Security.SecurityApplication sa)
                        {
                            var query = context.CreateSqlStatement <DbSecurityApplicationPolicy>().SelectFrom(typeof(DbSecurityPolicy), typeof(DbSecurityApplicationPolicy))
                                        .AutoJoin <DbSecurityPolicy, DbSecurityApplicationPolicy>();

                            if (securable is ApplicationPrincipal ap)
                            {
                                query.AutoJoin <DbSecurityApplication, DbSecurityApplication>()
                                .Where(o => o.PublicId == ap.Identity.Name);
                            }
                            else
                            {
                                query.Where(o => o.SourceKey == sa.Key);
                            }

                            result = context.Query <CompositeResult <DbSecurityPolicy, DbSecurityApplicationPolicy> >(query)
                                     .AsEnumerable().Select(o => new AdoSecurityPolicyInstance(o.Object2, o.Object1, securable)).ToList();
                        }
                        else if (securable is IPrincipal || securable is IIdentity)
                        {
                            var identity = (securable as IPrincipal)?.Identity ?? securable as IIdentity;

                            IEnumerable <CompositeResult <DbSecurityPolicy, DbSecurityPolicyActionableInstance> > retVal = null;

                            SqlStatement query = null;

                            if (!(identity is Server.Core.Security.ApplicationIdentity) &&
                                !(identity is DeviceIdentity)) // Is this a user based claim?
                            {
                                // Role policies
                                query = context.CreateSqlStatement <DbSecurityRolePolicy>().SelectFrom(typeof(DbSecurityPolicy), typeof(DbSecurityPolicyActionableInstance))
                                        .InnerJoin <DbSecurityRolePolicy, DbSecurityPolicy>(o => o.PolicyKey, o => o.Key)
                                        .InnerJoin <DbSecurityRolePolicy, DbSecurityUserRole>(o => o.SourceKey, o => o.RoleKey)
                                        .InnerJoin <DbSecurityUserRole, DbSecurityUser>(o => o.UserKey, o => o.Key)
                                        .Where <DbSecurityUser>(o => o.UserName.ToLower() == identity.Name.ToLower());

                                retVal = context.Query <CompositeResult <DbSecurityPolicy, DbSecurityPolicyActionableInstance> >(query).AsEnumerable();
                            }

                            // Claims principal, then we want device and app SID
                            if (securable is IClaimsPrincipal cp)
                            {
                                var appClaim = cp.Identities.OfType <Server.Core.Security.ApplicationIdentity>().SingleOrDefault()?.FindAll(SanteDBClaimTypes.Sid).SingleOrDefault() ??
                                               cp.FindAll(SanteDBClaimTypes.SanteDBApplicationIdentifierClaim).SingleOrDefault();
                                var devClaim = cp.Identities.OfType <Server.Core.Security.DeviceIdentity>().SingleOrDefault()?.FindAll(SanteDBClaimTypes.Sid).SingleOrDefault() ??
                                               cp.FindAll(SanteDBClaimTypes.SanteDBDeviceIdentifierClaim).SingleOrDefault();

                                IEnumerable <CompositeResult <DbSecurityPolicy, DbSecurityPolicyActionableInstance> > appDevClaim = null;

                                // There is an application claim so we want to add the application policies - most restrictive
                                if (appClaim != null)
                                {
                                    var claim = Guid.Parse(appClaim.Value);
                                    query = context.CreateSqlStatement <DbSecurityApplicationPolicy>().SelectFrom(typeof(DbSecurityPolicy), typeof(DbSecurityPolicyActionableInstance))
                                            .AutoJoin <DbSecurityPolicy, DbSecurityApplicationPolicy>()
                                            .Where(o => o.SourceKey == claim);

                                    if (retVal != null)
                                    {
                                        var usrPolKeys = retVal.AsEnumerable().Select(o => o.Object2.PolicyKey).ToArray(); // App grant only overrides those policies which already exist on user
                                        query.And <DbSecurityApplicationPolicy>(o => usrPolKeys.Contains(o.PolicyKey));
                                    }

                                    var appResults = context.Query <CompositeResult <DbSecurityPolicy, DbSecurityPolicyActionableInstance> >(query);
                                    appDevClaim = appDevClaim?.Union(appResults) ?? appResults;
                                }

                                // There is an device claim so we want to add the device policies - most restrictive
                                if (devClaim != null)
                                {
                                    var claim = Guid.Parse(devClaim.Value);
                                    query = context.CreateSqlStatement <DbSecurityDevicePolicy>().SelectFrom(typeof(DbSecurityPolicy), typeof(DbSecurityPolicyActionableInstance))
                                            .AutoJoin <DbSecurityPolicy, DbSecurityDevicePolicy>()
                                            .Where(o => o.SourceKey == claim);

                                    if (retVal != null)
                                    {
                                        var usrPolKeys = retVal.Select(o => o.Object2.PolicyKey).ToArray(); // Dev grant only overrides those policies which already exist on user
                                        query.And <DbSecurityDevicePolicy>(o => usrPolKeys.Contains(o.PolicyKey));
                                    }

                                    var devResults = context.Query <CompositeResult <DbSecurityPolicy, DbSecurityPolicyActionableInstance> >(query);
                                    appDevClaim = appDevClaim?.Union(devResults) ?? devResults;
                                }

                                if (appDevClaim != null)
                                {
                                    retVal = retVal?.Union(appDevClaim) ?? appDevClaim;
                                }
                            }

                            result = retVal.AsEnumerable().Select(o => new AdoSecurityPolicyInstance(o.Object2, o.Object1, securable)).ToList();
                            this.m_traceSource.TraceEvent(EventLevel.Verbose, "Principal {0} effective policy set {1}", identity?.Name, String.Join(",", result.Select(o => $"{o.Policy.Oid} [{o.Rule}]")));
                        }
                        else if (securable is Core.Model.Acts.Act pAct)
                        {
                            var query = context.CreateSqlStatement <DbActSecurityPolicy>().SelectFrom(typeof(DbSecurityPolicy), typeof(DbActSecurityPolicy))
                                        .AutoJoin <DbSecurityPolicy, DbActSecurityPolicy>()
                                        .Where(o => o.SourceKey == pAct.Key);

                            result = context.Query <CompositeResult <DbSecurityPolicy, DbActSecurityPolicy> >(query)
                                     .AsEnumerable().Select(o => new AdoSecurityPolicyInstance(o.Object2, o.Object1, securable)).ToList();
                        }
                        else if (securable is Core.Model.Entities.Entity pEntity)
                        {
                            var query = context.CreateSqlStatement <DbEntitySecurityPolicy>().SelectFrom(typeof(DbSecurityPolicy), typeof(DbEntitySecurityPolicy))
                                        .AutoJoin <DbSecurityPolicy, DbEntitySecurityPolicy>()
                                        .Where(o => o.SourceKey == pEntity.Key);

                            result = context.Query <CompositeResult <DbSecurityPolicy, DbEntitySecurityPolicy> >(query)
                                     .AsEnumerable().Select(o => new AdoSecurityPolicyInstance(o.Object2, o.Object1, securable)).ToList();
                        }
                        else if (securable is SecurityUser pUser)
                        {
                            // Join for policies
                            var query = context.CreateSqlStatement <DbSecurityUserRole>().SelectFrom(typeof(DbSecurityPolicy), typeof(DbSecurityRolePolicy))
                                        .InnerJoin <DbSecurityUserRole, DbSecurityRolePolicy>(
                                o => o.RoleKey,
                                o => o.SourceKey
                                )
                                        .InnerJoin <DbSecurityRolePolicy, DbSecurityPolicy>(
                                o => o.PolicyKey,
                                o => o.Key
                                )
                                        .Where <DbSecurityUserRole>(o => o.UserKey == pUser.Key);

                            result = context.Query <CompositeResult <DbSecurityPolicy, DbSecurityRolePolicy> >(query)
                                     .AsEnumerable().Select(o => new AdoSecurityPolicyInstance(o.Object2, o.Object1, securable)).ToList();
                        }
                        else
                        {
                            result = new List <AdoSecurityPolicyInstance>();
                        }
                    }
                    catch (Exception e)
                    {
                        this.m_traceSource.TraceEvent(EventLevel.Error, "Error getting active policies for {0} : {1}", securable, e);
                        throw new Exception($"Error getting active policies for {securable}", e);
                    }
                }
            }
            return(result);
        }
        /// <summary>
        /// Hack query builder based on clause
        /// </summary>
        public bool HackQuery(QueryBuilder builder, SqlStatement sqlStatement, SqlStatement whereClause, Type tmodel, PropertyInfo property, string queryPrefix, QueryPredicate predicate, object values, IEnumerable <TableMapping> scopedTables, params KeyValuePair <String, object>[] queryFilter)
        {
            string columnName = String.Empty;
            Type   scanType   = null;

            // Filter values
            if (typeof(Concept).IsAssignableFrom(property.PropertyType) && predicate.SubPath == "mnemonic")
            {
                Regex removeRegex = null;
                if (predicate.Path == "participationRole" && property.DeclaringType == typeof(ActParticipation))
                {
                    columnName = "rol_cd_id";
                    scanType   = typeof(ActParticipationKey);
                    // We want to remove the inner join for cd_tbl
                    removeRegex = new Regex(@"INNER\sJOIN\scd_tbl\s.*\(.*?rol_cd_id.*");
                }
                else if (predicate.Path == "relationshipType" && property.DeclaringType == typeof(EntityRelationship))
                {
                    columnName  = "rel_typ_cd_id";
                    scanType    = typeof(EntityRelationshipTypeKeys);
                    removeRegex = new Regex(@"INNER\sJOIN\scd_tbl\s.*\(.*?rel_typ_cd_id.*");
                }
                else if (predicate.Path == "relationshipType" && property.DeclaringType == typeof(ActRelationship))
                {
                    columnName  = "rel_typ_cd_id";
                    scanType    = typeof(ActRelationshipTypeKeys);
                    removeRegex = new Regex(@"INNER\sJOIN\scd_tbl\s.*\(.*?rel_typ_cd_id.*");
                }
                else
                {
                    return(false);
                }

                // Now we scan
                List <Object> qValues = new List <object>();
                if (values is IEnumerable)
                {
                    foreach (var i in values as IEnumerable)
                    {
                        var fieldInfo = scanType.GetRuntimeField(i.ToString());
                        if (fieldInfo == null)
                        {
                            return(false);
                        }
                        qValues.Add(fieldInfo.GetValue(null));
                    }
                }
                else
                {
                    var fieldInfo = scanType.GetRuntimeField(values.ToString());
                    if (fieldInfo == null)
                    {
                        return(false);
                    }
                    qValues.Add(fieldInfo.GetValue(null));
                }

                // Now add to query
                whereClause.And($"{columnName} IN ({String.Join(",", qValues.Select(o=>$"'{o}'").ToArray())})");

                // Remove the inner join
                var          remStack = new Stack <SqlStatement>();
                SqlStatement last;
                while (sqlStatement.RemoveLast(out last))
                {
                    var m = removeRegex.Match(last.SQL);
                    if (m.Success)
                    {
                        // The last thing we added was the
                        if (m.Index == 0 && m.Length == last.SQL.Length)
                        {
                            remStack.Pop();
                        }
                        else
                        {
                            sqlStatement.Append(last.SQL.Remove(m.Index, m.Length), last.Arguments.ToArray());
                        }
                        break;
                    }
                    else
                    {
                        remStack.Push(last);
                    }
                }
                while (remStack.Count > 0)
                {
                    sqlStatement.Append(remStack.Pop());
                }
                return(true);
            }
            else
            {
                return(false);
            }
        }
        /// <summary>
        /// Hack the query
        /// </summary>
        public bool HackQuery(QueryBuilder builder, SqlStatement sqlStatement, SqlStatement whereClause, Type tmodel, PropertyInfo property, string queryPrefix, QueryPredicate predicate, object values, IEnumerable <TableMapping> scopedTables, params KeyValuePair <String, object>[] queryFilter)
        {
            String cmpTblType = String.Empty, valTblType = String.Empty, keyName = String.Empty;
            Type   guardType = null, componentType = null;

            // We can attempt to hack the address
            if (typeof(EntityAddress).IsAssignableFrom(tmodel))
            {
                cmpTblType    = "ent_addr_cmp_tbl";
                valTblType    = "ent_addr_cmp_val_tbl";
                guardType     = typeof(AddressComponentKeys);
                componentType = typeof(EntityAddressComponent);
                keyName       = "addr_id";
            }
            else if (typeof(EntityName).IsAssignableFrom(tmodel))
            {
                cmpTblType    = "ent_name_cmp_tbl";
                valTblType    = "phon_val_tbl";
                guardType     = typeof(NameComponentKeys);
                componentType = typeof(EntityNameComponent);
                keyName       = "name_id";
            }
            else
            {
                return(false);
            }

            // Not applicable for us if
            //  - Not a name or address
            //  - Predicate is not component.value
            //  - There is already other where clause stuff
            if (guardType == null ||
                predicate.Path != "component" ||
                predicate.SubPath != "value" ||
                !String.IsNullOrEmpty(whereClause.SQL))
            {
                return(false);
            }

            whereClause.And($" {keyName} IN (SELECT {keyName} FROM  {cmpTblType} AS {queryPrefix}{cmpTblType} ");
            // Filter through other name or address components which may be in the query at this query level
            List <String> componentTypeGuard = new List <String>();
            var           localChar          = 'a';
            int           vCount             = 0;

            foreach (var itm in queryFilter)
            {
                var    pred        = QueryPredicate.Parse(itm.Key);
                String guardFilter = String.Empty;

                // Do we have a guard for address?
                if (!String.IsNullOrEmpty(pred.Guard))
                {
                    // Translate Guards to UUIDs
                    var guards = pred.Guard.Split('|');
                    for (int i = 0; i < guards.Length; i++)
                    {
                        guards[i] = guardType.GetField(guards[i]).GetValue(null).ToString();
                    }
                    if (guards.Any(o => o == null))
                    {
                        return(false);
                    }

                    // Add to where clause
                    componentTypeGuard.AddRange(guards);
                    guardFilter = $"AND {queryPrefix}{cmpTblType}.typ_cd_id IN ({String.Join(",", guards.Select(o => $"'{o}'"))})";
                }

                // Filter on the component value
                var value = itm.Value;
                if (value is String)
                {
                    value = new List <Object>()
                    {
                        value
                    }
                }
                ;
                var qValues = value as List <Object>;
                vCount++;


                whereClause.Append($"LEFT JOIN (SELECT val_seq_id FROM {valTblType} AS {queryPrefix}{valTblType} WHERE ");
                whereClause.Append(builder.CreateSqlPredicate($"{queryPrefix}{valTblType}", "val", componentType.GetProperty("Value"), qValues));
                whereClause.Append($") AS {queryPrefix}{valTblType}_{localChar} ON ({queryPrefix}{valTblType}_{localChar++}.val_seq_id = {queryPrefix}{cmpTblType}.val_seq_id {guardFilter})");
            }

            whereClause.Append($" WHERE ");
            if (componentTypeGuard.Count > 0)
            {
                whereClause.Append($"{queryPrefix}{cmpTblType}.typ_cd_id IN ({String.Join(",", componentTypeGuard.Select(o => $"'{o}'"))}) AND ");
            }
            whereClause.Append("(");
            // Ensure that the left joined objects exist
            for (char s = 'a'; s < localChar; s++)
            {
                whereClause.Append($" {queryPrefix}{valTblType}_{s}.val_seq_id IS NOT NULL ").Append("OR");
            }
            whereClause.RemoveLast();
            whereClause.Append($") GROUP BY {keyName} HAVING COUNT(DISTINCT {queryPrefix}{cmpTblType}.cmp_id) >= {vCount})");

            return(true);
        }
    }
        /// <summary>
        /// Hack the query
        /// </summary>
        public bool HackQuery(QueryBuilder builder, SqlStatement sqlStatement, SqlStatement whereClause, Type tmodel, PropertyInfo property, string queryPrefix, QueryPredicate predicate, object values, IEnumerable <TableMapping> scopedTables, params KeyValuePair <String, object>[] queryFilter)
        {
            String cmpTblType = String.Empty, valTblType = String.Empty, keyName = String.Empty;
            Type   guardType = null, componentType = null;

            // We can attempt to hack the address
            if (typeof(EntityAddress).IsAssignableFrom(tmodel))
            {
                cmpTblType    = "ent_addr_cmp_tbl";
                valTblType    = "ent_addr_cmp_val_tbl";
                guardType     = typeof(AddressComponentKeys);
                componentType = typeof(EntityAddressComponent);
                keyName       = "addr_id";
            }
            else if (typeof(EntityName).IsAssignableFrom(tmodel))
            {
                cmpTblType    = "ent_name_cmp_tbl";
                valTblType    = "phon_val_tbl";
                guardType     = typeof(NameComponentKeys);
                componentType = typeof(EntityNameComponent);
                keyName       = "name_id";
            }
            else
            {
                return(false);
            }

            // Not applicable for us if
            //  - Not a name or address
            //  - Predicate is not component.value
            //  - There is already other where clause stuff
            if (guardType == null ||
                predicate.Path != "component" ||
                predicate.SubPath != "value" ||
                !String.IsNullOrEmpty(whereClause.SQL))
            {
                return(false);
            }

            // Pop the last statement off
            // var fromClause = sqlStatement.RemoveLast();

            var subQueryAlias = $"{queryPrefix}{scopedTables.First().TableName}";

            whereClause.And($" {subQueryAlias}.{keyName} IN (");

            foreach (var itm in queryFilter)
            {
                var    pred        = QueryPredicate.Parse(itm.Key);
                String guardFilter = String.Empty;

                // Do we have a guard for address?
                if (!String.IsNullOrEmpty(pred.Guard))
                {
                    // Translate Guards to UUIDs
                    var guards = pred.Guard.Split('|');
                    for (int i = 0; i < guards.Length; i++)
                    {
                        guards[i] = guardType.GetField(guards[i]).GetValue(null).ToString();
                    }
                    if (guards.Any(o => o == null))
                    {
                        return(false);
                    }

                    // Add to where clause
                    guardFilter = $"AND {queryPrefix}{cmpTblType}.typ_cd_id IN ({String.Join(",", guards.Select(o => $"'{o}'"))}) ";
                }

                // Filter on the component value
                var value = itm.Value;
                if (value is String)
                {
                    value = new List <Object>()
                    {
                        value
                    }
                }
                ;
                var qValues = value as List <Object>;

                // Filter based on type and prefix :)
                whereClause
                .Append($" SELECT {queryPrefix}{cmpTblType}.{keyName} ")
                .Append($" FROM {cmpTblType} AS {queryPrefix}{cmpTblType} ")
                .Append(" WHERE ")
                .Append($" val_seq_id IN (SELECT val_seq_id FROM {valTblType} WHERE ")
                .Append(builder.CreateSqlPredicate($"{valTblType}", "val", componentType.GetProperty("Value"), qValues))
                .Append(") ")
                .Append(guardFilter)
                .Append(" INTERSECT ");
            }
            whereClause.RemoveLast();
            whereClause.Append($") ");
            whereClause.And($"{subQueryAlias}.obslt_vrsn_seq_id IS NULL ");

            return(true);
        }
    }