1 /** 2 Module that can parse a query. 3 */ 4 module ezdb.query.parse; 5 6 import ezdb.query.tree; 7 8 import std.uni; 9 import std.range; 10 version(unittest) import fluent.asserts; 11 12 /** 13 Splits camelcased words 14 */ 15 private string[] splitCamelCasedWords(string sentence) 16 { 17 string[] words; 18 string word; 19 foreach (chr; sentence) 20 { 21 if (chr.isUpper) 22 { 23 words ~= word.toLower(); 24 word = [chr]; 25 } 26 else 27 word ~= chr; 28 } 29 words ~= word.toLower(); 30 return words; 31 } 32 33 @("Can split camelcased words") 34 unittest 35 { 36 const words = splitCamelCasedWords("helloWorldFooBar"); 37 words.should.equal(["hello", "world", "foo", "bar"]); 38 } 39 40 /** 41 Parses a query action. 42 */ 43 private QueryAction parseQueryAction(string action) 44 { 45 switch (action) 46 { 47 case "find": 48 case "select": 49 return QueryAction.select; 50 case "remove": 51 case "delete": 52 return QueryAction.remove; 53 default: 54 assert(0, "Unsupported query action: " ~ action); 55 } 56 } 57 58 /** 59 Parses a query filter. 60 */ 61 private QueryFilter parseQueryFilter(string column) 62 { 63 QueryFilter filter; 64 filter.column = column; 65 filter.type = QueryFilterType.equal; 66 return filter; 67 } 68 69 /** 70 Parses a query. 71 */ 72 Query parseQuery(string sentences) 73 { 74 Query query; 75 const words = splitCamelCasedWords(sentences); 76 assert(words.length >= 3, "Query needs to contain at least 3 words"); 77 query.action = parseQueryAction(words[0]); 78 79 assert(words[1] == "by", "Second word of query should be 'by'"); 80 81 foreach (word; words[1..$].chunks(2)) 82 query.filters ~= parseQueryFilter(word[1]); 83 84 return query; 85 } 86 87 @("Can parse a simple query") 88 unittest 89 { 90 const query = parseQuery("findById"); 91 query.action.should.equal(QueryAction.select); 92 query.filters.length.should.equal(1); 93 query.filters[0].type.should.equal(QueryFilterType.equal); 94 query.filters[0].column.should.equal("id"); 95 }