1 /**
2 	* Defines the `ESParams` type for use in the API
3 	*
4 	* Copyright: © 2015 David Monagle
5 	* License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
6 	* Authors: David Monagle
7 */
8 module elasticsearch.api.parameters;
9 
10 import vibe.utils.dictionarylist;
11 import elasticsearch.api.exceptions;
12 import core.exception;
13 
14 import std.array;
15 import std.algorithm;
16 import std.string;
17 
18 /// Common ES parameters
19 static enum ES_COMMON_PARAMETERS = [
20 	"ignore",
21 	//"index", "type", "id",
22 	//"body",
23 	"node_id",
24 	"name",
25 	"field"
26 ];
27 
28 /// Common ES parameters used in queries
29 static enum ES_COMMON_QUERY_PARAMETERS = [
30 	"format",
31 	"pretty",
32 	"human"
33 ];
34 
35 /// ESParams is just an alias for a vibe.d dictionary list
36 alias ESParams = vibe.inet.message.InetHeaderMap;
37 
38 bool hasField(const ref ESParams p, string key) {
39 	return cast(bool)(key in p);
40 }
41 
42 /// Filters the given `ESParams` to only include the given keys. Returns a new range containing the allowed keys
43 ESParams filterESParams(const ref ESParams p, string[] allowed ...) {
44 	import std.algorithm;
45 
46 	ESParams returnParams;
47 
48 	foreach(key, value; p) {
49 		if (allowed.canFind(key)) returnParams.addField(key, value);
50 	}
51 
52 	return returnParams;
53 }
54 
55 unittest {
56 	ESParams p;
57 	p["one"] = "Hello";
58 	p["two"] = "Goodbye";
59 	
60 	auto filtered = p.filterESParams("one");
61 	
62 	assert(filtered.hasField("one"));
63 	assert(!filtered.hasField("two"));
64 }
65 
66 /// Returns the value of the supplied `ESParams ` or returns the defaultValue if it doesn't exist
67 T valueOrDefault(T)(ESParams p, string key, T defaultValue) {
68 	import std.conv;
69 
70 	if (key !in p) return defaultValue;
71 	return p[key].to!T;
72 }
73 
74 unittest {
75 	ESParams p;
76 	p["one"] = "1";
77 
78 	assert(p.valueOrDefault("one", 2) == 1);
79 	assert(p.valueOrDefault("two", 2) == 2);
80 }
81 
82 /// Throws an argument exception if the given parameter is not included in `p`
83 void enforceParameter(const ref ESParams p, string name) {
84 	enforce(p.hasField(name), new ArgumentException(p, name ~ " parameter is required"));
85 }
86 
87 /// Sets a parameter to a default value if if does not exist
88 void defaultParameter(ref ESParams p, string name, string defaultValue) {
89 	if(!p.hasField(name)) p[name] = defaultValue;
90 }
91 
92 /// Returns a new list of params which will only included common parameters plus those `allowed` passed in parameters
93 ESParams validateAndExtract(const ref ESParams params, string[] allowed ...) {
94 	return params.filterESParams(allowed ~ ES_COMMON_PARAMETERS ~ ES_COMMON_QUERY_PARAMETERS);
95 }
96 
97 /// Escapes the given string for use with ES API
98 string esEscape(string value) {
99 	import std.uri;
100 	
101 	return encodeComponent(value);
102 }
103 
104 /// Takes an array of strings representing a path and returns a clean path string
105 string esPathify(string[] path ...) {
106 	auto stripped = array(path.map!((p) => p.strip));
107 	auto cleanPath = stripped.remove!((p) => !p.length);
108 	auto returnString = cleanPath.join("/");
109 	return returnString.squeeze("/");
110 }
111 
112 unittest {
113 	assert(esPathify("hello/", "", " world") == "hello/world");
114 }
115 
116 /// Create a list from the given arguments
117 string esListify(string[] list ...) {
118 	auto cleanList = list.remove!((p) => !p.length);
119 	auto escaped = array(cleanList.map!((l) => l.esEscape));
120 	
121 	return escaped.join(",");
122 }
123 
124 unittest {
125 	assert(esListify("A", "B") == "A,B");
126 	assert(esListify("one", "two^three") == "one,two%5Ethree");
127 }