forked from ravendb/ravendb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
AbstractViewGenerator.cs
173 lines (144 loc) · 4.85 KB
/
AbstractViewGenerator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//-----------------------------------------------------------------------
// <copyright file="AbstractViewGenerator.cs" company="Hibernating Rhinos LTD">
// Copyright (c) Hibernating Rhinos LTD. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Text.RegularExpressions;
using Lucene.Net.Documents;
using Raven.Abstractions.Indexing;
using Raven.Abstractions.Linq;
using System.Linq;
using Raven.Database.Indexing;
namespace Raven.Database.Linq
{
/// <summary>
/// This class represents a base class for all "Views" we generate and compile on the fly - all
/// Map and MapReduce indexes are being re-written into this class and then compiled and executed
/// against the data in RavenDB
/// </summary>
[InheritedExport]
public abstract class AbstractViewGenerator
{
private readonly HashSet<string> fields = new HashSet<string>();
private bool? containsProjection;
private int? countOfSelectMany;
private bool? hasWhereClause;
private readonly HashSet<string> mapFields = new HashSet<string>();
private readonly HashSet<string> reduceFields = new HashSet<string>();
private static readonly Regex selectManyOrFrom = new Regex(@"( (^|\s) from \s ) | ( \.SelectMany\( )",
RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
public int CountOfSelectMany
{
get
{
if(countOfSelectMany == null)
{
countOfSelectMany = selectManyOrFrom.Matches(ViewText).Count;
}
return countOfSelectMany.Value;
}
}
public int CountOfFields { get { return fields.Count; } }
public List<IndexingFunc> MapDefinitions { get; private set; }
public IndexingFunc ReduceDefinition { get; set; }
public TranslatorFunc TransformResultsDefinition { get; set; }
public GroupByKeyFunc GroupByExtraction { get; set; }
public string ViewText { get; set; }
public IDictionary<string, FieldStorage> Stores { get; set; }
public IDictionary<string, FieldIndexing> Indexes { get; set; }
public HashSet<string> ForEntityNames { get; set; }
public string[] Fields
{
get { return fields.ToArray(); }
}
public bool HasWhereClause
{
get
{
if(hasWhereClause == null)
{
hasWhereClause = ViewText.IndexOf("where", StringComparison.OrdinalIgnoreCase) > -1;
}
return hasWhereClause.Value;
}
}
protected AbstractViewGenerator()
{
MapDefinitions = new List<IndexingFunc>();
ForEntityNames = new HashSet<string>();
Stores = new Dictionary<string, FieldStorage>();
Indexes = new Dictionary<string, FieldIndexing>();
}
protected IEnumerable<AbstractField> CreateField(string name, object value, bool stored = false, bool indexed = true)
{
var indexDefinition = new IndexDefinition();
indexDefinition.Indexes[name] = indexed ? FieldIndexing.Analyzed : FieldIndexing.NotAnalyzed;
var anonymousObjectToLuceneDocumentConverter = new AnonymousObjectToLuceneDocumentConverter(indexDefinition);
return anonymousObjectToLuceneDocumentConverter.CreateFields(name, value, stored ? Field.Store.YES : Field.Store.NO);
}
protected IEnumerable<dynamic> Hierarchy(object source, string name)
{
var djo = (DynamicJsonObject)source;
foreach (var item in ((IEnumerable)djo.GetValue(name)))
{
yield return item;
foreach (var subItem in Hierarchy(item, name))
{
yield return subItem;
}
}
}
protected IEnumerable<dynamic> Recurse(object item, Func<dynamic ,dynamic> func)
{
if (item == null)
return Enumerable.Empty<dynamic>();
var resultsOrdered = new List<dynamic>();
var results = new HashSet<object>();
item = func(item);
while (item != null)
{
if (results.Add(item) == false)
break;
resultsOrdered.Add(item);
item = func(item);
}
return new DynamicList(resultsOrdered.ToArray());
}
public void AddQueryParameterForMap(string field)
{
mapFields.Add(field);
}
public void AddQueryParameterForReduce(string field)
{
reduceFields.Add(field);
}
public void AddField(string field)
{
fields.Add(field);
}
public virtual bool ContainsFieldOnMap(string field)
{
if (ReduceDefinition == null)
return fields.Contains(field);
return mapFields.Contains(field);
}
public virtual bool ContainsField(string field)
{
if (fields.Contains(field))
return true;
if (containsProjection == null)
{
containsProjection = ViewText != null && ViewText.Contains("Project(");
}
return containsProjection.Value;
}
protected void AddMapDefinition(IndexingFunc mapDef)
{
MapDefinitions.Add(mapDef);
}
}
}