Using Hql in dynamic queries

--HG--
branch : 1.x
This commit is contained in:
Sebastien Ros
2011-12-12 17:31:01 -08:00
parent d14fc8d7cf
commit 682f38c1ee
10 changed files with 956 additions and 20 deletions

View File

@@ -1,5 +1,5 @@
ec573e5476f7e8a5a61593d6393e9985e9484fcc src/Orchard.Web/Modules/Orchard.Forms
d3ffae8d849f6b10eb1c4421f7b18e1d05edc85e src/Orchard.Web/Modules/Orchard.Projections
4e99d7e20caab07ddbdcf9c780525613bcf8a15b src/Orchard.Web/Modules/Orchard.Projections
01b83c05050bb731d9f69256bbe8884d458ea1c9 src/Orchard.Web/Modules/Orchard.Rules
65057c6a5cd71f7994ba9bcbeece50dbb737620e src/Orchard.Web/Modules/Orchard.TaskLease
c2e3c396c1fc6c60b131bfc9f83564c6f8d18e58 src/Orchard.Web/Modules/Orchard.Tokens

View File

@@ -93,7 +93,7 @@ namespace Orchard.Tests.ContentManagement {
public void SpecificTypeIsReturnedWhenSpecified() {
AddSampleData();
var alphaBeta = _manager.Query().Where(x => x.WithRecord("ContentType").In("Name", new [] {"alpha", "beta"})).List();
var alphaBeta = _manager.HqlQuery().ForType("alpha", "beta").List();
Assert.That(alphaBeta.Count(), Is.EqualTo(2));
Assert.That(alphaBeta.Count(x => x.Has<AlphaPart>()), Is.EqualTo(1));
@@ -101,7 +101,7 @@ namespace Orchard.Tests.ContentManagement {
Assert.That(alphaBeta.Count(x => x.Has<GammaPart>()), Is.EqualTo(0));
Assert.That(alphaBeta.Count(x => x.Has<DeltaPart>()), Is.EqualTo(0));
var gammaDelta = _manager.Query().Where(x => x.WithRecord("ContentType").In("Name", new[] { "gamma", "delta" })).List();
var gammaDelta = _manager.HqlQuery().ForType("gamma", "delta").List();
Assert.That(gammaDelta.Count(), Is.EqualTo(2));
Assert.That(gammaDelta.Count(x => x.Has<AlphaPart>()), Is.EqualTo(0));
@@ -119,8 +119,11 @@ namespace Orchard.Tests.ContentManagement {
_manager.Create<GammaPart>("gamma", init => { init.Record.Frap = "four"; });
_session.Flush();
var twoOrFour = _manager.Query<GammaPart, GammaRecord>()
.Where(x => x.WithRecord("GammaRecord").Or(a => a.Eq("Frap", "one"), b => b.Eq("Frap", "four")))
var twoOrFour = _manager
.HqlQuery()
.Where(
alias => alias.ContentPartRecord<GammaRecord>(),
x => x.Or(a => a.Eq("Frap", "one"), b => b.Eq("Frap", "four")))
.List();
Assert.That(twoOrFour.Count(), Is.EqualTo(2));
@@ -133,8 +136,8 @@ namespace Orchard.Tests.ContentManagement {
[Test]
public void EmptyWherePredicateRequiresRecord() {
AddSampleData();
var gammas = _manager.Query().Where(x => x.WithRecord("GammaRecord")).List(); // simulates an inner join
var deltas = _manager.Query().Where(x => x.WithRecord("DeltaRecord")).List();
var gammas = _manager.HqlQuery().Join(alias => alias.ContentPartRecord<GammaRecord>()).List();
var deltas = _manager.HqlQuery().Join(alias => alias.ContentPartRecord<DeltaRecord>()).List();
Assert.That(gammas.Count(), Is.EqualTo(1));
Assert.That(deltas.Count(), Is.EqualTo(1));
@@ -152,9 +155,10 @@ namespace Orchard.Tests.ContentManagement {
_session.Flush();
_session.Clear();
var ascending = _manager.Query("gamma")
.OrderBy(x => x.WithRecord("GammaRecord").Asc("Frap"))
.List<GammaPart>().ToList();
var ascending = _manager.HqlQuery<GammaPart>()
.ForType("gamma")
.OrderBy(alias => alias.ContentPartRecord<GammaRecord>(), x => x.Asc("Frap"))
.List().ToList();
Assert.That(ascending.Count(), Is.EqualTo(5));
Assert.That(ascending.First().Record.Frap, Is.EqualTo("four"));
@@ -162,8 +166,9 @@ namespace Orchard.Tests.ContentManagement {
_session.Clear();
var descending = _manager.Query<GammaPart, GammaRecord>()
.OrderBy(x => x.WithRecord("GammaRecord").Desc("Frap"))
var descending = _manager.HqlQuery<GammaPart>()
.ForType("gamma")
.OrderBy(alias => alias.ContentPartRecord<GammaRecord>(), x => x.Desc("Frap"))
.List().ToList();
Assert.That(descending.Count(), Is.EqualTo(5));
@@ -180,12 +185,12 @@ namespace Orchard.Tests.ContentManagement {
_manager.Create<GammaPart>("gamma", init => { init.Record.Frap = "four"; });
_session.Flush();
var reverseById = _manager.Query()
.OrderBy(x => x.WithRecord("GammaRecord").Desc("Id"))
var reverseById = _manager.HqlQuery()
.OrderBy(alias => alias.ContentPartRecord<GammaRecord>(), x => x.Desc("Id"))
.List();
var subset = _manager.Query()
.OrderBy(x => x.WithRecord("GammaRecord").Desc("Id"))
var subset = _manager.HqlQuery()
.OrderBy(alias => alias.ContentPartRecord<GammaRecord>(), x => x.Desc("Id"))
.Slice(2, 3);
Assert.That(subset.Count(), Is.EqualTo(3));
@@ -217,10 +222,11 @@ namespace Orchard.Tests.ContentManagement {
_session.Flush();
_session.Clear();
var results = _manager.Query("gamma")
.Where(x => x.WithVersionRecord("EpsilonRecord").Or(a => a.Eq("Quad", "2"), b => b.Eq("Quad", "3")))
.OrderBy(x => x.WithVersionRecord("EpsilonRecord").Desc("Quad"))
.List<EpsilonPart>();
var results = _manager.HqlQuery<EpsilonPart>()
.Where(alias => alias.ContentPartRecord<EpsilonRecord>(), x => x.Or(a => a.Eq("Quad", "2"), b => b.Eq("Quad", "3")))
.OrderBy(alias => alias.ContentPartRecord<EpsilonRecord>(), x => x.Desc("Quad"))
.ForType("gamma")
.List();
Assert.That(results.Count(), Is.EqualTo(2));
Assert.That(results.First().Record, Has.Property("Quad").EqualTo("3"));

View File

@@ -74,12 +74,18 @@ namespace Orchard.ContentManagement {
where TPart : ContentPart {
return manager.Query().ForPart<TPart>();
}
public static IContentQuery<TPart, TRecord> Query<TPart, TRecord>(this IContentManager manager)
where TPart : ContentPart<TRecord>
where TRecord : ContentPartRecord {
return manager.Query().ForPart<TPart>().Join<TRecord>();
}
public static IHqlQuery<TPart> HqlQuery<TPart>(this IContentManager manager)
where TPart : ContentPart {
return manager.HqlQuery().ForPart<TPart>();
}
/* Query(VersionOptions options) */
public static IContentQuery<ContentItem> Query(this IContentManager manager, VersionOptions options) {

View File

@@ -487,6 +487,10 @@ namespace Orchard.ContentManagement {
return query.ForPart<ContentItem>();
}
public IHqlQuery HqlQuery() {
return new DefaultHqlQuery(this, _sessionLocator.Value.For(typeof(ContentItemVersionRecord)));
}
// Insert or Update imported data into the content manager.
// Call content item handlers.
public void Import(XElement element, ImportContentSession importContentSession) {

View File

@@ -0,0 +1,390 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using NHibernate;
using Orchard.ContentManagement.Records;
using Orchard.Utility.Extensions;
namespace Orchard.ContentManagement {
public class DefaultHqlQuery : IHqlQuery {
private readonly ISession _session;
private VersionOptions _versionOptions;
protected IJoin _from;
protected readonly List<Tuple<IAlias, Join>> _joins = new List<Tuple<IAlias, Join>>();
protected readonly List<Tuple<IAlias, Action<IHqlExpressionFactory>>> _wheres = new List<Tuple<IAlias, Action<IHqlExpressionFactory>>>();
protected readonly List<Tuple<IAlias, Action<IHqlSortFactory>>> _sortings = new List<Tuple<IAlias, Action<IHqlSortFactory>>>();
public IContentManager ContentManager { get; private set; }
public DefaultHqlQuery(IContentManager contentManager, ISession session) {
_session = session;
ContentManager = contentManager;
}
internal string PathToAlias(string path) {
if (String.IsNullOrWhiteSpace(path)) {
throw new ArgumentException("Path can't be empty");
}
return Char.ToLower(path[0], CultureInfo.InvariantCulture) + path.Substring(1);
}
internal Join BindNamedAlias(string alias) {
var tuple = _joins.FirstOrDefault(x => x.Item2.Name == alias);
return tuple == null ? null : tuple.Item2;
}
internal IAlias BindCriteriaByPath(IAlias alias, string path) {
return BindCriteriaByAlias(alias, path, PathToAlias(path));
}
internal IAlias BindCriteriaByAlias(IAlias alias, string path, string aliasName) {
// is this Join already existing (based on aliasName)
Join join = BindNamedAlias(aliasName);
if (join == null) {
join = new Join(path, aliasName);
_joins.Add(new Tuple<IAlias, Join>(alias, join));
}
return join;
}
internal IAlias BindTypeCriteria() {
// ([ContentItemVersionRecord] >join> [ContentItemRecord]) >join> [ContentType]
return BindCriteriaByAlias(BindItemCriteria(), "ContentType", "ct");
}
internal IAlias BindItemCriteria() {
// [ContentItemVersionRecord] >join> [ContentItemRecord]
return BindCriteriaByAlias(BindItemVersionCriteria(), typeof(ContentItemRecord).Name, "ci");
}
internal IAlias BindItemVersionCriteria() {
return _from ?? (_from = new Join(typeof(ContentItemVersionRecord).FullName, "civ", ""));
}
internal IAlias BindPartCriteria<TRecord>() where TRecord : ContentPartRecord {
return BindPartCriteria(typeof(TRecord));
}
internal IAlias BindPartCriteria(Type contentPartRecordType) {
if (!contentPartRecordType.IsSubclassOf(typeof(ContentPartRecord))) {
throw new ArgumentException("The type must inherit from ContentPartRecord", "contentPartRecordType");
}
if (contentPartRecordType.IsSubclassOf(typeof(ContentPartVersionRecord))) {
return BindCriteriaByPath(BindItemVersionCriteria(), contentPartRecordType.Name);
}
return BindCriteriaByPath(BindItemCriteria(), contentPartRecordType.Name);
}
internal void Where(IAlias alias, Action<IHqlExpressionFactory> predicate) {
_wheres.Add(new Tuple<IAlias, Action<IHqlExpressionFactory>>(alias, predicate));
}
internal IAlias ApplyHqlVersionOptionsRestrictions(VersionOptions versionOptions) {
var alias = BindItemVersionCriteria();
if (versionOptions == null) {
Where(alias, x => x.Eq("Published", true));
}
else if (versionOptions.IsPublished) {
Where(alias, x => x.Eq("Published", true));
}
else if (versionOptions.IsLatest) {
Where(alias, x => x.Eq("Latest", true));
}
else if (versionOptions.IsDraft) {
Where(alias, x => x.And(y => y.Eq("Latest", true), y => y.Eq("Published", false)));
}
else if (versionOptions.IsAllVersions) {
// no-op... all versions will be returned by default
}
else {
throw new ApplicationException("Invalid VersionOptions for content query");
}
return alias;
}
public IHqlQuery Join(Action<IAliasFactory> alias) {
var aliasFactory = new DefaultAliasFactory(this);
alias(aliasFactory);
return this;
}
public IHqlQuery Where(Action<IAliasFactory> alias, Action<IHqlExpressionFactory> predicate) {
var aliasFactory = new DefaultAliasFactory(this);
alias(aliasFactory);
Where(aliasFactory.Current, predicate);
return this;
}
public IHqlQuery OrderBy(Action<IAliasFactory> alias, Action<IHqlSortFactory> order) {
var aliasFactory = new DefaultAliasFactory(this);
alias(aliasFactory);
_sortings.Add(new Tuple<IAlias, Action<IHqlSortFactory>>(aliasFactory.Current, order));
return this;
}
public IHqlQuery ForType(params string[] contentTypeNames) {
if (contentTypeNames != null && contentTypeNames.Length != 0) {
Where(BindTypeCriteria(), x => x.InG("Name", contentTypeNames));
}
return this;
}
public IHqlQuery ForVersion(VersionOptions options) {
_versionOptions = options;
return this;
}
public IHqlQuery<T> ForPart<T>() where T : IContent {
return new DefaultHqlQuery<T>(this);
}
public IEnumerable<ContentItem> List() {
return Slice(0, 0);
}
public IEnumerable<ContentItem> Slice(int skip, int count) {
ApplyHqlVersionOptionsRestrictions(_versionOptions);
var hql = ToHql(false);
var query = _session.CreateQuery(hql);
if (skip != 0) {
query.SetFirstResult(skip);
}
if (count != 0) {
query.SetMaxResults(count);
}
return query.List<ContentItemVersionRecord>()
.Select(x => ContentManager.Get(x.Id, VersionOptions.VersionRecord(x.Id)))
.ToReadOnlyCollection();
}
public int Count() {
ApplyHqlVersionOptionsRestrictions(_versionOptions);
return _session.CreateQuery(ToHql(true)).UniqueResult<int>();
}
public string ToHql(bool count) {
var sb = new StringBuilder();
if (count) {
sb.Append("select count(civ) ").AppendLine();
}
else {
sb.Append("select civ ").AppendLine();
}
sb.Append("from ").Append(_from.TableName).Append(" as ").Append(_from.Name).AppendLine();
foreach (var join in _joins) {
sb.Append(join.Item2.Type).Append(" ").Append(join.Item1.Name + "." + join.Item2.TableName).Append(" as ").Append(join.Item2.Name).AppendLine();
}
#region Where
bool first = true;
foreach (var where in _wheres) {
if (!first) {
sb.Append("and ");
}
else {
sb.Append("where ");
first = false;
}
var expressionFactory = new DefaultHqlExpressionFactory();
where.Item2(expressionFactory);
sb.Append(expressionFactory.Criterion.ToHql(where.Item1)).AppendLine();
}
#endregion
#region Order by
bool firstSort = true;
foreach (var sort in _sortings) {
if (!firstSort) {
sb.Append(", ");
}
else {
sb.Append("order by ");
firstSort = false;
}
var sortFactory = new DefaultHqlSortFactory();
sort.Item2(sortFactory);
sb.Append(sort.Item1.Name).Append(".").Append(sortFactory.PropertyName);
if (!sortFactory.Ascending) {
sb.Append(" desc");
}
}
#endregion
return sb.ToString();
}
}
public class DefaultHqlQuery<TPart> : IHqlQuery<TPart> where TPart : IContent {
private readonly DefaultHqlQuery _query;
public DefaultHqlQuery(DefaultHqlQuery query) {
_query = query;
}
public IContentManager ContentManager {
get { return _query.ContentManager; }
}
public IHqlQuery<TPart> ForType(params string[] contentTypes) {
_query.ForType(contentTypes);
return new DefaultHqlQuery<TPart>(_query);
}
public IHqlQuery<TPart> ForVersion(VersionOptions options) {
_query.ForVersion(options);
return new DefaultHqlQuery<TPart>(_query);
}
IEnumerable<TPart> IHqlQuery<TPart>.List() {
return _query.List().AsPart<TPart>();
}
IEnumerable<TPart> IHqlQuery<TPart>.Slice(int skip, int count) {
return _query.Slice(skip, count).AsPart<TPart>();
}
int IHqlQuery<TPart>.Count() {
return _query.Count();
}
public IHqlQuery<TPart> Join(Action<IAliasFactory> alias) {
_query.Join(alias);
return new DefaultHqlQuery<TPart>(_query);
}
public IHqlQuery<TPart> Where(Action<IAliasFactory> alias, Action<IHqlExpressionFactory> predicate) {
_query.Where(alias, predicate);
return new DefaultHqlQuery<TPart>(_query);
}
public IHqlQuery<TPart> OrderBy(Action<IAliasFactory> alias, Action<IHqlSortFactory> order) {
_query.OrderBy(alias, order);
return new DefaultHqlQuery<TPart>(_query);
}
}
public class Alias : IAlias {
public Alias(string name) {
if (String.IsNullOrEmpty(name)) {
throw new ArgumentException("Alias can't be empty");
}
Name = name;
}
public DefaultHqlQuery<IContent> Query { get; set; }
public string Name { get; set; }
}
public interface IJoin : IAlias {
string TableName { get; set; }
string Type { get; set; }
}
public class Sort {
public Sort(IAlias alias, string propertyName, bool ascending) {
Alias = alias;
PropertyName = propertyName;
Ascending = ascending;
}
public IAlias Alias { get; set; }
public string PropertyName { get; set; }
public bool Ascending { get; set; }
}
public class Join : Alias, IJoin {
public Join(string tableName, string alias)
: this(tableName, alias, "join") {}
public Join(string tableName, string alias, string type)
: base(alias) {
if (String.IsNullOrEmpty(tableName)) {
throw new ArgumentException("Table Name can't be empty");
}
TableName = tableName;
Type = type;
}
public string TableName { get; set; }
public string Type { get; set; }
}
public class DefaultHqlSortFactory : IHqlSortFactory
{
public bool Ascending { get; set; }
public string PropertyName { get; set; }
public void Asc(string propertyName) {
PropertyName = propertyName;
Ascending = true;
}
public void Desc(string propertyName) {
PropertyName = propertyName;
Ascending = false;
}
}
public class DefaultAliasFactory : IAliasFactory{
private readonly DefaultHqlQuery _query;
public IAlias Current { get; private set; }
public DefaultAliasFactory(DefaultHqlQuery query) {
_query = query;
Current = _query.BindItemCriteria();
}
public IAliasFactory ContentPartRecord<TRecord>() where TRecord : ContentPartRecord {
Current = _query.BindPartCriteria<TRecord>();
return this;
}
public IAliasFactory ContentPartRecord(Type contentPartRecord) {
if(!contentPartRecord.IsSubclassOf(typeof(ContentPartRecord))) {
throw new ArgumentException("Type must inherit from ContentPartRecord", "contentPartRecord");
}
Current = _query.BindPartCriteria(contentPartRecord);
return this;
}
public IAliasFactory Property(string propertyName, string alias) {
Current = _query.BindCriteriaByAlias(Current, propertyName, alias);
return this;
}
public IAliasFactory Named(string alias) {
Current = _query.BindNamedAlias(alias);
return this;
}
}
}

View File

@@ -29,6 +29,7 @@ namespace Orchard.ContentManagement {
void Flush();
IContentQuery<ContentItem> Query();
IHqlQuery HqlQuery();
ContentItemMetadata GetItemMetadata(IContent contentItem);
IEnumerable<GroupInfo> GetEditorGroupInfos(IContent contentItem);

View File

@@ -0,0 +1,248 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
namespace Orchard.ContentManagement {
public interface IHqlCriterion {
string ToHql(IAlias alias);
}
public abstract class HqlCriterion : IHqlCriterion {
public abstract string ToHql(IAlias alias);
}
public class BinaryExpression : HqlCriterion {
public BinaryExpression(string op, string propertyName, string value, Func<string, string> processPropertyName = null) {
if(value == null) {
throw new ArgumentNullException("value");
}
Op = op;
PropertyName = propertyName;
Value = value;
ProcessPropertyName = processPropertyName;
}
public string Op { get; set; }
public string PropertyName { get; set; }
public string Value { get; set; }
public Func<string, string> ProcessPropertyName { get; set; }
public override string ToHql(IAlias alias) {
var processed = String.Concat(alias.Name, ".", PropertyName);
if(ProcessPropertyName != null) {
processed = ProcessPropertyName(processed);
}
return String.Concat(processed, " ", Op, " ", Value);
}
}
public class CompositeHqlCriterion : HqlCriterion {
public string Op { get; set; }
public IList<IHqlCriterion> Criterions { get; private set; }
public CompositeHqlCriterion(string op) {
Op = op;
Criterions = new List<IHqlCriterion>();
}
public CompositeHqlCriterion Add(IHqlCriterion criterion) {
Criterions.Add(criterion);
return this;
}
public override string ToHql(IAlias alias) {
var sb = new StringBuilder();
var first = true;
foreach(var criterion in Criterions) {
if(!first) {
sb.Append(Op).Append(" ");
}
else {
first = false;
}
sb.Append(criterion.ToHql(alias)).Append(" ");
}
return sb.ToString();
}
}
public static class HqlRestrictions {
public static IEnumerable<string> FormatValue(IEnumerable values, bool quoteStrings = true) {
return from object value in values select FormatValue(value, quoteStrings);
}
public static string FormatValue(object value, bool quoteStrings = true) {
var typeCode = Type.GetTypeCode(value.GetType());
switch (typeCode) {
case TypeCode.String:
if (quoteStrings) {
return String.Concat("'", Convert.ToString(value, CultureInfo.InvariantCulture), "'");
}
return Convert.ToString(value, CultureInfo.InvariantCulture);
}
return Convert.ToString(value, CultureInfo.InvariantCulture);
}
public static IHqlCriterion AllEq(IDictionary propertyNameValues) {
var conjuction = new CompositeHqlCriterion("and");
foreach(string propertyName in propertyNameValues.Keys) {
conjuction.Add(Eq(propertyName, propertyNameValues[propertyName]));
}
return conjuction;
}
public static IHqlCriterion And(IHqlCriterion lhs, IHqlCriterion rhs) {
return new CompositeHqlCriterion("and")
.Add(lhs)
.Add(rhs);
}
public static IHqlCriterion Between(string propertyName, object lo, object hi) {
return null;
}
public static CompositeHqlCriterion Conjunction() {
return new CompositeHqlCriterion("and");
}
public static CompositeHqlCriterion Disjunction() {
return new CompositeHqlCriterion("or");
}
public static IHqlCriterion Eq(string propertyName, object value) {
return new BinaryExpression("=", propertyName, FormatValue(value));
}
public static IHqlCriterion EqProperty(string propertyName, string otherPropertyName) {
return null;
}
public static IHqlCriterion Ge(string propertyName, object value) {
return new BinaryExpression(">=", propertyName, FormatValue(value));
}
public static IHqlCriterion GeProperty(string propertyName, string otherPropertyName) {
return null;
}
public static IHqlCriterion Gt(string propertyName, object value) {
return new BinaryExpression(">", propertyName, FormatValue(value));
}
public static IHqlCriterion GtProperty(string propertyName, string otherPropertyName) {
return null;
}
public static IHqlCriterion IdEq(object value) {
return null;
}
public static IHqlCriterion In(string propertyName, ICollection values) {
if (values.Count == 0) {
throw new ArgumentException("Collection can't be empty", "values");
}
return new BinaryExpression("in", propertyName, "(" + String.Join(", ", FormatValue(values)) + ")");
}
public static IHqlCriterion In(string propertyName, object[] values) {
if (values.Length == 0) {
throw new ArgumentException("Collection can't be empty", "values");
}
return new BinaryExpression("in", propertyName, "(" + String.Join(", ", FormatValue(values)) + ")");
}
public static IHqlCriterion InG<T>(string propertyName, ICollection<T> values) {
if (values.Count == 0) {
throw new ArgumentException("Collection can't be empty", "values");
}
return new BinaryExpression("in", propertyName, "(" + String.Join(", ", FormatValue(values)) + ")");
}
public static IHqlCriterion InsensitiveLike(string propertyName, string value, HqlMatchMode matchMode) {
var expression = Like(propertyName, value, matchMode);
expression.ProcessPropertyName = x => String.Concat("lower(", x, ")");
return expression;
}
public static IHqlCriterion IsEmpty(string propertyName) {
return null;
}
public static IHqlCriterion IsNotEmpty(string propertyName) {
return null;
}
public static IHqlCriterion IsNotNull(string propertyName) {
return null;
}
public static IHqlCriterion IsNull(string propertyName) {
return null;
}
public static IHqlCriterion Le(string propertyName, object value) {
return new BinaryExpression("<=", propertyName, FormatValue(value));
}
public static IHqlCriterion LeProperty(string propertyName, string otherPropertyName) {
return null;
}
public static BinaryExpression Like(string propertyName, string value, HqlMatchMode matchMode) {
switch (matchMode) {
case HqlMatchMode.Start:
value = "'" + value + "%'";
break;
case HqlMatchMode.Exact:
break;
case HqlMatchMode.Anywhere:
value = "'%" + value + "%'";
break;
case HqlMatchMode.End:
value = "'%" + value + "'";
break;
}
return new BinaryExpression("like", propertyName, FormatValue((object)value, false));
}
public static IHqlCriterion Lt(string propertyName, object value) {
return new BinaryExpression("<", propertyName, FormatValue(value));
}
public static IHqlCriterion LtProperty(string propertyName, string otherPropertyName) {
return null;
}
public static IHqlCriterion NaturalId() {
return null;
}
public static IHqlCriterion Not(IHqlCriterion expression) {
return null;
}
public static IHqlCriterion NotEqProperty(string propertyName, string otherPropertyName) {
return null;
}
public static IHqlCriterion Or(IHqlCriterion lhs, IHqlCriterion rhs) {
return new CompositeHqlCriterion("or")
.Add(lhs)
.Add(rhs);
}
}
}

View File

@@ -0,0 +1,185 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Orchard.ContentManagement {
public interface IHqlExpressionFactory {
void Eq(string propertyName, object value);
void Like(string propertyName, string value, HqlMatchMode matchMode);
void InsensitiveLike(string propertyName, string value, HqlMatchMode matchMode);
void Gt(string propertyName, object value);
void Lt(string propertyName, object value);
void Le(string propertyName, object value);
void Ge(string propertyName, object value);
void Between(string propertyName, object lo, object hi);
void In(string propertyName, object[] values);
void In(string propertyName, ICollection values);
void InG<T>(string propertyName, ICollection<T> values);
void IsNull(string propertyName);
void EqProperty(string propertyName, string otherPropertyName);
void NotEqProperty(string propertyName, string otherPropertyName);
void GtProperty(string propertyName, string otherPropertyName);
void GeProperty(string propertyName, string otherPropertyName);
void LtProperty(string propertyName, string otherPropertyName);
void LeProperty(string propertyName, string otherPropertyName);
void IsNotNull(string propertyName);
void IsNotEmpty(string propertyName);
void IsEmpty(string propertyName);
void And(Action<IHqlExpressionFactory> lhs, Action<IHqlExpressionFactory> rhs);
void Or(Action<IHqlExpressionFactory> lhs, Action<IHqlExpressionFactory> rhs);
void Not(Action<IHqlExpressionFactory> expression);
void Conjunction(Action<IHqlExpressionFactory> expression, params Action<IHqlExpressionFactory>[] otherExpressions);
void Disjunction(Action<IHqlExpressionFactory> expression, params Action<IHqlExpressionFactory>[] otherExpressions);
void AllEq(IDictionary propertyNameValues);
void NaturalId();
}
public class DefaultHqlExpressionFactory : IHqlExpressionFactory {
public IHqlCriterion Criterion { get; private set; }
public void Eq(string propertyName, object value) {
Criterion = HqlRestrictions.Eq(propertyName, value);
}
public void Like(string propertyName, string value, HqlMatchMode matchMode) {
Criterion = HqlRestrictions.Like(propertyName, value, matchMode);
}
public void InsensitiveLike(string propertyName, string value, HqlMatchMode matchMode) {
Criterion = HqlRestrictions.InsensitiveLike(propertyName, value, matchMode);
}
public void Gt(string propertyName, object value) {
Criterion = HqlRestrictions.Gt(propertyName, value);
}
public void Lt(string propertyName, object value) {
Criterion = HqlRestrictions.Lt(propertyName, value);
}
public void Le(string propertyName, object value) {
Criterion = HqlRestrictions.Le(propertyName, value);
}
public void Ge(string propertyName, object value) {
Criterion = HqlRestrictions.Ge(propertyName, value);
}
public void Between(string propertyName, object lo, object hi) {
Criterion = HqlRestrictions.Between(propertyName, lo, hi);
}
public void In(string propertyName, object[] values) {
Criterion = HqlRestrictions.In(propertyName, values);
}
public void In(string propertyName, ICollection values) {
Criterion = HqlRestrictions.In(propertyName, values);
}
public void InG<T>(string propertyName, ICollection<T> values) {
Criterion = HqlRestrictions.InG(propertyName, values);
}
public void IsNull(string propertyName) {
Criterion = HqlRestrictions.IsNull(propertyName);
}
public void EqProperty(string propertyName, string otherPropertyName) {
Criterion = HqlRestrictions.EqProperty(propertyName, otherPropertyName);
}
public void NotEqProperty(string propertyName, string otherPropertyName) {
Criterion = HqlRestrictions.NotEqProperty(propertyName, otherPropertyName);
}
public void GtProperty(string propertyName, string otherPropertyName) {
Criterion = HqlRestrictions.GtProperty(propertyName, otherPropertyName);
}
public void GeProperty(string propertyName, string otherPropertyName) {
Criterion = HqlRestrictions.GeProperty(propertyName, otherPropertyName);
}
public void LtProperty(string propertyName, string otherPropertyName) {
Criterion = HqlRestrictions.LtProperty(propertyName, otherPropertyName);
}
public void LeProperty(string propertyName, string otherPropertyName) {
Criterion = HqlRestrictions.LeProperty(propertyName, otherPropertyName);
}
public void IsNotNull(string propertyName) {
Criterion = HqlRestrictions.IsNotNull(propertyName);
}
public void IsNotEmpty(string propertyName) {
Criterion = HqlRestrictions.IsNotEmpty(propertyName);
}
public void IsEmpty(string propertyName) {
Criterion = HqlRestrictions.IsEmpty(propertyName);
}
public void And(Action<IHqlExpressionFactory> lhs, Action<IHqlExpressionFactory> rhs) {
lhs(this);
var a = Criterion;
rhs(this);
var b = Criterion;
Criterion = HqlRestrictions.And(a, b);
}
public void Or(Action<IHqlExpressionFactory> lhs, Action<IHqlExpressionFactory> rhs) {
lhs(this);
var a = Criterion;
rhs(this);
var b = Criterion;
Criterion = HqlRestrictions.Or(a, b);
}
public void Not(Action<IHqlExpressionFactory> expression) {
expression(this);
var a = Criterion;
Criterion = HqlRestrictions.Not(a);
}
public void Conjunction(Action<IHqlExpressionFactory> expression, params Action<IHqlExpressionFactory>[] otherExpressions) {
var junction = HqlRestrictions.Conjunction();
foreach (var exp in Enumerable.Empty<Action<IHqlExpressionFactory>>().Union(new[] { expression }).Union(otherExpressions)) {
exp(this);
junction.Add(Criterion);
}
Criterion = junction;
}
public void Disjunction(Action<IHqlExpressionFactory> expression, params Action<IHqlExpressionFactory>[] otherExpressions) {
var junction = HqlRestrictions.Disjunction();
foreach (var exp in Enumerable.Empty<Action<IHqlExpressionFactory>>().Union(new[] { expression }).Union(otherExpressions)) {
exp(this);
junction.Add(Criterion);
}
Criterion = junction;
}
public void AllEq(IDictionary propertyNameValues) {
Criterion = HqlRestrictions.AllEq(propertyNameValues);
}
public void NaturalId() {
Criterion = HqlRestrictions.NaturalId();
}
}
public enum HqlMatchMode {
Exact,
Start,
End,
Anywhere
}
}

View File

@@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using Orchard.ContentManagement.Records;
namespace Orchard.ContentManagement {
public interface IHqlQuery {
IContentManager ContentManager { get; }
IHqlQuery ForType(params string[] contentTypes);
IHqlQuery ForVersion(VersionOptions options);
IHqlQuery<T> ForPart<T>() where T : IContent;
IEnumerable<ContentItem> List();
IEnumerable<ContentItem> Slice(int skip, int count);
int Count();
IHqlQuery Join(Action<IAliasFactory> alias);
IHqlQuery Where(Action<IAliasFactory> alias, Action<IHqlExpressionFactory> predicate);
IHqlQuery OrderBy(Action<IAliasFactory> alias, Action<IHqlSortFactory> order);
}
public interface IHqlQuery<out TPart> where TPart : IContent {
IHqlQuery<TPart> ForType(params string[] contentTypes);
IHqlQuery<TPart> ForVersion(VersionOptions options);
IEnumerable<TPart> List();
IEnumerable<TPart> Slice(int skip, int count);
int Count();
IHqlQuery<TPart> Join(Action<IAliasFactory> alias);
IHqlQuery<TPart> Where(Action<IAliasFactory> alias, Action<IHqlExpressionFactory> predicate);
IHqlQuery<TPart> OrderBy(Action<IAliasFactory> alias, Action<IHqlSortFactory> order);
}
public interface IAlias {
string Name { get; }
}
public interface IAliasFactory {
IAliasFactory ContentPartRecord<TRecord>() where TRecord : ContentPartRecord;
IAliasFactory ContentPartRecord(Type contentPartRecord);
IAliasFactory Property(string propertyName, string alias);
IAliasFactory Named(string alias); // returns an existing alias
}
public interface IHqlSortFactory {
void Asc(string propertyName);
void Desc(string propertyName);
}
/*
*
* query // IHqlQuery<ContentItem>
* .Join<RoutePartRecord>().As("route") // IAlias(query), IAlias<T>(query<TP>), IAlias<TP,TR>(query<TP,TR>) alias name is implicit, there can't be any conflict
* x => x.Where(route => route.
* )
*
* query.Join<
*
* query: IAlias
*
*
* IHqlQuery<T> ONLY, because we can have <ContentItem> by default, and the Records can't be used in expression though, thus having them
* in the generic type is useless. _manager.HqlQuery<GammaPart>() will create a new query then apply ForPart<GammaPart>
*
* .Join<TRecord> is only valid for ContentPartRecord because they will resolve the fake civ.{TRecord} property
* .Where<TRecord> is only valid for ContentPartRecord because they will resolve the fake civ.{TRecord} property
* .Where( on => on.Named("foo"), x => x.Eq("Id", 1))
*
*
* .Join( on => on.ContentPartRecord<FieldIndexPartRecord>().Property("IntegerFieldIndexRecords", alias: "integerFields")
* .Where( on => on.Named("foo"), x => x.Eq("Id", 1))
* .Where( on => on.ContentPartRecord<FieldIndexPartRecord>(), x => x.Eq("Id", 1))
*
*
* Join(Action<IAliasFactory> alias)
* Where(Action<IAliasFactory> alias, Action<IHqlExpression> predicate)
*
* Thus we can create aliases directly from the Where()
*
* IAlias {
* ContentPartRecord<TRecord>() where TRecord : ContentPartRecord
* Property(string propertyName, string alias)
* Named(string alias) // returns an existing alias
*
* }
*/
}

View File

@@ -169,7 +169,11 @@
<Compile Include="ContentManagement\ContentIdentity.cs" />
<Compile Include="ContentManagement\ContentItemBehavior.cs" />
<Compile Include="ContentManagement\ContentPartBehavior.cs" />
<Compile Include="ContentManagement\DefaultHqlQuery.cs" />
<Compile Include="ContentManagement\IHqlExpression.cs" />
<Compile Include="ContentManagement\IHqlQuery.cs" />
<Compile Include="ContentManagement\Handlers\DescribeMembersContext.cs" />
<Compile Include="ContentManagement\IHqlCriterion.cs" />
<Compile Include="ContentManagement\ISortFactory.cs" />
<Compile Include="ContentManagement\DefaultContentDisplay.cs" />
<Compile Include="ContentManagement\Drivers\ContentShapeResult.cs" />