Skip to content

Commit 7c5aa98

Browse files
committed
Merge pull request Azure#47 from arramac/master
Add JavaScript language integrated query samples
2 parents 57b6460 + 6ce0081 commit 7c5aa98

File tree

6 files changed

+407
-1
lines changed

6 files changed

+407
-1
lines changed

samples/code-samples/DocumentDB.Samples.sln

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio 2013
4-
VisualStudioVersion = 12.0.31101.0
4+
VisualStudioVersion = 12.0.30501.0
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2DF914B1-91A8-4C78-989B-64D1ABEF6A17}"
77
ProjectSection(SolutionItems) = preProject
@@ -37,6 +37,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Queries.OrderBy", "Queries.
3737
EndProject
3838
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Queries.Spatial", "Queries.Spatial\Queries.Spatial.csproj", "{798560FA-2AD7-45A9-94B0-7A12FA2B8A51}"
3939
EndProject
40+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Queries.JavaScript", "Queries.JavaScript\Queries.JavaScript.csproj", "{D876FAB8-B479-4E65-A80D-D0F6CDD5B243}"
41+
EndProject
4042
Global
4143
GlobalSection(SolutionConfigurationPlatforms) = preSolution
4244
Debug|Any CPU = Debug|Any CPU
@@ -87,6 +89,10 @@ Global
8789
{798560FA-2AD7-45A9-94B0-7A12FA2B8A51}.Debug|Any CPU.Build.0 = Debug|Any CPU
8890
{798560FA-2AD7-45A9-94B0-7A12FA2B8A51}.Release|Any CPU.ActiveCfg = Release|Any CPU
8991
{798560FA-2AD7-45A9-94B0-7A12FA2B8A51}.Release|Any CPU.Build.0 = Release|Any CPU
92+
{D876FAB8-B479-4E65-A80D-D0F6CDD5B243}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
93+
{D876FAB8-B479-4E65-A80D-D0F6CDD5B243}.Debug|Any CPU.Build.0 = Debug|Any CPU
94+
{D876FAB8-B479-4E65-A80D-D0F6CDD5B243}.Release|Any CPU.ActiveCfg = Release|Any CPU
95+
{D876FAB8-B479-4E65-A80D-D0F6CDD5B243}.Release|Any CPU.Build.0 = Release|Any CPU
9096
EndGlobalSection
9197
GlobalSection(SolutionProperties) = preSolution
9298
HideSolutionNode = FALSE
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<configuration>
3+
<startup>
4+
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
5+
</startup>
6+
<appSettings file="appSettings.config"/>
7+
</configuration>
Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
namespace DocumentDB.Samples.Queries.Spatial
2+
{
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Configuration;
6+
using System.IO;
7+
using System.Linq;
8+
using System.Threading.Tasks;
9+
using DocumentDB.Samples.Shared;
10+
using Microsoft.Azure.Documents;
11+
using Microsoft.Azure.Documents.Client;
12+
using Microsoft.Azure.Documents.Linq;
13+
using Microsoft.Azure.Documents.Spatial;
14+
using Newtonsoft.Json;
15+
using Newtonsoft.Json.Serialization;
16+
17+
/// <summary>
18+
/// This sample demonstrates the use of geospatial indexing and querying with Azure DocumentDB. We
19+
/// look at how to store Points using the classes in the Microsoft.Azure.Documents.Spatial namespace,
20+
/// how to enable a collection for geospatial indexing, and how to query for WITHIN and DISTANCE
21+
/// using SQL and LINQ.
22+
/// </summary>
23+
public class Program
24+
{
25+
/// <summary>
26+
/// Gets the database ID to use for the demo.
27+
/// </summary>
28+
private static readonly string DatabaseId = ConfigurationManager.AppSettings["DatabaseId"];
29+
30+
/// <summary>
31+
/// Gets the collection ID to use for the demo.
32+
/// </summary>
33+
private static readonly string CollectionId = ConfigurationManager.AppSettings["CollectionId"];
34+
35+
/// <summary>
36+
/// Gets the DocumentDB endpoint to use for the demo.
37+
/// </summary>
38+
private static readonly string EndpointUrl = ConfigurationManager.AppSettings["EndPointUrl"];
39+
40+
/// <summary>
41+
/// Gets the DocumentDB authorization key to use for the demo.
42+
/// </summary>
43+
private static readonly string AuthorizationKey = ConfigurationManager.AppSettings["AuthorizationKey"];
44+
45+
/// <summary>
46+
/// Gets an indexing policy with spatial enabled. You can also configure just certain paths for spatial indexing, e.g. Path = "/location/?"
47+
/// </summary>
48+
private static readonly IndexingPolicy IndexingPolicyWithSpatialEnabled = new IndexingPolicy
49+
{
50+
IncludedPaths = new System.Collections.ObjectModel.Collection<IncludedPath>()
51+
{
52+
new IncludedPath
53+
{
54+
Path = "/*",
55+
Indexes = new System.Collections.ObjectModel.Collection<Index>()
56+
{
57+
new SpatialIndex(DataType.Point),
58+
new RangeIndex(DataType.Number) { Precision = -1 },
59+
new RangeIndex(DataType.String) { Precision = -1 }
60+
}
61+
}
62+
}
63+
};
64+
65+
/// <summary>
66+
/// Gets the client to use.
67+
/// </summary>
68+
private static DocumentClient client;
69+
70+
/// <summary>
71+
/// The main method to use.
72+
/// </summary>
73+
/// <param name="args">The command line arguments.</param>
74+
public static void Main(string[] args)
75+
{
76+
try
77+
{
78+
// Get a Document client
79+
using (client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey))
80+
{
81+
RunDemoAsync(DatabaseId, CollectionId).Wait();
82+
}
83+
}
84+
catch (DocumentClientException de)
85+
{
86+
Exception baseException = de.GetBaseException();
87+
Console.WriteLine("{0} error occurred: {1}, Message: {2}", de.StatusCode, de.Message, baseException.Message);
88+
}
89+
catch (Exception e)
90+
{
91+
Exception baseException = e.GetBaseException();
92+
Console.WriteLine("Error: {0}, Message: {1}", e.Message, baseException.Message);
93+
}
94+
finally
95+
{
96+
Console.WriteLine("End of demo, press any key to exit.");
97+
Console.ReadKey();
98+
}
99+
}
100+
101+
/// <summary>
102+
/// Run the geospatial demo.
103+
/// </summary>
104+
/// <param name="databaseId">The database Id.</param>
105+
/// <param name="collectionId">The collection Id.</param>
106+
/// <returns>The Task for asynchronous execution.</returns>
107+
private static async Task RunDemoAsync(string databaseId, string collectionId)
108+
{
109+
Database database = await GetDatabaseAsync(databaseId);
110+
111+
// Create a new collection, or modify an existing one to enable spatial indexing.
112+
DocumentCollection collection = await GetCollection(database.SelfLink, collectionId);
113+
114+
await CreateDocumentAsync(collection.SelfLink, "{ firstName: 'Ryan', lastName: 'Crawcour', address: { country: 'NZ' }}");
115+
await CreateDocumentAsync(collection.SelfLink, "{ firstName: 'Aravind', lastName: 'Ramachandran', address: { city: 'Kirkland', state: 'WA' }}");
116+
await CreateDocumentAsync(collection.SelfLink, "{ firstName: 'Andrew', lastName: 'Liu', address: { city: 'Seattle', state: 'WA' }}");
117+
118+
// Run a simple filter query
119+
object filterQueryResult = await QueryScalar(
120+
collection.SelfLink,
121+
@"__.filter(function(person) { return person.firstName === 'Andrew'; })");
122+
123+
Console.WriteLine("Filter query returned: {0}", filterQueryResult);
124+
125+
// Run a map (projection) query
126+
object projectionQueryResult = await QueryScalar(
127+
collection.SelfLink,
128+
@"__.map(function(person) { return { familyName: person.lastName, address: person.address }; })");
129+
130+
Console.WriteLine("Projection query returned: {0}", JsonConvert.SerializeObject(projectionQueryResult, Formatting.Indented));
131+
132+
// Run a query using filter and map (using chaining)
133+
object chainQueryResult = await QueryScalar(collection.SelfLink,
134+
@"__.chain()
135+
.filter(function(person) { return person.firstName === 'Andrew'; })
136+
.map(function(person) { return { familyName: person.lastName, address: person.address }; })
137+
.value()");
138+
139+
Console.WriteLine("Chain (filter & projection) query returned: {0}", JsonConvert.SerializeObject(chainQueryResult, Formatting.Indented));
140+
141+
// Run a chained filter, map and sorting (using chaining)
142+
object sortQueryResult = await QueryScalar(collection.SelfLink,
143+
@"__.chain()
144+
.filter(function(person) { return person.firstName === 'Andrew' || person.firstName === 'Ryan'; })
145+
.sortBy(function(person) { return person.lastName; })
146+
.map(function(person) { return { familyName: person.lastName, address: person.address }; })
147+
.value()");
148+
149+
Console.WriteLine("Chain (filter, sort & projection) query returned: {0}", JsonConvert.SerializeObject(sortQueryResult, Formatting.Indented));
150+
151+
await Cleanup(collection);
152+
}
153+
154+
/// <summary>
155+
/// Get a Database for this id. Delete if it already exists.
156+
/// </summary>
157+
/// <param name="id">The id of the Database to create.</param>
158+
/// <returns>The created Database object</returns>
159+
private static async Task<Database> GetDatabaseAsync(string id)
160+
{
161+
Database database = client.CreateDatabaseQuery().Where(c => c.Id == id).ToArray().FirstOrDefault();
162+
if (database != null)
163+
{
164+
return database;
165+
}
166+
167+
Console.WriteLine("Creating new database...");
168+
database = await client.CreateDatabaseAsync(new Database { Id = id });
169+
170+
return database;
171+
}
172+
173+
/// <summary>
174+
/// Get a DocumentCollection by id, or create a new one if one with the id provided doesn't exist.
175+
/// </summary>
176+
/// <param name="databaseLink">The database self-link to use.</param>
177+
/// <param name="id">The id of the DocumentCollection to search for, or create.</param>
178+
/// <returns>The matched, or created, DocumentCollection object</returns>
179+
private static async Task<DocumentCollection> GetCollection(string databaseLink, string id)
180+
{
181+
DocumentCollection collection = client.CreateDocumentCollectionQuery(databaseLink)
182+
.Where(c => c.Id == id)
183+
.AsEnumerable()
184+
.FirstOrDefault();
185+
186+
if (collection != null)
187+
{
188+
return collection;
189+
}
190+
191+
Console.WriteLine("Creating new collection...");
192+
193+
collection = await client.CreateDocumentCollectionAsync(
194+
databaseLink,
195+
new DocumentCollection
196+
{
197+
Id = id,
198+
IndexingPolicy = new IndexingPolicy(new RangeIndex(DataType.String) { Precision = -1 })
199+
});
200+
201+
return collection;
202+
}
203+
204+
/// <summary>
205+
/// Run a query that returns a single document, and display it
206+
/// </summary>
207+
/// <param name="collectionLink">The collection self-link</param>
208+
/// <param name="query">The query to run</param>
209+
private static async Task<object> QueryScalar(string collectionLink, string javascriptQuery)
210+
{
211+
string javaScriptFunctionStub = string.Format("function() {{ {0}; }}", javascriptQuery);
212+
string singleQuerySprocName = "query";
213+
214+
StoredProcedure currentProcedure = client.CreateStoredProcedureQuery(collectionLink)
215+
.Where(s => s.Id == singleQuerySprocName)
216+
.AsEnumerable()
217+
.FirstOrDefault();
218+
219+
if (currentProcedure != null)
220+
{
221+
currentProcedure.Body = javaScriptFunctionStub;
222+
await client.ReplaceStoredProcedureAsync(currentProcedure);
223+
}
224+
else
225+
{
226+
currentProcedure = await client.CreateStoredProcedureAsync(
227+
collectionLink,
228+
new StoredProcedure
229+
{
230+
Id = singleQuerySprocName,
231+
Body = javaScriptFunctionStub
232+
});
233+
}
234+
235+
StoredProcedureResponse<object> result = await client.ExecuteStoredProcedureAsync<object>(currentProcedure.SelfLink);
236+
return result.Response;
237+
}
238+
239+
/// <summary>
240+
/// Create a document from JSON string
241+
/// </summary>
242+
/// <param name="collectionLink">The collection self-link</param>
243+
/// <param name="query">The JSON to create</param>
244+
private static async Task CreateDocumentAsync(string collectionLink, string json)
245+
{
246+
using (System.IO.MemoryStream ms = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(json)))
247+
{
248+
Document documentFromJson = Document.LoadFrom<Document>(ms);
249+
await client.CreateDocumentAsync(collectionLink, documentFromJson);
250+
}
251+
}
252+
253+
/// <summary>
254+
/// Cleanup data from previous runs.
255+
/// </summary>
256+
/// <param name="collection">The DocumentDB collection.</param>
257+
/// <returns>The Task for asynchronous execution.</returns>
258+
private static async Task Cleanup(DocumentCollection collection)
259+
{
260+
Console.WriteLine("Cleaning up");
261+
foreach (Document d in await client.ReadDocumentFeedAsync(collection.SelfLink))
262+
{
263+
await client.DeleteDocumentAsync(d.SelfLink);
264+
}
265+
}
266+
}
267+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle("Queries.JavaScript")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("")]
12+
[assembly: AssemblyProduct("Queries.JavaScript")]
13+
[assembly: AssemblyCopyright("Copyright © 2015")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible(false)]
21+
22+
// The following GUID is for the ID of the typelib if this project is exposed to COM
23+
[assembly: Guid("7f70fda7-b88d-43fb-be18-94ac745cd092")]
24+
25+
// Version information for an assembly consists of the following four values:
26+
//
27+
// Major Version
28+
// Minor Version
29+
// Build Number
30+
// Revision
31+
//
32+
// You can specify all the values or you can default the Build and Revision Numbers
33+
// by using the '*' as shown below:
34+
// [assembly: AssemblyVersion("1.0.*")]
35+
[assembly: AssemblyVersion("1.0.0.0")]
36+
[assembly: AssemblyFileVersion("1.0.0.0")]

0 commit comments

Comments
 (0)