Ejemplo n.º 1
0
        public void ExtensionMethods_GetHtmlId_ThenTryParseFromHtmlId_Success(string input)
        {
            var id         = HiveId.TryParse(input).Result;
            var htmlId     = id.GetHtmlId() + ".TemplateId";
            var fromHtmlId = HiveIdExtensions.TryParseFromHtmlId(htmlId).Result;

            Assert.AreEqual(id, fromHtmlId, "HtmlId was: " + htmlId);
        }
        public static T GetById <T>(this IQueryable <T> source, string idAsString)
            where T : class, IReferenceByHiveId
        {
            var parsed = HiveId.TryParse(idAsString);

            if (!parsed.Success)
            {
                return(null);
            }
            return(source.FirstOrDefault(x => x.Id == parsed.Result));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Builds up the PersistedItems property
        /// </summary>
        /// <param name="serializedVal"></param>
        public override void SetModelValues(IDictionary <string, object> serializedVal)
        {
            //set the Value to a serialized version of what is saved

            var persistedIds = serializedVal
                               .Where(x => x.Key.StartsWith("val"))
                               //need to ensure they are sorted!
                               .OrderBy(x =>
            {
                var index = x.Key.Substring(3, x.Key.Length - 3);
                int i;
                return(int.TryParse(index, out i) ? i : 0);
            })
                               .Select(x => x.Value.ToString())
                               .WhereNotNull()
                               .ToArray();

            Value = string.Join(",", persistedIds);

            //now we have to build up the PersistedItems property, we need to determine the node's icon, name, id , etc...
            //we do this by getting the corresponding INodeSelectorDataSource for the tree that has been selected in prevalues.

            var dataSource = _backOfficeRequestContext.RegisteredComponents.TreeControllers
                             .GetNodeSelectorDataSource(PreValueModel.SelectedTree);


            var hiveIds = persistedIds
                          .Select(x =>
            {
                //need to do some error checking here to ensure it parses correctly
                var parsedId = HiveId.TryParse(x);
                return(parsedId.Success ? parsedId.Result : HiveId.Empty);
            })
                          .Where(x => x != HiveId.Empty)
                          .ToArray();

            //set the persisted items
            PersistedItems = hiveIds
                             .Select(x =>
            {
                var model = dataSource.GetNodeSelectorItemModel(x, PreValueModel.SelectedTree);
                //if showing thumbs, go get it
                if (PreValueModel.ShowThumbnails)
                {
                    model.ThumbnailUrl = dataSource.GetMediaUrl(x, PreValueModel.SelectedTree, PreValueModel.ThumbnailPropertyName);
                }
                return(model);
            })
                             .Where(x => x != null)
                             .ToList();
        }
Ejemplo n.º 4
0
        public void ParsingDynamicStringWorks()
        {
            var hiveId  = new HiveId(Guid.NewGuid());
            var myBendy = new BendyObject();

            myBendy["Item"]       = new BendyObject();
            myBendy["Item"].Value = new BendyObject(hiveId);

            var asDynamic = (dynamic)myBendy;

            AttemptTuple <HiveId> result = HiveId.TryParse(asDynamic.Item.Value);

            Assert.That(result.Success, Is.True);
            Assert.That(result.Result, Is.EqualTo(hiveId));
        }
Ejemplo n.º 5
0
        public void FromString_ParseAsUriSafe()
        {
            // Assert
            var item = "storage$net_root$stylesheets$_p__provider-key$_v__string$_value";

            // Act
            var itemParsed = HiveId.TryParse(item);

            // Assert
            Assert.IsTrue(itemParsed.Success);
            HiveId hiveId = itemParsed.Result;

            Assert.AreEqual(hiveId.ProviderId, "provider-key");
            Assert.AreEqual(hiveId.Value.Type, HiveIdValueTypes.String);
            Assert.AreEqual((string)hiveId.Value, "value");
            Assert.AreEqual(hiveId.Value, new HiveIdValue("value"));
            Assert.AreEqual(new Uri("storage://stylesheets/"), hiveId.ProviderGroupRoot);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Need to custom create the model since theres no empty constructor for the FileEditorModel
        /// </summary>
        /// <param name="controllerContext"></param>
        /// <param name="bindingContext"></param>
        /// <param name="modelType"></param>
        /// <returns></returns>
        protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
        {
            //try to extract the id from the request as this will give us all of the information about the file
            var idName = string.IsNullOrEmpty(bindingContext.ModelName) ? "id" : bindingContext.ModelName;
            var valueProviderResult = bindingContext.ValueProvider.GetValue(idName);
            var rawId = valueProviderResult.AttemptedValue;

            var name    = bindingContext.ValueProvider.GetValue("name").AttemptedValue;
            var content = bindingContext.ValueProvider.GetValue("fileContent").AttemptedValue;

            FileEditorModel model;

            if (string.IsNullOrEmpty(rawId))
            {
                model             = FileEditorModel.CreateNew();
                model.Name        = name;
                model.FileContent = content;
            }
            else
            {
                var id = HiveId.TryParse(rawId);
                if (id.Success)
                {
                    if (!id.Result.IsNullValueOrEmpty())
                    {
                        model = new FileEditorModel(id.Result, name, DateTimeOffset.UtcNow, DateTimeOffset.UtcNow,
                                                    () => content);
                    }
                    else
                    {
                        model             = FileEditorModel.CreateNew();
                        model.Name        = name;
                        model.FileContent = content;
                    }
                }
                else
                {
                    throw new ArgumentException("The id parameter in the route values could not parse into a HiveId");
                }
            }

            return(model);
        }
Ejemplo n.º 7
0
        public static IEnumerable <HiveId> SelectedNodeIds(this TypedAttribute attribute)
        {
            Mandate.ParameterNotNull(attribute, "attribute");

            ValidateNodeSelectorPropertyEditor(attribute);

            return(attribute.Values
                   //need to ensure they are sorted!
                   .OrderBy(x =>
            {
                var index = x.Key.Substring(3, x.Key.Length - 3);
                int i;
                return int.TryParse(index, out i) ? i : 0;
            })
                   .Select(x =>
            {
                //ensure the value is parsable, this shouldn't happen but we'll be sure to check.
                var hiveId = HiveId.TryParse(x.Value.ToString());
                return hiveId.Success ? hiveId.Result : HiveId.Empty;
            })
                   .Where(x => !x.IsNullValueOrEmpty())); //if it didn't parse, don't return it
        }
Ejemplo n.º 8
0
        public void FromString_ParseAsAutoValue()
        {
            // Assert
            var intAsString  = "1";
            var guidAsString = "B7C8A690-D721-42E6-B571-79EC46DEDFC8";
            var blahAsString = "ssdfljsdlfjsdfjdkfl";

            // Act
            var parsedAsInt    = HiveId.TryParse(intAsString);
            var parsedAsGuid   = HiveId.TryParse(guidAsString);
            var parsedAsString = HiveId.TryParse(blahAsString);

            // Assert
            Assert.IsTrue(parsedAsInt.Success);
            HiveId hiveIdAsInt = parsedAsInt.Result;

            Assert.IsNull(hiveIdAsInt.ProviderId);
            Assert.AreEqual(hiveIdAsInt.Value.Type, HiveIdValueTypes.Int32);
            Assert.AreEqual((int)hiveIdAsInt.Value, 1);
            Assert.AreEqual(hiveIdAsInt.Value, new HiveIdValue(1));

            Assert.IsTrue(parsedAsGuid.Success);
            HiveId hiveIdAsGuid = parsedAsGuid.Result;

            Assert.IsNull(hiveIdAsGuid.ProviderId);
            Assert.AreEqual(hiveIdAsGuid.Value.Type, HiveIdValueTypes.Guid);
            Assert.AreEqual((Guid)hiveIdAsGuid.Value, Guid.Parse(guidAsString));
            Assert.AreEqual(hiveIdAsGuid.Value, new HiveIdValue(Guid.Parse(guidAsString)));

            Assert.IsTrue(parsedAsString.Success);
            HiveId hiveIdAsString = parsedAsString.Result;

            Assert.IsNull(hiveIdAsString.ProviderId);
            Assert.AreEqual(hiveIdAsString.Value.Type, HiveIdValueTypes.String);
            Assert.AreEqual((string)hiveIdAsString.Value, blahAsString);
            Assert.AreEqual(hiveIdAsString.Value, new HiveIdValue(blahAsString));
        }
        public override ICriterion VisitFieldPredicate(FieldPredicateExpression node)
        {
            var fieldName      = node.SelectorExpression.FieldName;
            var valueKey       = node.SelectorExpression.ValueKey;
            var fieldValue     = node.ValueExpression.Value;
            var fieldValueType = fieldValue != null?fieldValue.GetType() : typeof(string);

            switch (fieldName.ToLowerInvariant())
            {
            case "utccreated":
                var dateValue = (DateTimeOffset)fieldValue;
                if (dateValue == default(DateTimeOffset))
                {
                    break;
                }
                _requiresOuterNodeJoin = true;
                switch (node.ValueExpression.ClauseType)
                {
                case ValuePredicateType.LessThanOrEqual:
                    return(Restrictions.Le(Projections.Property(() => outerNode.DateCreated), dateValue));
                }
                break;

            case "id":
                Guid idValue = GetIdValue(node);

                switch (node.ValueExpression.ClauseType)
                {
                case ValuePredicateType.Equal:
                    _discoveredRequiredNodeIds.Add(idValue);
                    return(Restrictions.Eq(Projections.Property(() => version.Node.Id), idValue));

                case ValuePredicateType.NotEqual:
                    _negatingNodeIdsExist = true;
                    return(!Restrictions.Eq(Projections.Property(() => version.Node.Id), idValue));

                default:
                    throw new InvalidOperationException(
                              "Cannot query an item by id by any other operator than == or !=");
                }

            case "system-internal-selected-template":
                //TODO Pending property editors getting involved in query modification prior to being passed to hive provider,
                //manually check for queries against a template here
                if (valueKey == "TemplateId" && fieldValue != null)
                {
                    var tryParseResult = HiveId.TryParse(fieldValue.ToString());
                    if (!tryParseResult.Success || tryParseResult.Result.ProviderGroupRoot == null || tryParseResult.Result.ProviderId == null ||
                        (tryParseResult.Result.ProviderGroupRoot.AbsoluteUri != "storage://" && tryParseResult.Result.ProviderId != "templates"))
                    {
                        var normalisedFieldValue = "/" + fieldValue.ToString().TrimStart("/").TrimEnd(".") + ".";
                        // Need to convert the value into the serialized form that a HiveId would use
                        var newValue = new HiveId("storage", "templates", new HiveIdValue(normalisedFieldValue)).ToString(HiveIdFormatStyle.UriSafe);
                        fieldValue = newValue;
                    }
                    else
                    {
                        fieldValue = tryParseResult.Result.ToString(HiveIdFormatStyle.UriSafe);
                    }
                }
                break;
            }

            // First look up the types of the main field
            AttributeDefinition defAlias  = null;
            AttributeType       typeAlias = null;
            var attributeType             = _activeSession.NhSession.QueryOver <AttributeDefinition>(() => defAlias)
                                            .JoinAlias(() => defAlias.AttributeType, () => typeAlias)
                                            .Where(() => defAlias.Alias == fieldName)
                                            .Select(x => typeAlias.PersistenceTypeProvider)
                                            .List <string>();

            foreach (var type in attributeType)
            {
                var typeName = type;
                if (_typesAlreadyEstablished.Contains(typeName))
                {
                    continue;
                }
                try
                {
                    _typesAlreadyEstablished.Add(typeName);
                    var persisterType = Type.GetType(typeName, false);
                    if (persisterType != null)
                    {
                        var persisterInstance = Activator.CreateInstance(persisterType) as IAttributeSerializationDefinition;
                        if (persisterInstance != null && !_typesToQuery.Contains(persisterInstance.DataSerializationType))
                        {
                            _typesToQuery.Add(persisterInstance.DataSerializationType);
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error <NhCriteriaVisitor>("Error while trying to decide which value-tables to join & query", ex);
                    throw;
                }
            }

            // U5-789
            // Workaround pending a better check of what data is actually saved
            // An issue arose because previous data had been saved in long-string,
            // but the datatype changed to be just string, therefore only string was
            // being queried despite all the data residing still in long-string
            if (_typesToQuery.Contains(DataSerializationTypes.String) && !_typesToQuery.Contains(DataSerializationTypes.LongString))
            {
                _typesToQuery.Add(DataSerializationTypes.LongString);
            }

            //NodeVersion aliasNodeVersion = null;
            //Attribute aliasAttribute = null;
            //AttributeDefinition aliasAttributeDefinition = null;
            //AttributeStringValue aliasStringValue = null;
            //AttributeLongStringValue aliasLongStringValue = null;
            //AttributeIntegerValue aliasIntegerValue = null;
            //AttributeDecimalValue aliasDecimalValue = null;
            //NodeRelation aliasNodeRelation = null;
            //AttributeDateValue aliasDateValue = null;

            //QueryOver<NodeVersion, AttributeDefinition> queryExtender = QueryOver.Of<NodeVersion>(() => aliasNodeVersion)
            //    .JoinQueryOver<Attribute>(() => aliasNodeVersion.Attributes, () => aliasAttribute)
            //    .JoinQueryOver<AttributeDefinition>(() => aliasAttribute.AttributeDefinition, () => aliasAttributeDefinition);

            int numberOfMatchesEvaluated         = 0;
            AbstractCriterion restrictionBuilder = null;

            foreach (var dataSerializationTypese in _typesToQuery.Distinct())
            {
                AbstractCriterion restriction = null;
                global::System.Linq.Expressions.Expression <Func <object> > propertyExpression = null;
                global::System.Linq.Expressions.Expression <Func <object> > subkeyExpression   = null;
                List <ValuePredicateType> validClauseTypes = null;
                var useLikeMatchForStrings = false;
                switch (dataSerializationTypese)
                {
                case DataSerializationTypes.SmallInt:
                case DataSerializationTypes.LargeInt:
                case DataSerializationTypes.Boolean:
                    propertyExpression = () => integerVal.Value;
                    subkeyExpression   = () => integerVal.ValueKey;
                    validClauseTypes   = new List <ValuePredicateType>()
                    {
                        ValuePredicateType.Equal,
                        ValuePredicateType.GreaterThan,
                        ValuePredicateType.GreaterThanOrEqual,
                        ValuePredicateType.LessThan,
                        ValuePredicateType.LessThanOrEqual,
                        ValuePredicateType.NotEqual
                    };
                    break;

                case DataSerializationTypes.Decimal:
                    propertyExpression = () => decimalVal.Value;
                    subkeyExpression   = () => decimalVal.ValueKey;
                    validClauseTypes   = new List <ValuePredicateType>()
                    {
                        ValuePredicateType.Equal,
                        ValuePredicateType.GreaterThan,
                        ValuePredicateType.GreaterThanOrEqual,
                        ValuePredicateType.LessThan,
                        ValuePredicateType.LessThanOrEqual,
                        ValuePredicateType.NotEqual
                    };
                    break;

                case DataSerializationTypes.String:
                    propertyExpression = () => stringVal.Value;
                    subkeyExpression   = () => stringVal.ValueKey;
                    validClauseTypes   = new List <ValuePredicateType>()
                    {
                        ValuePredicateType.Equal,
                        ValuePredicateType.NotEqual,
                        ValuePredicateType.Contains,
                        ValuePredicateType.StartsWith,
                        ValuePredicateType.EndsWith,
                        ValuePredicateType.MatchesWildcard
                    };
                    break;

                case DataSerializationTypes.LongString:
                    propertyExpression     = () => longStrVal.Value;
                    subkeyExpression       = () => longStrVal.ValueKey;
                    useLikeMatchForStrings = true;
                    validClauseTypes       = new List <ValuePredicateType>()
                    {
                        ValuePredicateType.Equal,
                        ValuePredicateType.NotEqual,
                        ValuePredicateType.Contains,
                        ValuePredicateType.StartsWith,
                        ValuePredicateType.EndsWith,
                        ValuePredicateType.MatchesWildcard
                    };
                    break;

                case DataSerializationTypes.Date:
                    propertyExpression = () => dateVal.Value;
                    subkeyExpression   = () => dateVal.ValueKey;
                    validClauseTypes   = new List <ValuePredicateType>()
                    {
                        ValuePredicateType.Equal,
                        ValuePredicateType.GreaterThan,
                        ValuePredicateType.GreaterThanOrEqual,
                        ValuePredicateType.LessThan,
                        ValuePredicateType.LessThanOrEqual,
                        ValuePredicateType.NotEqual,
                        ValuePredicateType.Empty
                    };
                    break;
                }

                if (!validClauseTypes.Contains(node.ValueExpression.ClauseType))
                {
                    throw new InvalidOperationException("A field of type {0} cannot be queried with operator {1}".InvariantFormat(dataSerializationTypese.ToString(), node.ValueExpression.ClauseType.ToString()));
                }

                switch (node.ValueExpression.ClauseType)
                {
                case ValuePredicateType.Equal:
                    restriction = GetRestrictionEq(fieldValue, useLikeMatchForStrings, propertyExpression, subkeyExpression, valueKey);
                    break;

                case ValuePredicateType.NotEqual:
                    restriction = !GetRestrictionEq(fieldValue, useLikeMatchForStrings, propertyExpression);
                    break;

                case ValuePredicateType.LessThan:
                    restriction = GetRestrictionLt(fieldValue, propertyExpression);
                    break;

                case ValuePredicateType.LessThanOrEqual:
                    restriction = GetRestrictionLtEq(fieldValue, propertyExpression);
                    break;

                case ValuePredicateType.GreaterThan:
                    restriction = GetRestrictionGt(fieldValue, propertyExpression);
                    break;

                case ValuePredicateType.GreaterThanOrEqual:
                    restriction = GetRestrictionGtEq(fieldValue, propertyExpression);
                    break;

                case ValuePredicateType.Contains:
                    restriction = GetRestrictionContains(fieldValue, propertyExpression);
                    break;

                case ValuePredicateType.StartsWith:
                    restriction = GetRestrictionStarts(fieldValue, propertyExpression);
                    break;

                case ValuePredicateType.EndsWith:
                    restriction = GetRestrictionEnds(fieldValue, propertyExpression);
                    break;
                }

                if (restriction != null)
                {
                    if (numberOfMatchesEvaluated == 0)
                    {
                        restrictionBuilder = restriction;
                        numberOfMatchesEvaluated++;
                    }
                    else
                    {
                        restrictionBuilder = Restrictions.Or(restriction, restrictionBuilder);
                    }
                }
            }

            var fieldNameRestriction = Restrictions.Eq(Projections.Property(() => def.Alias), fieldName);

            if (restrictionBuilder != null)
            {
                restrictionBuilder = Restrictions.And(restrictionBuilder, fieldNameRestriction);
            }
            else
            {
                restrictionBuilder = fieldNameRestriction;
            }

            return(restrictionBuilder);
        }
Ejemplo n.º 10
0
        public override FieldFilterResult VisitFieldPredicate(FieldPredicateExpression node)
        {
            var fieldName      = node.SelectorExpression.FieldName;
            var valueKey       = node.SelectorExpression.ValueKey;
            var fieldValue     = node.ValueExpression.Value;
            var fieldValueType = fieldValue != null?fieldValue.GetType() : typeof(string);

            var toReturn = new FieldFilterResult();

            RdbmsModel.Attribute att            = null;
            Node outerNode                      = null;
            AttributeStringValue     stringVal  = null;
            AttributeLongStringValue longStrVal = null;
            AttributeIntegerValue    integerVal = null;
            AttributeDecimalValue    decimalVal = null;
            AttributeDateValue       dateVal    = null;
            AttributeDefinition      def        = null;

            // First check for special cases, typically stuff that can be queried
            // that isn't necessarily a value in any of the Attribute*Value tables
            switch (fieldName.ToLowerInvariant())
            {
            case "utccreated":
                DateTimeOffset createdDtoValue = ParseDateTimeOffset(fieldValue);
                if (createdDtoValue == default(DateTime))
                {
                    break;
                }

                toReturn.NhCriterion = CreateRestriction(node.ValueExpression.ClauseType,
                                                         () => outerNode.DateCreated, createdDtoValue);

                if (toReturn.NhCriterion != null)
                {
                    toReturn.Joins.Add(new Join(() => agg.Node, () => outerNode, JoinType.InnerJoin));
                }

                break;

            case "utcmodified":
                DateTimeOffset modifiedDtoValue = ParseDateTimeOffset(fieldValue);
                if (modifiedDtoValue == default(DateTime))
                {
                    break;
                }

                toReturn.NhCriterion = CreateRestriction(node.ValueExpression.ClauseType,
                                                         () => agg.StatusDate, modifiedDtoValue);

                break;

            case "id":
                Guid idValue = GetIdValue(node);

                switch (node.ValueExpression.ClauseType)
                {
                case ValuePredicateType.Equal:
                    toReturn.NhCriterion = Restrictions.Eq(Projections.Property(() => agg.Node.Id), idValue);
                    break;

                case ValuePredicateType.NotEqual:
                    toReturn.NhCriterion = !Restrictions.Eq(Projections.Property(() => agg.Node.Id), idValue);
                    break;

                default:
                    throw new InvalidOperationException("Cannot query an item by id by any other operator than == or !=");
                }
                break;

            case "system-internal-selected-template":
                //TODO Pending property editors getting involved in query modification prior to being passed to hive provider,
                //manually check for queries against a template here
                if (valueKey == "TemplateId" && fieldValue != null)
                {
                    var tryParseResult = HiveId.TryParse(fieldValue.ToString());
                    if (!tryParseResult.Success || tryParseResult.Result.ProviderGroupRoot == null || tryParseResult.Result.ProviderId == null ||
                        (tryParseResult.Result.ProviderGroupRoot.AbsoluteUri != "storage://" && tryParseResult.Result.ProviderId != "templates"))
                    {
                        var normalisedFieldValue = "/" + fieldValue.ToString().TrimStart("/").TrimEnd(".") + ".";
                        // Need to convert the value into the serialized form that a HiveId would use
                        var newValue = new HiveId("storage", "templates", new HiveIdValue(normalisedFieldValue)).ToString(HiveIdFormatStyle.UriSafe);
                        fieldValue = newValue;
                    }
                    else
                    {
                        fieldValue = tryParseResult.Result.ToString(HiveIdFormatStyle.UriSafe);
                    }
                }
                break;
            }

            if (toReturn.NhCriterion != null)
            {
                // The special-case handling above has already set the criterion,
                // so we don't have to evaluate field values in this pass and can return
                return(toReturn);
            }

            // Establish which Attribute*Value tables to query
            // First look up the types of the main field
            AttributeDefinition defAlias  = null;
            AttributeType       typeAlias = null;
            var attributeType             = _activeSession.NhSession.QueryOver <AttributeDefinition>(() => defAlias)
                                            .JoinAlias(() => defAlias.AttributeType, () => typeAlias)
                                            .Where(() => defAlias.Alias == fieldName)
                                            .Select(Projections.Distinct(Projections.Property(() => typeAlias.PersistenceTypeProvider)))
                                            .Cacheable()
                                            .List <string>();

            foreach (var type in attributeType)
            {
                var typeName = type;

                // Ensure we don't do unneccessary calls to Activator.CreateInstance,
                // (_typesAlreadyEstablished lives for the lifetime of the visitor)
                // but still make sure we populate the toReturn.ValueTypesToQuery for this
                // visit to a field predicate
                if (TypesAlreadyDiscovered.ContainsKey(typeName))
                {
                    var dst = TypesAlreadyDiscovered[typeName];
                    if (toReturn.ValueTypesToQuery.Contains(dst))
                    {
                        continue;
                    }
                    toReturn.ValueTypesToQuery.Add(dst);
                }
                try
                {
                    var persisterType = Type.GetType(typeName, false);
                    if (persisterType != null)
                    {
                        var persisterInstance = Activator.CreateInstance(persisterType) as IAttributeSerializationDefinition;
                        if (persisterInstance != null && !toReturn.ValueTypesToQuery.Contains(persisterInstance.DataSerializationType))
                        {
                            toReturn.ValueTypesToQuery.Add(persisterInstance.DataSerializationType);
                            TypesAlreadyDiscovered.TryAdd(typeName, persisterInstance.DataSerializationType);
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error <NhCriteriaVisitor>("Error while trying to decide which value-tables to join & query", ex);
                    throw;
                }
            }

            // U5-789
            // Workaround pending a better check of what data is actually saved
            // An issue arose because previous data had been saved in long-string,
            // but the datatype changed to be just string, therefore only string was
            // being queried despite all the data residing still in long-string
            if (toReturn.ValueTypesToQuery.Contains(DataSerializationTypes.String) && !toReturn.ValueTypesToQuery.Contains(DataSerializationTypes.LongString))
            {
                toReturn.ValueTypesToQuery.Add(DataSerializationTypes.LongString);
            }

            // Now go through the types that we've found, and set up the expressions for the criteria
            int numberOfMatchesEvaluated         = 0;
            AbstractCriterion restrictionBuilder = null;

            foreach (var dataSerializationTypese in toReturn.ValueTypesToQuery.Distinct())
            {
                AbstractCriterion restriction = null;
                global::System.Linq.Expressions.Expression <Func <object> > propertyExpression = null;
                global::System.Linq.Expressions.Expression <Func <object> > subkeyExpression   = null;
                List <ValuePredicateType> validClauseTypes = null;
                var useLikeMatchForStrings = false;
                switch (dataSerializationTypese)
                {
                case DataSerializationTypes.SmallInt:
                case DataSerializationTypes.LargeInt:
                case DataSerializationTypes.Boolean:
                    propertyExpression = () => integerVal.Value;
                    subkeyExpression   = () => integerVal.ValueKey;
                    validClauseTypes   = new List <ValuePredicateType>()
                    {
                        ValuePredicateType.Equal,
                        ValuePredicateType.GreaterThan,
                        ValuePredicateType.GreaterThanOrEqual,
                        ValuePredicateType.LessThan,
                        ValuePredicateType.LessThanOrEqual,
                        ValuePredicateType.NotEqual
                    };
                    break;

                case DataSerializationTypes.Decimal:
                    propertyExpression = () => decimalVal.Value;
                    subkeyExpression   = () => decimalVal.ValueKey;
                    validClauseTypes   = new List <ValuePredicateType>()
                    {
                        ValuePredicateType.Equal,
                        ValuePredicateType.GreaterThan,
                        ValuePredicateType.GreaterThanOrEqual,
                        ValuePredicateType.LessThan,
                        ValuePredicateType.LessThanOrEqual,
                        ValuePredicateType.NotEqual
                    };
                    break;

                case DataSerializationTypes.String:
                    propertyExpression = () => stringVal.Value;
                    subkeyExpression   = () => stringVal.ValueKey;
                    validClauseTypes   = new List <ValuePredicateType>()
                    {
                        ValuePredicateType.Equal,
                        ValuePredicateType.NotEqual,
                        ValuePredicateType.Contains,
                        ValuePredicateType.StartsWith,
                        ValuePredicateType.EndsWith,
                        ValuePredicateType.MatchesWildcard
                    };
                    break;

                case DataSerializationTypes.LongString:
                    propertyExpression     = () => longStrVal.Value;
                    subkeyExpression       = () => longStrVal.ValueKey;
                    useLikeMatchForStrings = true;
                    validClauseTypes       = new List <ValuePredicateType>()
                    {
                        ValuePredicateType.Equal,
                        ValuePredicateType.NotEqual,
                        ValuePredicateType.Contains,
                        ValuePredicateType.StartsWith,
                        ValuePredicateType.EndsWith,
                        ValuePredicateType.MatchesWildcard
                    };
                    break;

                case DataSerializationTypes.Date:
                    propertyExpression = () => dateVal.Value;
                    subkeyExpression   = () => dateVal.ValueKey;
                    validClauseTypes   = new List <ValuePredicateType>()
                    {
                        ValuePredicateType.Equal,
                        ValuePredicateType.GreaterThan,
                        ValuePredicateType.GreaterThanOrEqual,
                        ValuePredicateType.LessThan,
                        ValuePredicateType.LessThanOrEqual,
                        ValuePredicateType.NotEqual,
                        ValuePredicateType.Empty
                    };
                    break;
                }

                if (!validClauseTypes.Contains(node.ValueExpression.ClauseType))
                {
                    throw new InvalidOperationException("A field of type {0} cannot be queried with operator {1}".InvariantFormat(dataSerializationTypese.ToString(), node.ValueExpression.ClauseType.ToString()));
                }

                // Based on the clause type, generate an NH criterion
                switch (node.ValueExpression.ClauseType)
                {
                case ValuePredicateType.Equal:
                    restriction = GetRestrictionEq(fieldValue, useLikeMatchForStrings, propertyExpression, subkeyExpression, valueKey);
                    break;

                case ValuePredicateType.NotEqual:
                    restriction = !GetRestrictionEq(fieldValue, useLikeMatchForStrings, propertyExpression);
                    break;

                case ValuePredicateType.LessThan:
                    restriction = GetRestrictionLt(fieldValue, propertyExpression);
                    break;

                case ValuePredicateType.LessThanOrEqual:
                    restriction = GetRestrictionLtEq(fieldValue, propertyExpression);
                    break;

                case ValuePredicateType.GreaterThan:
                    restriction = GetRestrictionGt(fieldValue, propertyExpression);
                    break;

                case ValuePredicateType.GreaterThanOrEqual:
                    restriction = GetRestrictionGtEq(fieldValue, propertyExpression);
                    break;

                case ValuePredicateType.Contains:
                    restriction = GetRestrictionContains(fieldValue, propertyExpression);
                    break;

                case ValuePredicateType.StartsWith:
                    restriction = GetRestrictionStarts(fieldValue, propertyExpression);
                    break;

                case ValuePredicateType.EndsWith:
                    restriction = GetRestrictionEnds(fieldValue, propertyExpression);
                    break;
                }

                // We might be dealing with multiple restrictions even for one field (e.g. if it's been stored once in String table, and another time in LongString)
                if (restriction != null)
                {
                    if (numberOfMatchesEvaluated == 0)
                    {
                        restrictionBuilder = restriction;
                        numberOfMatchesEvaluated++;
                    }
                    else
                    {
                        // If we're doing a second or later evaluation, turn the restriction into an Or to combine them all
                        restrictionBuilder = Restrictions.Or(restriction, restrictionBuilder);
                    }
                }
            }

            // Add the field name restriction
            var fieldNameRestriction = Restrictions.Eq(Projections.Property(() => def.Alias), fieldName);

            if (restrictionBuilder != null)
            {
                restrictionBuilder = Restrictions.And(restrictionBuilder, fieldNameRestriction);
            }
            else
            {
                restrictionBuilder = fieldNameRestriction;
            }

            // Build the query which will use the restrictions we've just generated
            var query = QueryOver.Of(() => agg);

            // Set up the basic joins (not that we're adding these to a Joins collection on our own type, not just doing
            // them on an NH query, so that we can optimise or merge the joins once the entire expression tree is evaluated
            // for example inside VisitBinary)
            toReturn.Joins.Add(new Join(() => agg.NodeVersion, () => version, JoinType.InnerJoin));
            toReturn.Joins.Add(new Join(() => version.Attributes, () => att, JoinType.InnerJoin));
            toReturn.Joins.Add(new Join(() => att.AttributeDefinition, () => def, JoinType.InnerJoin));

            // Set up the joins for the value tables - only add joins for the tables that we know we want to actually query based on
            // what VisitField might have encountered and added to toReturn.ValueTypesToQuery
            foreach (var dataSerializationTypese in toReturn.ValueTypesToQuery.Distinct())
            {
                Expression <Func <object> > path  = null;
                Expression <Func <object> > alias = null;
                switch (dataSerializationTypese)
                {
                case DataSerializationTypes.SmallInt:
                case DataSerializationTypes.LargeInt:
                case DataSerializationTypes.Boolean:
                    path  = () => att.AttributeIntegerValues;
                    alias = () => integerVal;
                    break;

                case DataSerializationTypes.Decimal:
                    path  = () => att.AttributeDecimalValues;
                    alias = () => decimalVal;
                    break;

                case DataSerializationTypes.String:
                    path  = () => att.AttributeStringValues;
                    alias = () => stringVal;
                    break;

                case DataSerializationTypes.LongString:
                    path  = () => att.AttributeLongStringValues;
                    alias = () => longStrVal;
                    break;

                case DataSerializationTypes.Date:
                    path  = () => att.AttributeDateValues;
                    alias = () => dateVal;
                    break;
                }
                toReturn.Joins.Add(new Join(path, alias));
            }

            toReturn.Subquery = query
                                .Where(restrictionBuilder)
                                .Select(x => x.NodeVersion.Id);

            toReturn.NhCriterion = restrictionBuilder;
            return(toReturn);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Finds a TypedEntity based on the Uri
        /// </summary>
        /// <param name="fullUrlIncludingDomain"></param>
        /// <param name="revisionStatusType"></param>
        /// <returns></returns>
        public EntityRouteResult FindEntityByUrl(Uri fullUrlIncludingDomain, RevisionStatusType revisionStatusType = null)
        {
            Mandate.ParameterNotNull(fullUrlIncludingDomain.Scheme, "Scheme");

            var statusTypeCacheKey = (revisionStatusType != null) ? revisionStatusType.Alias : string.Empty;

            //cache key is full uri except query string and revision status
            var cacheKey = EntityMappedKey + "-" + fullUrlIncludingDomain.GetLeftPart(UriPartial.Path) + "-" + statusTypeCacheKey;

            //TODO: We need to change how the NiceUrls are cached because if we store them in one entry as a dictionary in cache, then
            // we can do a reverse lookup to see if we've already generated the URL for the entity which may match the fullUrlIncludingDomain,
            // if so, then all we have to do is return the entity with the cached ID.

            return(ApplicationContext.FrameworkContext.ApplicationCache
                   .GetOrCreate(cacheKey, () =>
            {
                using (DisposableTimer.Start(timer =>
                                             LogHelper.TraceIfEnabled <DefaultRoutingEngine>("FindEntityByUrl (not from cache) for URL {0} took {1}ms", () => fullUrlIncludingDomain, () => timer)))
                {
                    ReadonlyGroupUnitFactory <IContentStore> persistenceManager;

                    using (DisposableTimer.TraceDuration <DefaultRoutingEngine>("FindEntityByUrl: Getting a reader", "FindEntityByUrl: Got a reader"))
                        persistenceManager = ApplicationContext.Hive.GetReader <IContentStore>(fullUrlIncludingDomain);

                    if (persistenceManager != null)
                    {
                        IReadonlyGroupUnit <IContentStore> readonlyGroupUnit;
                        using (DisposableTimer.TraceDuration <DefaultRoutingEngine>("FindEntityByUrl: Opening a reader", "FindEntityByUrl: Opened a reader"))
                            readonlyGroupUnit = persistenceManager.CreateReadonly();

                        using (var uow = readonlyGroupUnit)
                        {
                            //first, lets check if it's an ID URL
                            var trimmedAppPath = _httpContext.Request.ApplicationPath.TrimEnd('/');
                            var appPathLength = trimmedAppPath.Length;

                            // gate-check for the incoming url because some code (e.g. the alt-template checker) could be unaware of vdirs etc.
                            var absolutePath = fullUrlIncludingDomain.AbsolutePath;
                            var path = (absolutePath.Length < appPathLength) ? absolutePath : absolutePath.Substring(appPathLength, absolutePath.Length - appPathLength);

                            var urlId = HiveId.TryParse(path.TrimStart('/'));
                            if (urlId.Success && urlId.Result.ProviderGroupRoot != null)
                            {
                                LogHelper.TraceIfEnabled <DefaultRoutingEngine>("In FindEntityByUrl: Resolving entity by Id URL (Id: {0} ", () => urlId.Result.ToFriendlyString());
                                try
                                {
                                    //var entityById = uow.Repositories.Revisions.GetLatestRevision<TypedEntity>(urlId.Result, revisionStatusType);
                                    var entityById = uow.Repositories.OfRevisionType(revisionStatusType).InIds(urlId.Result.AsEnumerableOfOne()).FirstOrDefault();
                                    if (entityById == null)
                                    {
                                        LogHelper.Warn <DefaultRoutingEngine>("In FindEntityByUrl: Resolving entity by Id URL failed (Id: {0} ", urlId.Result.ToFriendlyString());
                                        return null;
                                    }
                                    return new HttpRuntimeCacheParameters <EntityRouteResult>(new EntityRouteResult(entityById, EntityRouteStatus.SuccessById));
                                }
                                catch (ArgumentException)
                                {
                                    //this occurs if the Id parsed but 'not really'
                                    return null;
                                }
                            }

                            TypedEntity lastItemFound;
                            //is the current requesting hostname/port in our list ?
                            if (DomainList.ContainsHostname(fullUrlIncludingDomain.Authority))
                            {
                                //domain found so get the first item assigned to this domain
                                LogHelper.TraceIfEnabled <DefaultRoutingEngine>("In FindEntityByUrl: Resolving entity by Domain URL {0}", () => fullUrlIncludingDomain.Authority);
                                var hostnameEntry = DomainList[fullUrlIncludingDomain.Authority];
                                //lastRevisionFound = uow.Repositories.Revisions.GetLatestRevision<TypedEntity>(hostnameEntry.ContentId, revisionStatusType);
                                lastItemFound = uow.Repositories.OfRevisionType(revisionStatusType).InIds(hostnameEntry.ContentId.AsEnumerableOfOne()).FirstOrDefault();
                                Mandate.That(lastItemFound != null, x => new InvalidOperationException("Could not find an entity with a revision status of '" + revisionStatusType.Alias + "', having a hostname '" + fullUrlIncludingDomain.Authority + "' and id: " + hostnameEntry.ContentId));
                            }
                            else
                            {
                                //no domain found for the current request, so we need to find the first routable node that doesn't require a domain
                                LogHelper.TraceIfEnabled <DefaultRoutingEngine>("In FindEntityByUrl: Resolving entity by Non-Domain URL");
                                //var root = uow.Repositories.Revisions.GetLatestRevision<TypedEntity>(FixedHiveIds.ContentVirtualRoot, revisionStatusType);
                                //Mandate.That(root != null, x => new InvalidOperationException("Could not find the content root"));
                                var domainListIds = DomainList.Select(d => d.ContentId).ToArray();

                                var firstLevelRelations =
                                    uow.Repositories.GetChildRelations(FixedHiveIds.ContentVirtualRoot, FixedRelationTypes.DefaultRelationType).OrderBy(
                                        x => x.Ordinal).ToArray();

                                //try to find a first level node that doesn't exist in our domain list
                                var firstNonHostnameEntity = firstLevelRelations.FirstOrDefault(x => !domainListIds.Contains(x.DestinationId));

                                // Issue #U5-112
                                // If we have found no entities that are NOT assigned to a domain, given that we have already tried to find
                                // content matching the current request's domain, we cannot route any content, therefore return null

                                // Also return null if there is no content
                                if (firstNonHostnameEntity == null || !firstLevelRelations.Any())
                                {
                                    return null;
                                }

                                var idToUse = firstNonHostnameEntity.DestinationId;
                                using (DisposableTimer.TraceDuration <DefaultRoutingEngine>("FindEntityByUrl: Querying for " + idToUse, "FindEntityByUrl: Query"))
                                    lastItemFound = uow.Repositories.OfRevisionType(revisionStatusType).InIds(idToUse.AsEnumerableOfOne()).FirstOrDefault();

                                ////if there is no first level node anywhere, then there is no content. Show a friendly message
                                //if (firstNonHostnameEntity == null && !firstLevelRelations.Any())
                                //    return null;

                                ////if we have a first level node not assigned to a domain, use the first, otherwise if all nodes are assigned to domains, then just use the first
                                //var idToUse = firstNonHostnameEntity == null ? firstLevelRelations.First().DestinationId : firstNonHostnameEntity.DestinationId;
                                //lastItemFound = uow.Repositories.OfRevisionType(revisionStatusType).InIds(idToUse.AsEnumerableOfOne()).FirstOrDefault();
                            }


                            // Now we will have the path from the current application root like:
                            //      /this/is/a/path/to/a/document
                            // Now we need to walk down the tree
                            if (lastItemFound != null && !string.IsNullOrWhiteSpace(path) && path != "/")
                            {
                                using (DisposableTimer.TraceDuration <DefaultRoutingEngine>("FindEntityByUrl: Calling GetEntityByPath for " + lastItemFound.Id + " " + path, "FindEntityByUrl: GetEntityByPath"))
                                    lastItemFound = uow
                                                    .Repositories
                                                    .GetEntityByPath <TypedEntity>(lastItemFound.Id,
                                                                                   path,
                                                                                   revisionStatusType,
                                                                                   true);
                            }

                            if (lastItemFound == null)
                            {
                                return new HttpRuntimeCacheParameters <EntityRouteResult>(
                                    new EntityRouteResult(null, EntityRouteStatus.FailedNotFoundByName));
                            }

                            return new HttpRuntimeCacheParameters <EntityRouteResult>(
                                new EntityRouteResult(lastItemFound, EntityRouteStatus.SuccessWithoutHostname));
                        }
                    }

                    return null;
                }
            }));
        }
        /// <summary>
        /// Finds a TypedEntity based on the Uri
        /// </summary>
        /// <param name="fullUrlIncludingDomain"></param>
        /// <param name="revisionStatusType"></param>
        /// <returns></returns>
        public EntityRouteResult FindEntityByUrl(Uri fullUrlIncludingDomain, RevisionStatusType revisionStatusType)
        {
            Mandate.ParameterNotNull(fullUrlIncludingDomain.Scheme, "Scheme");

            //cache key is full uri except query string and revision status
            var cacheKey = EntityMappedKey + "-" + fullUrlIncludingDomain.GetLeftPart(UriPartial.Path) + "-" + revisionStatusType;

            //TODO: We need to change how the NiceUrls are cached because if we store them in one entry as a dictionary in cache, then
            // we can do a reverse lookup to see if we've already generated the URL for the entity which may match the fullUrlIncludingDomain,
            // if so, then all we have to do is return the entity with the cached ID.

            return(ApplicationContext.FrameworkContext.ApplicationCache
                   .GetOrCreate(cacheKey, () =>
            {
                using (DisposableTimer.Start(timer =>
                                             LogHelper.TraceIfEnabled <DefaultRoutingEngine>("FindEntityByUrl for URL {0} took {1}ms", () => fullUrlIncludingDomain, () => timer)))
                {
                    var persistenceManager = ApplicationContext.Hive.GetReader <IContentStore>(fullUrlIncludingDomain);
                    if (persistenceManager != null)
                    {
                        using (var uow = persistenceManager.CreateReadonly())
                        {
                            //first, lets check if it's an ID URL
                            var path = fullUrlIncludingDomain.AbsolutePath.Substring(
                                _httpContext.Request.ApplicationPath.TrimEnd('/').Length,
                                fullUrlIncludingDomain.AbsolutePath.Length - _httpContext.Request.ApplicationPath.TrimEnd('/').Length);
                            var urlId = HiveId.TryParse(path.TrimStart('/'));
                            if (urlId.Success && urlId.Result.ProviderGroupRoot != null)
                            {
                                LogHelper.TraceIfEnabled <DefaultRoutingEngine>("Resolving entity by Id URL (Id: {0} ", () => urlId.Result.ToFriendlyString());
                                try
                                {
                                    var entityById = uow.Repositories.Revisions.GetLatestRevision <TypedEntity>(urlId.Result, revisionStatusType);
                                    if (entityById == null)
                                    {
                                        LogHelper.Warn <DefaultRoutingEngine>("Resolving entity by Id URL failed (Id: {0} ", urlId.Result.ToFriendlyString());
                                        return null;
                                    }
                                    return new HttpRuntimeCacheParameters <EntityRouteResult>(
                                        new EntityRouteResult(entityById.Item, EntityRouteStatus.SuccessById));
                                }
                                catch (ArgumentException)
                                {
                                    //this occurs if the Id parsed but 'not really'
                                    return null;
                                }
                            }

                            Revision <TypedEntity> lastRevisionFound;
                            TypedEntity lastItemFound;
                            //is the current requesting hostname/port in our list ?
                            if (DomainList.ContainsHostname(fullUrlIncludingDomain.Authority))
                            {
                                //domain found so get the first item assigned to this domain
                                LogHelper.TraceIfEnabled <DefaultRoutingEngine>("Resolving entity by Domain URL");
                                var hostnameEntry = DomainList[fullUrlIncludingDomain.Authority];
                                lastRevisionFound = uow.Repositories.Revisions.GetLatestRevision <TypedEntity>(hostnameEntry.ContentId, revisionStatusType);
                                Mandate.That(lastRevisionFound != null, x => new InvalidOperationException("Could not find an entity with a revision status of '" + revisionStatusType.Alias + "', having a hostname '" + fullUrlIncludingDomain.Authority + "' and id: " + hostnameEntry.ContentId));
                                lastItemFound = lastRevisionFound.Item;
                            }
                            else
                            {
                                //no domain found for the current request, so we need to find the first routable node that doesn't require a domain
                                LogHelper.TraceIfEnabled <DefaultRoutingEngine>("Resolving entity by Non-Domain URL");
                                //var root = uow.Repositories.Revisions.GetLatestRevision<TypedEntity>(FixedHiveIds.ContentVirtualRoot, revisionStatusType);
                                //Mandate.That(root != null, x => new InvalidOperationException("Could not find the content root"));
                                var domainListIds = DomainList.Select(d => d.ContentId);

                                var firstLevelRelations =
                                    uow.Repositories.GetChildRelations(FixedHiveIds.ContentVirtualRoot, FixedRelationTypes.DefaultRelationType).OrderBy(
                                        x => x.Ordinal).ToArray();

                                //try to find a first level node that doesn't exist in our domain list
                                var firstNonHostnameEntity = firstLevelRelations.FirstOrDefault(x => !domainListIds.Contains(x.DestinationId));

                                //if there is no first level node anywhere, then there is no content. Show a friendly message
                                if (firstNonHostnameEntity == null && firstLevelRelations.Count() == 0)
                                {
                                    return null;
                                }

                                //if we have a first level node not assigned to a domain, use the first, otherwise if all nodes are assigned to domains, then just use the first
                                lastRevisionFound = uow.Repositories.Revisions.GetLatestRevision <TypedEntity>(
                                    firstNonHostnameEntity == null
                                                ? firstLevelRelations.First().DestinationId
                                                : firstNonHostnameEntity.DestinationId, revisionStatusType);

                                lastItemFound = lastRevisionFound != null ? lastRevisionFound.Item : null;
                            }


                            // Now we will have the path from the current application root like:
                            //      /this/is/a/path/to/a/document
                            // Now we need to walk down the tree
                            if (lastItemFound != null && !string.IsNullOrWhiteSpace(path) && path != "/")
                            {
                                lastItemFound = uow.Repositories.GetEntityByPath <TypedEntity>(lastItemFound.Id, path, revisionStatusType, true);
                            }

                            if (lastItemFound == null)
                            {
                                return new HttpRuntimeCacheParameters <EntityRouteResult>(
                                    new EntityRouteResult(null, EntityRouteStatus.FailedNotFoundByName));
                            }

                            return new HttpRuntimeCacheParameters <EntityRouteResult>(
                                new EntityRouteResult(lastItemFound, EntityRouteStatus.SuccessWithoutHostname));
                        }
                    }

                    return null;
                }
            }));
        }