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)); }
/// <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(); }
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)); }
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); }
/// <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); }
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 }
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); }
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); }
/// <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; } })); }