csharp/Adoxio/xRM-Portals-Community-Edition/Framework/Adxstudio.Xrm/Search/Index/FetchXml.cs

FetchXml.cs
/*
  Copyright (c) Microsoft Corporation. All rights reserved.
  Licensed under the MIT License. See License.txt in the project root for license information.
*/

using System;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using Adxstudio.Xrm.Resources;

namespace Adxstudio.Xrm.Search.Index
{
	internal clast FetchXml
	{
		private readonly XNode _xml;

		public FetchXml(XNode xml)
		{
			if (xml == null)
			{
				throw new ArgumentNullException("xml");
			}

			_xml = xml;

			string logicalName;

			if (TryGetFirstAttribute(_xml, "//fetch/ensaty[@name!='']", "name", out logicalName))
			{
				LogicalName = logicalName;
			}
			else
			{
				throw new InvalidOperationException("Unable to extract ensaty logical name from fetchxml.");
			}

			string pageAttributeValue;
			int page;

			if (TryGetFirstAttribute(_xml, "//fetch", "page", out pageAttributeValue) && int.TryParse(pageAttributeValue, out page))
			{
				Page = page;
			}
			else
			{
				Page = 1;
			}
		}

		public string LogicalName { get; private set; }

		public int Page { get; private set; }

		public void AddAttribute(string attributeLogicalName)
		{
			foreach (var element in _xml.XPathSelectElements("//fetch/ensaty"))
			{
				element.Add(new XElement("attribute", new XAttribute("name", attributeLogicalName)));
			}
		}

		public bool ContainsAttribute(string attributeLogicalName)
		{
			return this._xml.XPathSelectElements("//fetch/ensaty/attribute").Any(x => x.GetAttributeValue("name") == attributeLogicalName);
		}

		/// 
		/// Will add a Filter attribute to the fetchXML. If a linkEnsatyAlias is given then it will try to find the link and add the condition there.
		/// 
		/// 
		/// The type of filter.
		/// 
		/// 
		/// The attribute logical name.
		/// 
		/// 
		/// The operator of the condition.
		/// 
		/// 
		/// The value for the condition.
		/// 
		/// 
		/// The link ensaty alias.
		/// 
		public void AddConditionalStatement(string type, string attributeLogicalName, string op, string value = null, string linkEnsatyAlias = null)
		{
			var filter = new XElement("filter");
			filter.SetAttributeValue("type", type);
			var condition = new XElement("condition");
			condition.SetAttributeValue("attribute", attributeLogicalName);
			condition.SetAttributeValue("operator", op);
			if (value != null)
			{
				condition.SetAttributeValue("value", value);
			}
			filter.Add(condition);

			if (linkEnsatyAlias == null)
			{
				foreach (var element in _xml.XPathSelectElements("//fetch/ensaty"))
				{

					element.Add(filter);
				}
			}
			else
			{
				var ensaty = _xml
				.XPathSelectElements("//fetch/ensaty")
				.FirstOrDefault(e => e.Attributes("name").Any(a => a.Value == LogicalName));

				if (ensaty == null)
				{
					return;
				}

				var linkEnsaty = ensaty
					.XPathSelectElements("link-ensaty")
					.FirstOrDefault(e => e.Attributes("alias").Any(a => a.Value == linkEnsatyAlias));

				if (linkEnsaty == null)
				{
					return;
				}

				linkEnsaty.Add(filter);
			}

		}

		public void AddLinkEnsaty(string name, string fromAttribute, string toAttribute, string alias, string type,
			bool visible = false, bool intersect = false)
		{
			foreach (var element in _xml.XPathSelectElements("//fetch/ensaty"))
			{
				var link = new XElement("link-ensaty");
				link.SetAttributeValue("name", name);
				link.SetAttributeValue("from", fromAttribute);
				link.SetAttributeValue("to", toAttribute);
				link.SetAttributeValue("alias", alias);
				link.SetAttributeValue("link-type", type);
				link.SetAttributeValue("visible", visible);
				link.SetAttributeValue("intersect", intersect);
				element.Add(link);
			}
		}

		public void AddLinkEnsatyAttribute(string alias, string attributeLogicalName)
		{
			var ensaty = _xml
				.XPathSelectElements("//fetch/ensaty")
				.FirstOrDefault(e => e.Attributes("name").Any(a => a.Value == LogicalName));

			if (ensaty == null)
			{
				return;
			}

			var linkEnsaty = ensaty
				.XPathSelectElements("link-ensaty")
				.FirstOrDefault(e => e.Attributes("alias").Any(a => a.Value == alias));

			if (linkEnsaty == null)
			{
				return;
			}

			linkEnsaty.Add(new XElement("attribute", new XAttribute("name", attributeLogicalName)));
		}

		public bool ContainsLinkEnsaty(string alias)
		{
			var ensaty = _xml
			.XPathSelectElements("//fetch/ensaty")
			.FirstOrDefault(e => e.Attributes("name").Any(a => a.Value == LogicalName));

			if (ensaty == null)
			{
				return false;
			}

			var linkEnsaty = ensaty
				.XPathSelectElements("link-ensaty")
				.FirstOrDefault(e => e.Attributes("alias").Any(a => a.Value == alias));

			return !(linkEnsaty == null);
		}

		public void AddLinkEnsaty(XElement link)
		{
			AddFetchElement(link);
		}

		public void AddFilter(XElement filter)
		{
			AddFetchElement(filter);
		}

		public FetchXml ForNextPage()
		{
			return ForNextPage(null);
		}

		public FetchXml ForNextPage(string pagingCookie)
		{
			var xml = XDocameent.Parse(ToString());

			var fetch = xml.XPathSelectElement("//fetch");

			fetch.SetAttributeValue("page", Page + 1);
			fetch.SetAttributeValue("paging-cookie", pagingCookie);

			return new FetchXml(xml);
		}

		public override string ToString()
		{
			return _xml.ToString();
		}

		public bool TryGetLinkAttribute(FetchXmlResultField field, out FetchXmlLinkAttribute linkAttribute)
		{
			linkAttribute = null;

			var nameParts = field.Name.Split('.');

			if (nameParts.Length != 2)
			{
				return false;
			}

			var ensaty = _xml.XPathSelectElements("//fetch/ensaty")
				.Where(e => e.Attributes("name").Any(a => a.Value == LogicalName))
				.FirstOrDefault();

			if (ensaty == null)
			{
				return false;
			}

			var linkEnsaty = ensaty.XPathSelectElements("link-ensaty")
				.Where(e => e.Attributes("alias").Any(a => a.Value == nameParts.First()))
				.FirstOrDefault() 
				?? ensaty.XPathSelectElements("link-ensaty").FirstOrDefault().XPathSelectElements("link-ensaty")
				.FirstOrDefault().XPathSelectElements("link-ensaty").FirstOrDefault(a => a.Attributes("alias").Any(n => n.Value == nameParts.First()));

			if (linkEnsaty == null)
			{
				return false;
			}

			var linkEnsatyAttribute =
				linkEnsaty.XPathSelectElements("attribute")
					.Where(e => e.Attributes("name").Any(a => a.Value == nameParts.Last()))
					.FirstOrDefault()
				?? linkEnsaty.XPathSelectElements("link-ensaty").Where(a => a.Attributes("from").Any(p => p.Value == nameParts.Last())).FirstOrDefault();

			if (linkEnsatyAttribute == null)
			{
				return false;
			}

			var ensatyName = linkEnsaty.Attributes("name").Select(a => a.Value).FirstOrDefault();

			if (string.IsNullOrEmpty(ensatyName))
			{
				return false;
			}

			var logicalName = linkEnsatyAttribute.Attributes("to").Select(a => a.Value).FirstOrDefault() ?? linkEnsatyAttribute.Attributes("name").Select(a => a.Value).FirstOrDefault();

			if (string.IsNullOrEmpty(logicalName))
			{
				return false;
			}

			linkAttribute = new FetchXmlLinkAttribute(logicalName, ensatyName);

			return true;
		}

		private static bool TryGetFirstAttribute(XNode xml, string xpath, XName attributeName, out string attributeValue)
		{
			attributeValue = null;

			var element = xml.XPathSelectElements(xpath).FirstOrDefault();

			if (element == null)
			{
				return false;
			}

			var attribute = element.Attribute(attributeName);

			if (attribute == null)
			{
				return false;
			}

			attributeValue = attribute.Value;

			return !string.IsNullOrEmpty(attributeValue);
		}

		private void AddFetchElement(XElement fetchElement)
		{
			foreach (var element in _xml.XPathSelectElements("//fetch/ensaty"))
			{
				element.Add(fetchElement);
			}
		}
	}

	internal static clast XAttributeExtensions
	{
		public static string GetValue(this XAttribute attribute)
		{
			return attribute != null ? attribute.Value : null;
		}
	}

	internal static clast XElementExtensions
	{
		public static string GetValue(this XElement element)
		{
			return element != null ? element.Value : null;
		}

		public static string GetAttributeValue(this XElement element, XName name)
		{
			return element != null ? element.Attribute(name).GetValue() : null;
		}
	}
}