- @foreach (var post in new UmbracoNS.Examine.Linq.Sandbox.Repositories.BlogRepository().GetAllBlogPosts())
+ @*foreach (var post in new UmbracoNS.Examine.Linq.Sandbox.Repositories.BlogRepository().GetAllBlogPosts())*@
+ @foreach (var post in results)
{
diff --git a/Umbraco.Examine.Linq.Sandbox/media/created-packages/LinqToExamine_1.2.zip b/Umbraco.Examine.Linq.Sandbox/media/created-packages/LinqToExamine_1.2.zip
new file mode 100644
index 0000000..7de21fd
Binary files /dev/null and b/Umbraco.Examine.Linq.Sandbox/media/created-packages/LinqToExamine_1.2.zip differ
diff --git a/Umbraco.Examine.Linq/ExpressionTreeVisitor.cs b/Umbraco.Examine.Linq/ExpressionTreeVisitor.cs
index 8e455fb..3cb8b53 100644
--- a/Umbraco.Examine.Linq/ExpressionTreeVisitor.cs
+++ b/Umbraco.Examine.Linq/ExpressionTreeVisitor.cs
@@ -50,6 +50,7 @@ protected override System.Linq.Expressions.Expression VisitBinaryExpression(Syst
currentPart.Append("eq");
break;
case ExpressionType.NotEqual:
+ currentPart.Append("ne");
inverseMode = true;
break;
@@ -156,8 +157,16 @@ protected override Expression VisitConstantExpression(ConstantExpression express
if(expression.Value is string)
{
value = expression.Value.ToString();
- if (value.Contains(' '))
- value = string.Format("\"{0}\"", value);
+ operation = currentPart.ToString().Substring(currentPart.Length - 2);
+ if (operation == "eq" || operation == "ne")
+ {
+ if (value.Contains(' '))
+ value = string.Format("\"{0}\"", value);
+ }
+ else
+ {
+ operation = "";
+ }
}
else if (expression.Value is string[])
value = string.Join(" ", (string[])expression.Value);
@@ -165,56 +174,80 @@ protected override Expression VisitConstantExpression(ConstantExpression express
value = string.Join(" ", (IEnumerable
)expression.Value);
else if (expression.Value is DateTime)
{
- var formattedDateTime = ((DateTime)expression.Value).ToString("yyyyMMddHHmmssfff", CultureInfo.InvariantCulture);//((DateTime)expression.Value).ToString("o");
+ string fieldName = currentPart.ToString().Substring(0, currentPart.Length - 3); //-3 to remove colon
+
+ string minRange = shouldFormatLegacyDate(fieldName) || true ? "00000000000000000" : formatDateTime(fieldName, DateTime.MinValue);
+ string maxRange = shouldFormatLegacyDate(fieldName) || true ? "99999999999999999" : formatDateTime(fieldName, DateTime.MaxValue);
+
operation = currentPart.ToString().Substring(currentPart.Length - 2);
+
if (operation == "eq")
{
- value = formattedDateTime;
+ var formattedDateTime = formatDateTime(fieldName, (DateTime)expression.Value);
+ value = $"\"{formattedDateTime}\"";
}
else if (operation == "ne")
{
- string fieldName = currentPart.ToString().Substring(0, currentPart.Length - 2);
+ var formattedDateTime = formatDateTime("createDate", (DateTime)expression.Value, true);
//we will do a < and then >
operation = "gt";
- handleRangeOperation(formattedDateTime, "\\-99999999999999999", "99999999999999999", operation, ref value);
+ handleRangeOperation(formattedDateTime, minRange, maxRange, operation, ref value);
//we want to now create the greater than expression
value += " OR " + fieldName;
operation = "lt";
- handleRangeOperation(formattedDateTime, "\\-99999999999999999", "99999999999999999", operation, ref value);
+ formattedDateTime = formatDateTime(fieldName, (DateTime)expression.Value);
+ handleRangeOperation(formattedDateTime, minRange, maxRange, operation, ref value);
}
else
{
- handleRangeOperation(formattedDateTime, "\\-99999999999999999", "99999999999999999", operation, ref value);
+ var formattedDateTime = formatDateTime(fieldName, (DateTime)expression.Value);
+ if (operation == "gt")
+ {
+ formattedDateTime = formatDateTime(fieldName, (DateTime)expression.Value, true);
+ handleRangeOperation(formattedDateTime, minRange, maxRange, operation, ref value);
+ }
+ else
+ handleRangeOperation(formattedDateTime, minRange, maxRange, operation, ref value);
}
}
else if(expression.Value is int || expression.Value is double)
{
- var formattedInt = expression.Value is double ? (Convert.ToInt64((double)expression.Value)).ToString() : ((int)expression.Value).ToString();
operation = currentPart.ToString().Substring(currentPart.Length - 2);
if(operation == "eq")
{
+ var formattedInt = expression.Value is double ? (Convert.ToInt64((double)expression.Value)).ToString() : ((int)expression.Value).ToString();
value = formattedInt;
}
else if (operation == "ne")
{
+ var formattedGt = expression.Value is double ? (Convert.ToInt64((double)expression.Value - 1)).ToString() : ((int)expression.Value - 1).ToString();
+ var formattedLt = expression.Value is double ? (Convert.ToInt64((double)expression.Value + 1)).ToString() : ((int)expression.Value + 1).ToString();
string fieldName = currentPart.ToString().Substring(0, currentPart.Length - 2);
//we will do a < and then >
operation = "gt";
- handleRangeOperation(formattedInt, "\\-99999999999999999", "99999999999999999", operation, ref value);
+ handleRangeOperation(formattedGt, "\\-99999999999999999", "99999999999999999", operation, ref value);
//we want to now create the greater than expression
value += " OR " + fieldName;
operation = "lt";
- handleRangeOperation(formattedInt, "\\-99999999999999999", "99999999999999999", operation, ref value);
+ handleRangeOperation(formattedLt, "\\-99999999999999999", "99999999999999999", operation, ref value);
}
else
{
+ string formattedInt = "";
+ if(operation == "gt")
+ formattedInt = expression.Value is double ? (Convert.ToInt64((double)expression.Value - 1)).ToString() : ((int)expression.Value - 1).ToString();
+ else if(operation == "lt")
+ formattedInt = expression.Value is double ? (Convert.ToInt64((double)expression.Value + 1)).ToString() : ((int)expression.Value + 1).ToString();
handleRangeOperation(formattedInt, "\\-99999999999999999", "99999999999999999", operation, ref value);
}
}
else if (expression.Value is bool || expression.Value is Boolean)
- value = ((bool)expression.Value) ? "1" : "0";
+ {
+ operation = currentPart.ToString().Substring(currentPart.Length - 2);
+ value = ((bool)expression.Value) && !inverseMode ? "1" : "0";
+ }
else
value = expression.Value.ToString();
@@ -235,7 +268,7 @@ protected override Expression VisitMethodCallExpression(MethodCallExpression exp
{
case "Contains":
bracketsEnabled = false;
- currentPart.Append(inverseMode ? "-" : "+");
+ currentPart.Append(inverseMode ? "-" : "");
VisitExpression(expression.Object);
if(expression.Arguments.Count == 3)
{
@@ -297,29 +330,48 @@ protected override Expression VisitMethodCallExpression(MethodCallExpression exp
}
bracketsEnabled = true;
break;
+ case "IsWithinRange":
+ //in this instance, the first argument is an expression to the value,
+ //so we will disable brackets and visit the expression
+ bracketsEnabled = false;
+ DateTime fromDate = (DateTime)((ConstantExpression)expression.Arguments[1]).Value;
+ DateTime toDate = (DateTime)((ConstantExpression)expression.Arguments[2]).Value;
+ VisitExpression(expression.Arguments[0]);
+ var fieldName = currentPart.ToString().Split(':')[0];
+ //below we offset the date by a minute to be inclusive of the dates being filtered. Lucene doesn't include the min and max in the results
+ currentPart.AppendFormat("[{0} TO {1}]", formatDateTime("", fromDate.AddMinutes(-1), true), formatDateTime(fieldName, toDate.AddMinutes(1)));
+ bracketsEnabled = true;
+ break;
+ case "StartsWith":
+ bracketsEnabled = false;
+ VisitExpression(expression.Object);
+ currentPart.Append("^");
+ VisitExpression(expression.Arguments[0]);
+ bracketsEnabled = true;
+ break;
+ case "Equals":
+ bracketsEnabled = false;
+ VisitExpression(expression.Object);
+ VisitExpression(expression.Arguments[0]);
+ bracketsEnabled = true;
+ break;
case "Boost":
bracketsEnabled = false;
VisitExpression(expression.Arguments[0]);
VisitExpression(expression.Object);
- addEndBracket();
+ //addEndBracket();
currentPart.AppendFormat("^{0}", expression.Arguments[1]);
bracketsEnabled = false;
break;
case "Fuzzy":
bracketsEnabled = false;
fuzzy = (double)((ConstantExpression)expression.Arguments[1]).Value;
- if(expression.Arguments.Any())
+ if (expression.Arguments.Any())
VisitExpression(expression.Arguments[0]);
VisitExpression(expression.Object);
fuzzy = 0;
bracketsEnabled = false;
break;
- case "Equals":
- bracketsEnabled = false;
- VisitExpression(expression.Object);
- VisitExpression(expression.Arguments[0]);
- bracketsEnabled = true;
- break;
}
query.Append(currentPart);
@@ -329,6 +381,35 @@ protected override Expression VisitMethodCallExpression(MethodCallExpression exp
return expression;
}
+ protected string formatDateTime(string fieldName, DateTime date, bool isFrom = false)
+ {
+
+ return shouldFormatLegacyDate(fieldName)
+ ? toDateLegacy(date)
+ : isFrom ? toDateFromFormat(date) : toDateISO8601(date);
+ }
+
+ protected bool shouldFormatLegacyDate(string fieldName)
+ {
+ var legacyDateTimeFields = new[] { "createDate", "updateDate" };
+ return legacyDateTimeFields.Contains(fieldName);
+ }
+
+ protected string toDateISO8601(DateTime date)
+ {
+ return date.ToString("yyyy-MM-ddTHH:mm:ss");
+ }
+
+ protected string toDateLegacy(DateTime date)
+ {
+ return date.ToString("yyyyMMddHHmmssfff", CultureInfo.InvariantCulture);
+ }
+
+ protected string toDateFromFormat(DateTime date)
+ {
+ return date.ToString("yyyy-MM-ddTHHmmssfff");
+ }
+
protected bool handleRangeOperation(string formattedValue, string defaultMinValue, string defaultMaxValue, string operation, ref string value)
{
switch (operation)
@@ -337,14 +418,12 @@ protected bool handleRangeOperation(string formattedValue, string defaultMinValu
value += string.Format("[{0} TO {1}]", defaultMinValue, formattedValue);
break;
case "lt":
- formattedValue = (Int64.Parse(formattedValue) - 1).ToString();//-1 on the formattedValue to do less than
value += string.Format("[{0} TO {1}]", defaultMinValue, formattedValue);
break;
case "ge":
value += string.Format("[{0} TO {1}]", formattedValue, defaultMaxValue);
break;
case "gt":
- formattedValue = (Int64.Parse(formattedValue) + 1).ToString();//-1 on the formattedValue to do less than
value += string.Format("[{0} TO {1}]", formattedValue, defaultMaxValue);
break;
default: //is equals
diff --git a/Umbraco.Examine.Linq/Extensions/ClassTypes.cs b/Umbraco.Examine.Linq/Extensions/ClassTypes.cs
index 38ee79c..f2ec301 100644
--- a/Umbraco.Examine.Linq/Extensions/ClassTypes.cs
+++ b/Umbraco.Examine.Linq/Extensions/ClassTypes.cs
@@ -8,9 +8,9 @@ namespace Umbraco.Examine.Linq.Extensions
{
public static class ClassTypes
{
- //public static DateTime Boost(this DateTime value, int boost)
- //{
- // return value;
- //}
+ public static bool IsWithinRange(this DateTime value, DateTime from, DateTime to)
+ {
+ return value > from && value < to;
+ }
}
}
diff --git a/Umbraco.Examine.Linq/Index.cs b/Umbraco.Examine.Linq/Index.cs
index add8579..8fc638b 100644
--- a/Umbraco.Examine.Linq/Index.cs
+++ b/Umbraco.Examine.Linq/Index.cs
@@ -14,13 +14,13 @@ namespace Umbraco.Examine.Linq
public class Index : QueryableBase
{
public Index(IMapper mapper)
- : base(new DefaultQueryProvider(typeof(Index<>), QueryParser.CreateDefault(), new Executor(new UmbracoSearch("ExternalSearcher"), mapper)))
+ : base(new DefaultQueryProvider(typeof(Index<>), QueryParser.CreateDefault(), new Executor(new LuceneSearch("ExternalSearcher"), mapper)))
{
}
public Index(string indexName = "ExternalSearcher", IMapper mapper = null)
- : base(new DefaultQueryProvider(typeof(Index<>), QueryParser.CreateDefault(), new Executor(new UmbracoSearch(indexName), mapper)))
+ : base(new DefaultQueryProvider(typeof(Index<>), QueryParser.CreateDefault(), new Executor(new LuceneSearch(indexName), mapper)))
{
}
diff --git a/Umbraco.Examine.Linq/SearchProviders/UmbracoSearch.cs b/Umbraco.Examine.Linq/SearchProviders/ExamineSearch.cs
similarity index 90%
rename from Umbraco.Examine.Linq/SearchProviders/UmbracoSearch.cs
rename to Umbraco.Examine.Linq/SearchProviders/ExamineSearch.cs
index fd9580f..1386053 100644
--- a/Umbraco.Examine.Linq/SearchProviders/UmbracoSearch.cs
+++ b/Umbraco.Examine.Linq/SearchProviders/ExamineSearch.cs
@@ -10,18 +10,18 @@
namespace Umbraco.Examine.Linq.SearchProviders
{
- public class UmbracoSearch : ISearcher
+ public class ExamineSearch : ISearcher
{
protected string IndexName { get; set; }
public static Dictionary searchQueryCache { get; set; }
- static UmbracoSearch()
+ static ExamineSearch()
{
searchQueryCache = new Dictionary();
}
- public UmbracoSearch(string indexName)
+ public ExamineSearch(string indexName)
{
IndexName = indexName;
}
diff --git a/Umbraco.Examine.Linq/SearchProviders/LuceneSearch.cs b/Umbraco.Examine.Linq/SearchProviders/LuceneSearch.cs
new file mode 100644
index 0000000..f5b8534
--- /dev/null
+++ b/Umbraco.Examine.Linq/SearchProviders/LuceneSearch.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Examine;
+using Examine.LuceneEngine.Providers;
+using Examine.SearchCriteria;
+
+namespace Umbraco.Examine.Linq.SearchProviders
+{
+ public class LuceneSearch : ISearcher
+ {
+ protected string IndexName { get; set; }
+
+ public static Dictionary searchQueryCache { get; set; }
+
+ static LuceneSearch()
+ {
+ searchQueryCache = new Dictionary();
+ }
+
+ public LuceneSearch(string indexName)
+ {
+ IndexName = indexName;
+ }
+
+ public IEnumerable Search(string query)
+ {
+ LuceneSearcher searcher = ExamineManager.Instance.SearchProviderCollection[IndexName] as LuceneSearcher;
+ return searcher.Search(searcher.CreateSearchCriteria().RawQuery(query)).ToList();
+ }
+ }
+}
diff --git a/Umbraco.Examine.Linq/Umbraco.Examine.Linq.csproj b/Umbraco.Examine.Linq/Umbraco.Examine.Linq.csproj
index e96a0f1..65d0b90 100644
--- a/Umbraco.Examine.Linq/Umbraco.Examine.Linq.csproj
+++ b/Umbraco.Examine.Linq/Umbraco.Examine.Linq.csproj
@@ -200,7 +200,8 @@
-
+
+