all repos — litestore @ e324eb96723bae8299b270b7c06b9c882501032b

A minimalist nosql document store.

Now parsing select clauses.
h3rald h3rald@h3rald.com
Sat, 24 Feb 2018 12:04:59 +0100
commit

e324eb96723bae8299b270b7c06b9c882501032b

parent

1e311a41fb554c76ab2ac6906a47261e901d8a17

3 files changed, 39 insertions(+), 10 deletions(-)

jump to
M lib/api_v3.nimlib/api_v3.nim

@@ -42,14 +42,37 @@ table["contains"] = "contains"

return table[op] -proc filterClauses*(str: string, options: var QueryOptions): string = +proc selectClause*(str: string, options: var QueryOptions) = + let tokens = """ + path <- '$' (objItem / objField)+ + ident <- [a-zA-Z0-9_]+ + objIndex <- '[' \d+ ']' + objField <- '.' ident + objItem <- objField objIndex + """ + let fields = peg(""" + fields <- ^{field} (\s* ',' \s* {field})*$ + field <- path \s+ ('as' / 'AS') \s+ ident + """ & tokens) + let field = peg(""" + field <- ^{path} \s+ ('as' / 'AS') \s+ {ident}$ + """ & tokens) + var fieldMatches = newSeq[string](10) + if str.strip.match(fields, fieldMatches): + for m in fieldMatches: + if not m.isNil: + var rawTuple = newSeq[string](2) + if m.match(field, rawTuple): + options.jsonSelect.add((path: rawTuple[0], alias: rawTuple[1])) + +proc filterClauses*(str: string, options: var QueryOptions) = let tokens = """ operator <- 'not eq' / 'eq' / 'gte' / 'gt' / 'lte' / 'lt' / 'contains' value <- string / number / 'null' / 'true' / 'false' string <- '"' ('\"' . / [^"])* '"' number <- '-'? '0' / [1-9] [0-9]* ('.' [0-9]+)? (( 'e' / 'E' ) ( '+' / '-' )? [0-9]+)? path <- '$' (objItem / objField)+ - ident <- [a-zA-Z0-9_-]+ + ident <- [a-zA-Z0-9_]+ objIndex <- '[' \d+ ']' objField <- '.' ident objItem <- objField objIndex

@@ -87,7 +110,7 @@ parsedAndClauses.add clauses

if parsedAndClauses.len > 0: parsedClauses.add parsedAndClauses if parsedClauses.len == 0: - return "" + return var currentArr = 0 var tables = newSeq[string]() let resOrClauses = parsedClauses.map do (it: seq[seq[string]]) -> string:

@@ -100,7 +123,7 @@ else:

return "json_extract(documents.data, '$1') $2 $3" % x return resAndClauses.join(" AND ") options.tables = options.tables & tables - return resOrClauses.join(" OR ") + options.jsonFilter = resOrClauses.join(" OR ") proc parseQueryOption*(fragment: string, options: var QueryOptions) = var pair = fragment.split('=')

@@ -112,9 +135,13 @@ except:

raise newException(EInvalidRequest, "Unable to decode query string fragment '$1'" % fragment) case pair[0]: of "filter": - options.jsonFilter = filterClauses(pair[1], options) + filterClauses(pair[1], options) if options.jsonFilter == "": raise newException(EInvalidRequest, "Invalid filter clause: $1" % pair[1].replace("\"", "\\\"")) + of "select": + selectClause(pair[1], options) + if options.jsonSelect.len == 0: + raise newException(EInvalidRequest, "Invalid select clause: $1" % pair[1].replace("\"", "\\\"")) of "search": options.search = pair[1] of "tags":
M lib/types.nimlib/types.nim

@@ -23,6 +23,7 @@ mount*: string

QueryOptions* = object tables*: seq[string] jsonFilter*: string + jsonSelect*: seq[tuple[path: string, alias: string]] select*: seq[string] single*:bool limit*: int

@@ -100,4 +101,4 @@ "Server": LS.appname & "/" & LS.appversion

} proc newQueryOptions*(): QueryOptions = - return QueryOptions(select: @["documents.id AS id", "documents.data AS data", "content_type", "binary", "searchable", "created", "modified"], single: false, limit: 0, offset: 0, orderby: "", tags: "", search: "", folder: "", jsonFilter: "", tables: newSeq[string]()) + return QueryOptions(select: @["documents.id AS id", "documents.data AS data", "content_type", "binary", "searchable", "created", "modified"], single: false, limit: 0, offset: 0, orderby: "", tags: "", search: "", folder: "", jsonFilter: "", jsonSelect: newSeq[tuple[path: string, alias: string]](), tables: newSeq[string]())
M lib/utils.nimlib/utils.nim

@@ -7,6 +7,7 @@ strutils,

pegs, asyncdispatch, math, + sequtils, strtabs import

@@ -36,6 +37,9 @@

proc prepareSelectDocumentsQuery*(options: var QueryOptions): string = var tables = options.tables result = "SELECT " + if options.jsonFilter.len > 0: + if not options.tags.contains("$subtype:json"): + options.tags = options.tags.split(",").concat(@["$subtype:json"]).join(",") if options.search.len > 0: if options.select[0] != "COUNT(docid)": let rank = "rank(matchinfo(searchdata, 'pcxnal'), 1.20, 0.75, 5.0, 0.5) AS rank"

@@ -70,16 +74,13 @@ if options.single:

result = result & "AND id = ?" var doc_id_col: string if options.tags.len > 0 or options.folder.len > 0: - if options.search.len > 0 and options.select[0] != "COUNT(docid)": + if options.jsonFilter.len > 0 or (options.search.len > 0 and options.select[0] != "COUNT(docid)"): doc_id_col = "documents.id" else: doc_id_col = "id" if options.folder.len > 0: result = result & "AND " & doc_id_col & " LIKE ? " if options.tags.len > 0: - if options.jsonFilter.len > 0: - if options.tags.contains("$subtype:json"): - options.tags = options.tags & ",$subtype:json" result = result & options.tags.selectDocumentsByTags(doc_id_col) if options.jsonFilter.len > 0: result = result & "AND " & options.jsonFilter