forked from ravendb/ravendb
/
DatabaseExtensions.cs
145 lines (126 loc) · 4.96 KB
/
DatabaseExtensions.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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Raven.Database;
using Raven.Bundles.DynamicQueries.Data;
using Raven.Database.Data;
using System.Threading;
using System.Diagnostics;
using Microsoft.Isam.Esent.Interop;
using Raven.Database.Indexing;
using Raven.Database.Plugins;
using Raven.Database.Json;
using Raven.Database.Extensions;
namespace Raven.Bundles.DynamicQueries.Database
{
public static class DatabaseExtensions
{
public static QueryResults ExecuteDynamicQuery(this DocumentDatabase database, DynamicQuery query)
{
// TODO: Check for existence of created query
/* Use the below code to query that created query
QueryResult result = null;
var sp = Stopwatch.StartNew();
while (true)
{
result = database.Query(indexName,
new Raven.Database.Data.IndexQuery()
{
Cutoff = dateStart,
PageSize = query.PageSize,
Query = query.Query,
Start = query.Start
});
if (result.IsStale)
{
if (sp.Elapsed.TotalMilliseconds > 10000)
{
sp.Stop();
break;
}
Thread.Sleep(100);
continue;
}
else
{
break;
}
}
* */
// Fall back to a temporary query
return PerformTemporaryQuery(database, query);
}
private static QueryResults PerformTemporaryQuery(DocumentDatabase database, DynamicQuery query)
{
// This is our cut-off date, one way or another
var dateStart = DateTime.Now;
var indexName = String.Format("Temp_{0}", Guid.NewGuid().ToString());
var mapping = query.Mappings
.Select(x=> string.Format("{0} = doc.{1}", x.To, x.From))
.ToArray();
// Create the definition
var definition = new IndexDefinition(){
Map = @"from doc in docs select new
{
" + String.Join(",\r\n", mapping) + @"
}",
};
// Store the actual index definition
database.IndexDefinitionStorage.AddIndex(indexName, definition);
database.IndexStorage.CreateIndexImplementation(indexName, definition);
database.TransactionalStorage.Batch(actions =>
{
actions.Indexing.AddIndexAsTemporary(indexName);
});
// Perform a manual run-through of this index
var viewGenerator = database.IndexDefinitionStorage.GetViewGenerator(indexName);
var currentEtag = Guid.Empty;
bool docsPending = true;
// Perform the on-demand index
while(docsPending){
database.TransactionalStorage.Batch(actions=>{
// We get some docs
var jsonDocs = actions.Documents.GetDocumentsAfter(currentEtag)
.Where(x => x != null && x.LastModified < dateStart)
.Take(10000)
.ToArray();
// Stop searching once we've reached cut-off
if(jsonDocs.Length == 0){
docsPending = false;
return;
}
var documentRetriever = new DocumentRetriever(null, database.WorkContext.ReadTriggers);
// Perform the index
database.WorkContext.IndexStorage.Index(indexName, viewGenerator,
jsonDocs
.Select(doc => documentRetriever.ProcessReadVetoes(doc, null, ReadOperation.Index))
.Where(doc => doc != null)
.Select(x => JsonToExpando.Convert(x.ToJson())), database.WorkContext, actions, dateStart);
// And update our etag
currentEtag = jsonDocs.Last().Etag;
});
}
// Query
var result = database.Query(indexName,
new IndexQuery()
{
Cutoff = dateStart,
PageSize = query.PageSize,
Query = query.Query,
Start = query.Start
});
// Destroy the index
database.TransactionalStorage.Batch(actions =>
{
actions.Indexing.DeleteIndex(indexName);
});
database.IndexDefinitionStorage.RemoveIndex(indexName);
database.IndexStorage.DeleteIndex(indexName);
return new QueryResults()
{
Results = result.Results.ToArray()
};
}
}
}