From 9fa8fa2fbb0c2423281ac7c2072daba804036aa0 Mon Sep 17 00:00:00 2001
From: adam
Date: Wed, 20 Mar 2013 17:30:11 +0700
Subject: [PATCH] Working on lua documentation
---
luaejdb/doc/index.html | 1220 +++++++++++++++++++++++++++++++++++++++++++++---
luaejdb/ejdb.lua | 89 ++--
luaejdb/ejdb.luadoc | 280 +++++++++--
luaejdb/test/t1.lua | 9 +-
node/ejdb.js | 4 +-
5 files changed, 1470 insertions(+), 132 deletions(-)
diff --git a/luaejdb/doc/index.html b/luaejdb/doc/index.html
index 0fd9211..fb6e468 100644
--- a/luaejdb/doc/index.html
+++ b/luaejdb/doc/index.html
@@ -123,12 +123,40 @@
Save/update specified JSON objects in the collection. |
- DB:find (cname, q) |
+ DB:find (cname, q, flags) |
Execute query on collection. |
+ DB:findOne (cname, q) |
+ Same as DB:find but retrieves only first matching JSON object. |
+
+
+ DB:update (cname, q) |
+ Convenient method to execute update queries. |
+
+
+ DB:count (cname, q) |
+ Convenient count(*) operation. |
+
+
+ RS:object (i) |
+ Returns result set lua table object at specified position i |
+
+
+ RS:field (i, name) |
+ Returns field value of lua object at specified position i |
+
+
+ RS.__len () |
+ Length of result set. |
+
+
+ Q:F (fname) |
+ Set current field for the next operation during query building. |
+
+
Q:Eq (val) |
- Field eq restriction. |
+ Field equality restriction. |
Q:ElemMatch (val) |
@@ -154,6 +182,95 @@
Q:Lte (val) |
Lesser than or equal (val <= arg) |
+
+ Q:Icase (val) |
+ Case insensitive string matching |
+
+
+ Q:Begin (val) |
+ String starts with prefix |
+
+
+ Q:In (val) |
+ Field value matched any value of specified in val table. |
+
+
+ Q:NotIn (val) |
+ Negation of Q:In |
+
+
+ Q:Bt (n1, n2) |
+ Between for number types |
+
+
+ Q:StrAnd (val) |
+ String tokens(or string array vals) matches all tokens in specified val array. |
+
+
+ Q:StrOr (val) |
+ String tokens(or string array vals) matches any token in specified array. |
+
+
+ Q:Inc (val) |
+ Increment current field. |
+
+
+ Q:Set (val) |
+ Set fields to values. |
+
+
+ Q:Upsert (val) |
+ Atomic upsert. |
+
+
+ Q:AddToSet (val) |
+ Atomically adds val to the array field only if val not in the array already. |
+
+
+ Q:AddToSetAll (val) |
+ Atomically performs set union with values in val for specified array field. |
+
+
+ Q:Pull (val) |
+ Atomically removes all occurrences of val from field, if field is an array. |
+
+
+ Q:PullAll (val) |
+ Atomically performs set substraction of values in val for specified array field. |
+
+
+ Q:DropAll () |
+ In-place record removal operation. |
+
+
+ Q:Join (cname, fpath) |
+ Make collection join
+ for select queries. |
+
+
+ Q:Or (...) |
+ Add OR joined query restrictions. |
+
+
+ Q:Skip (val) |
+ Sets number of skipped records in the result set. |
+
+
+ Q:Max (val) |
+ Sets max number of records in the result set. |
+
+
+ Q:OrderBy (...) |
+ Set sorting rules for query results. |
+
+
+ Q:Fields (...) |
+ Sets fields to be included in resulting objects. |
+
+
+ Q:NotFields (...) |
+ Sets fields to be excluded from resulting objects. |
+
@@ -166,6 +283,10 @@
DB |
Database itself. |
+
+ RS |
+ Result set cursor object. |
+
@@ -180,19 +301,21 @@
Opens EJDB database.
- w
Open as a writer
- r
Open as a reader
- c
Create db if it not exists
- t
Truncate existing db
- s
Sycn db after each transaction
- Default open mode: rws
Parameters:
- path
- {String} Database main file
+ string
+ Database main file
- mode
- {String?} Database open mode flags:
+ optional string
+ Database open mode flags:
+ w
Open as a writer
+ r
Open as a reader
+ c
Create db if it not exists
+ t
Truncate existing db
+ s
Sycn db after each transaction
+ Default open mode: rwcs
Returns:
@@ -232,7 +355,8 @@
Parameters:
- val
- {String} 24 hex chars BSON_OID
+ string
+ 24 hex chars BSON_OID
@@ -293,9 +417,11 @@
Parameters:
- re
- {String} Regular expression
+ string
+ Regular expression
- opts
- {String} Regular expression flags
+ optional string
+ Regular expression flags
Returns:
@@ -535,9 +661,11 @@
Parameters:
- cname
- {String} Name of collection.
+ string
+ Name of collection.
- obj
- Lua table or Q represents JSON object.
+ table or Q
+ represents JSON object.
- ...
If last argument is True a saved object will be merged with who's
@@ -554,15 +682,17 @@
- DB:find (cname, q)
+ DB:find (cname, q, flags)
Execute query on collection.
- EJDB queries inspired by MongoDB (mongodb.org) and follows same philosophy.
- - Supported queries:
-- Simple matching of String OR Number OR Array value:
+ EJDB queries inspired by MongoDB (mongodb.org) and follows same philosophy.
+
+ Queries and query hints can be constructed by Q query/json builder.
+- Supported queries:
+- Simple matching of String OR Number OR Array value:
- {'fpath' : 'val', ...}
- $not Negate operation.
- {'fpath' : {'$not' : val}} //Field not equal to val
@@ -630,21 +760,22 @@
- NOTE: It is better to execute update queries with $onlycount=true
hint flag
+ NOTE: It is better to execute update queries with $onlycount=true
hint flag
or use the special `update()` method to avoid unnecessarily data fetching.
- NOTE: Negate operations: $not and $nin not using indexes
+
+ NOTE: Negate operations: $not and $nin not using indexes
so they can be slow in comparison to other matching operations.
- NOTE: Only one index can be used in search query operation.
- NOTE: If callback is not provided this function will be synchronous.
- QUERY HINTS (specified by hints
argument):
+ NOTE: Only one index can be used in search query operation.
+
+ NOTE: If callback is not provided this function will be synchronous.
+
+ QUERY HINTS specified by calling Q:Skip Q:Max, Q:OrderBy, Q:Fields:
- $max Maximum number in the result set
- $skip Number of skipped results in the result set
- $orderby Sorting order of query fields.
-- $onlycount true|false If `true` only count of matching records will be returned
- without placing records in result set.
- $fields Set subset of fetched fields.
If field presented in $orderby clause it will be forced to include in resulting records.
Example:
@@ -700,11 +831,33 @@ end
Parameters:
+ Returns:
+
+ -
+ RS
+ result set, it will be
nil
if c
flag presented in the control flags
+ -
+ number
+ Count of matched/updated records
+ -
+ optional string
+ Query execution log if
l
flag presented in the control flags
+
see also:
@@ -712,25 +865,188 @@ end
Q
+ Usage:
+
+ db:find("mycoll", Q("foo", "bar")) => {"foo" : "bar"}
+ db:find("mycoll", Q("foo", "bar"):Max(10)) -- Limit results up to 10 records
+ db:find("parrots2", Q("likes", "toys"):OrderBy("name asc", "age desc"))
+ db:find("parrots2", Q():F("likes"):Eq("toys"):OrderBy({ name = 1 }, { age = -1 }))
+
-
- Q:Eq (val)
+
+ DB:findOne (cname, q)
+ Same as DB:find but retrieves only first matching JSON object.
+
+ Parameters:
+
+ - cname
+ string
+ Name of collection
+ - q
+ Q
+ JSON query object
+
+
+ Returns:
+
+ -
+ table
+ Lua table constructed from matched BSON record or
nil
of record not found
+ -
+ number
+ Count of matched/updated records
+ -
+ optional string
+ Query execution log if
l
flag presented in the control flags
+
+
-Field eq restriction.
-{fname : fval}
-
+
+
+
+ DB:update (cname, q)
+
+
+ Convenient method to execute update queries.
+
Parameters:
- - val
+
- cname
+ string
+ Name of collection
+ - q
+ Q
+ JSON query object
+
+
+ Returns:
+
+ -
+ number
+ Count of matched/updated records
+ -
+ optional string
+ Query execution log if
l
flag presented in the control flags
+
-
+
+
+
+
+
+ DB:count (cname, q)
+
+
+ Convenient count(*)
operation.
+
+ Parameters:
+
+ - cname
+ string
+ Name of collection
+ - q
+ Q
+ JSON query object
+
+
+ Returns:
+
+ -
+ number
+ Count of matched/updated records
+ -
+ optional string
+ Query execution log if
l
flag presented in the control flags
+
+
+
+
+
+
+
+
+ RS:object (i)
+
+
+ Returns result set lua table object at specified position i
+
+ Parameters:
+
+ - i
+ number
+ Position of record in the result set
+
+
+ Returns:
+
+
+ table
+ Resulting lua object constructed from BSON record.
+
+
+
+
+
+
+
+
+ RS:field (i, name)
+
+
+ Returns field value of lua object at specified position i
+
+ Parameters:
+
+ - i
+ number
+ Position of record in the result set
+ - name
+ string
+ JSON field name
+
+
+ Returns:
+
+
+ Value of field
+
+
+
+
+
+
+
+
+ RS.__len ()
+
+
+ Length of result set.
+
+
+
+
+
+
+
+
+
+ Q:F (fname)
+
+
+ Set current field for the next operation during query building.
+
+ Parameters:
+
+ - fname
+ string
+ JSON field path
@@ -738,23 +1054,49 @@ end
Usage:
Q:F("name"):Eq("andy"):F("age"):Gt(30) => {"name" : "andy", "age" : {"$gt" : 30}}
-
- Q:ElemMatch (val)
+
+ Q:Eq (val)
+ Field equality restriction.
+ All usage samples represent same thing: {"fname" : fval}
-Element match construction.
-- $elemMatch The $elemMatch operator matches more than one component within an array element.
- - { array: { $elemMatch: { value1 : 1, value2 : { $gt: 1 } } } }
- Restriction: only one $elemMatch allowed in context of one array field.
-
+ Parameters:
+
+ - val
+ any BSON value as Lua object including Q instances.
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+
+ Usage:
+
+ Q():F("fname"):Eq(fval)
+ Q("fname", fval)
+ Q():F("fname", fval)
+
+
+
+
+ Q:ElemMatch (val)
+
+
+ Element match construction.
+ - $elemMatch The $elemMatch operator matches more than one component within an array element.
+ - { array: { $elemMatch: { value1 : 1, value2 : { $gt: 1 } } } }
+ Restriction: only one $elemMatch allowed in context of one array field.
Parameters:
@@ -764,6 +1106,11 @@ end
+ Returns:
+
+
+ Self Q
+
@@ -784,6 +1131,11 @@ end
+ Returns:
+
+
+ Self Q
+
@@ -803,11 +1155,17 @@ end
Parameters:
+ Returns:
+
+
+ Self Q
+
@@ -827,11 +1185,17 @@ end
Parameters:
+ Returns:
+
+
+ Self Q
+
@@ -851,11 +1215,17 @@ end
Parameters:
+ Returns:
+
+
+ Self Q
+
@@ -875,11 +1245,17 @@ end
Parameters:
+ Returns:
+
+
+ Self Q
+
@@ -889,32 +1265,699 @@ end
-
- Tables
-
-
-
- Q
+
+ Q:Icase (val)
-
- Query/JSON builder is used to create EJDB queries or JSON objects with
- preserverd keys order (Unlike lua tables).
+ Case insensitive string matching
- Examples:
+
Parameters:
+
+ Returns:
+
- see also:
-
+ Self Q
+
+
+
+
+ Usage:
+
+ Q():F("name"):Icase("aNdY") => {"name" : {"$icase" : "aNdY"}}
+ Q():F("name"):Icase({[$in] = {"aNdY", "AnTon"}}) => {"name" : {"$icase" : {"$in" : ["aNdY", "AnTon"]}}}
+
+
+
+
+
+ Q:Begin (val)
+
+
+ String starts with prefix
+
+ Parameters:
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+
+ Usage:
+ Q():F("fpath"):Begin("prefix") => {"fpath" : {"$begin" : "prefix"}}
+
+
+
+
+
+ Q:In (val)
+
+
+ Field value matched any value of specified in val
table.
+
+ Parameters:
+
+ - val
+ table
+ Not empty lua array of values.
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+
+ Usage:
+ Q():F("fpath"):In({"val1", "val2", "val3"}) => {"fpath" : {"$in" : ["val1", "val2", "val3"]}}
+
+
+
+
+
+ Q:NotIn (val)
+
+
+ Negation of Q:In
+
+ Parameters:
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+ see also:
+
+
+
+
+
+
+ Q:Bt (n1, n2)
+
+
+ Between for number types
+
+ Parameters:
+
+ - n1
+ number
+
+
+
+ - n2
+ number
+
+
+
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+
+ Usage:
+ Q():F("age"):Bt(10, 20) => {"age" : {"$bt" : [10, 20]}}
+
+
+
+
+
+ Q:StrAnd (val)
+
+
+ String tokens(or string array vals) matches all tokens in specified val
array.
+
+ Parameters:
+
+ - val
+ table
+ Array of tokens to match.
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+
+ Usage:
+ Q():F("description"):StrAnd({"foo", "bar"}) -- descripton contains all tokens: 'foo' and 'bar'
+
+
+
+
+
+ Q:StrOr (val)
+
+
+ String tokens(or string array vals) matches any token in specified array.
+
+ Parameters:
+
+ - val
+ table
+ Array of tokens to match.
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+
+ Usage:
+ Q():F("description"):StrOr({"foo", "bar"}) -- descripton contains all tokens: 'foo' or 'bar'
+
+
+
+
+
+ Q:Inc (val)
+
+
+ Increment current field. Only number types are supported.
+
+ Parameters:
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+ see also:
+
+
+ Usage:
+ Q():F("count"):Inc(1):F("age"):Inc(-20) => {"$inc" : {"count" : 1, "age" : -20}}
+
+
+
+
+
+ Q:Set (val)
+
+
+ Set fields to values.
+
+ Parameters:
+
+ - val
+ table or Q
+ Table of fields to set
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+
+ Usage:
+ Q():Set({age = 20, count = 1}) => {"$set" : {"age" : 20, count : 1}}
+
+
+
+
+
+ Q:Upsert (val)
+
+
+ Atomic upsert.
+ If matching records are found it will be $set
operation,
+ otherwise new record will be inserted with fields specified by val
table.
+
+ Parameters:
+
+ - val
+ table or Q
+ Table of fields to set/insert
+ Insert {"foo" : "bar"} if this object does not exists:
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+
+ Usage:
+
+ Q("foo","bar"):Upsert(Q("foo", "bar")) => {"foo" : "bar", "$upsert" : {"foo" : "bar"}}
+ Q("foo","bar"):Upsert({foo ="bar"}) => {"foo" : "bar", "$upsert" : {"foo" : "bar"}}
+
+
+
+
+
+ Q:AddToSet (val)
+
+
+ Atomically adds val
to the array field
only if val
not in the array already.
+ If containing array is missing it will be created.
+
+ Parameters:
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+
+ Usage:
+ Q():F("tags"):AddToSet("red") => {"$addToSet" : {"tags" : "red"}}
+
+
+
+
+
+ Q:AddToSetAll (val)
+
+
+ Atomically performs set union
with values in val
for specified array field.
+
+ Parameters:
+
+ - val
+ table
+ Array of values to add
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+ see also:
+
+
+ Usage:
+ Q():F("tags"):AddToSetAll({"red", "green"})
+
+
+
+
+
+ Q:Pull (val)
+
+
+ Atomically removes all occurrences of val
from field, if field is an array.
+
+ Parameters:
+
+ - val
+ Value to remove
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+ see also:
+
+
+ Usage:
+ Q():F("tags"):Pull("red") => {"$pull" : {"tags" : "red"}}
+
+
+
+
+
+ Q:PullAll (val)
+
+
+ Atomically performs set substraction
of values in val
for specified array field.
+
+ Parameters:
+
+ - val
+ table
+ Array of values to remove from array field
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+ see also:
+
+
+ Usage:
+ Q():F("tags"):PullAll({"red", "green"}) => {"$pullAll" : {"tags" : ["red", "green"]}}
+
+
+
+
+
+ Q:DropAll ()
+
+
+ In-place record removal operation.
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+
+ Usage:
+ db:update(Q():F("name", "andy"):DropAll()) -- Removes all records with name eq 'andy'
+
+
+
+
+
+ Q:Join (cname, fpath)
+
+
+ Make collection join
+ for select queries.
+
+ Parameters:
+
+ - cname
+ string
+ Name for joined collection
+ - fpath
+ string
+ Name of field with BSON OIDs of joined objects
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+
+
+
+
+
+ Q:Or (...)
+
+
+ Add OR joined query restrictions.
+
+ Parameters:
+
+ - ...
+ table or Q
+ List of OR joined restrictions
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+
+ Usage:
+ Q():Or(Q("name", "anton"), Q("name", "andy"))
+ Find records with "name" field eq "anton" or "andy"
+
+
+
+
+
+ Q:Skip (val)
+
+
+ Sets number of skipped records in the result set.
+
+ Parameters:
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+
+
+
+
+
+ Q:Max (val)
+
+
+ Sets max number of records in the result set.
+
+ Parameters:
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+
+
+
+
+
+ Q:OrderBy (...)
+
+
+ Set sorting rules for query results.
+ tparam table|string
+
+ Parameters:
+
+
+
+
+
+ Usage:
+
+ Q:OrderBy("name asc", "age desc") => ORDER BY name ASC, age dESC
+ Q:OrderBy({name = 1}, {age = -1}) => ORDER BY name ASC, age dESC
+
+
+
+
+
+ Q:Fields (...)
+
+
+ Sets fields to be included in resulting objects.
+ If field presented in $orderby clause it will be forced to include in resulting records.
+
+ Parameters:
+
+ - ...
+ string
+ Fields to be included in fetched objects.
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+
+ Usage:
+ Q:Fields("name", "age")
+
+
+
+
+
+ Q:NotFields (...)
+
+
+ Sets fields to be excluded from resulting objects.
+
+ Parameters:
+
+ - ...
+ string
+ Fields to be excluded from fetched objects.
+
+
+ Returns:
+
+
+ Self Q
+
+
+
+
+ Usage:
+ Q:NotFields("name", "description")
+
+
+
+
+ Tables
+
+ -
+
+ Q
+
+ -
+ Query/JSON builder is used to create EJDB queries or JSON objects with
+ preserverd keys order (Unlike lua tables).
+ Q can be used to construct BSON objects as well as queries.
+
+
Examples:
+
+
+
+
+
see also:
+
Usage:
@@ -938,6 +1981,59 @@ end
+ -
+
+ RS
+
+ -
+
+
Result set cursor object.
+ Usage:
+#res - length of result set
+res[i] - BSON representations of object as lua string
+res:object(i) - Lua table constructed from BSON data
+res:field(i, <field name>) - Lua value of fetched BSON object
+res() - Creates iterator for pairs (obj, idx)
+ where obj - Lua table constructed from BSON data
+ idx - Index of fetched object in the result set
+
+
+ Examples:
+for i = 1, #res do
+ local ob = res:object(i)
+ ...
+end
+
+
+ OR
+
+for i = 1, #res do
+ res:field(i, "json field name")
+ ...
+end
+
+
+ OR
+
+for vobj, idx in res() do
+ -- vobj is a lua table representation of fetched json object
+ vobj["json field name"]
+ ...
+end
+
+
+
+
+
+
+ see also:
+
+
+
+
diff --git a/luaejdb/ejdb.lua b/luaejdb/ejdb.lua
index b294c99..25be60f 100644
--- a/luaejdb/ejdb.lua
+++ b/luaejdb/ejdb.lua
@@ -260,16 +260,17 @@ function B:_init(fname, ...)
return self
end
-function B:_checkop()
+function B:_checkOp()
assert(type(self._field) == "string")
end
-function B:_setop(op, val, ...)
- self:_checkop()
+function B:_setOp(op, val, ...)
+ self:_checkOp()
local types, replace = ...
local ttypes = type(types)
if (ttypes == "string") then
- assert(type(val) == types, "Invalid query argument field: " .. self._field .. " val: " .. inspect(val))
+ assert(type(val) == types, "Invalid query argument field: " .. self._field ..
+ " It should have '" .. types .. "' type," .. " got: " .. inspect(val))
elseif (ttypes == "function") then
assert(types(val), "Invalid query argument field: " .. self._field .. " val: " .. inspect(val))
elseif (ttypes == "table") then
@@ -296,12 +297,33 @@ function B:_setop(op, val, ...)
elseif replace then
for i = 2, #olist do olist[i] = nil end
end
- if (op == nil) then
+ if op == nil then
table.insert(olist, setmetatable({ val }, mtBVal))
else
- table.insert(olist, { op, val })
+ local found = false
+ for i = 2, #olist do
+ if olist[i][1] == op then -- found previous added op
+ found = true
+ olist[i][2] = val -- replace old value
+ break
+ end
+ end
+ if not found then
+ table.insert(olist, { op, val })
+ end
end
self._bson = nil
+ return self
+end
+
+function B:_invertOp(op, val, ...)
+ local pf = self._field;
+ assert(type(op) == "string", "Operation must be a string")
+ assert(type(pf) == "string", "You should set field before by Q:F('fname')")
+ self._field = op
+ self:_setOp(pf, val, ...)
+ self._field = pf
+ return self
end
function B:_toOpVal(op, val)
@@ -317,12 +339,13 @@ function B:_hintOp(op, val, ...)
self._hints = B()
end
self._hints:_rootOp(op, val, ...)
+ return self
end
function B:_rootOp(name, val, ...)
local types = ...
self:F(name)
- self:_setop(nil, val, types, true)
+ self:_setOp(nil, val, types, true)
self:F(nil)
return self
end
@@ -340,55 +363,61 @@ end
-- Generic key=value
function B:KV(key, val)
self:F(key);
- self:_setop(nil, val, nil, true)
+ self:_setOp(nil, val, nil, true)
return self
end
-function B:Eq(val) self:_setop(nil, val, nil, true) return self end
+function B:Eq(val) return self:_setOp(nil, val, nil, true) end
-function B:ElemMatch(val) self:_setop("$elemMatch", val) return self end
+function B:ElemMatch(val) return self:_setOp("$elemMatch", val) end
-function B:Not(val) self:_setop("$not", val) return self end
+function B:Not(val) return self:_setOp("$not", val) end
-function B:Gt(val) self:_setop("$gt", val) return self end
+function B:Gt(val) return self:_setOp("$gt", val, "number") end
-function B:Gte(val) self:_setop("$gte", val) return self end
+function B:Gte(val) return self:_setOp("$gte", val, "number") end
-function B:Lt(val) self:_setop("$lt", val) return self end
+function B:Lt(val) return self:_setOp("$lt", val, "number") end
-function B:Lte(val) self:_setop("$lte", val) return self end
+function B:Lte(val) return self:_setOp("$lte", val, "number") end
-function B:Icase(val) self:_setop("$icase", val) return self end
+function B:Icase(val) return self:_setOp("$icase", val) end
-function B:Begin(val) self:_setop("$begin", val) return self end
+function B:Begin(val) return self:_setOp("$begin", val, "string") end
-function B:In(val) self:_setop("$in", val) return self end
+function B:In(val) return self:_setOp("$in", val, "table") end
-function B:NotIn(val) self:_setop("$nin", val) return self end
+function B:NotIn(val) return self:_setOp("$nin", val, "table") end
-function B:Bt(val) self:_setop("$bt", val) return self end
+function B:Bt(n1, n2) return self:_setOp("$bt", { n1, n2 }) end
-function B:StrAnd(val) self:_setop("$strand", val) return self end
+function B:StrAnd(val) return self:_setOp("$strand", val, "table") end
-function B:StrOr(val) self:_setop("$strand", val) return self end
+function B:StrOr(val) return self:_setOp("$stror", val, "table") end
-function B:Inc(val) self:_setop("$inc", val) return self end
+function B:Inc(val) return self:_invertOp("$inc", val, "number") end
-function B:Set(val) return self:_rootOp("$set", val) end
+function B:Set(val) return self:_rootOp("$set", val, "table") end
-function B:AddToSet(val) return self:_rootOp("$addToSet", val) end
+function B:AddToSet(val) return self:_invertOp("$addToSet", val) end
-function B:AddToSetAll(val) return self:_rootOp("$addToSetAll", val) end
+function B:AddToSetAll(val) return self:_invertOp("$addToSetAll", val, "table") end
-function B:Pull(val) return self:_rootOp("$pull", val) end
+function B:Pull(val) return self:_invertOp("$pull", val) end
-function B:PullAll(val) return self:_rootOp("$pullAll", val) end
+function B:PullAll(val) return self:_invertOp("$pullAll", val, "table") end
-function B:Upsert(val) return self:_rootOp("$upsert", val) end
+function B:Upsert(val) return self:_rootOp("$upsert", val, "table") end
function B:DropAll() return self:_rootOp("$dropall", true) end
-function B:Do(val) return self:_rootOp("$do", val) end
+function B:Do(val) return self:_rootOp("$do", val, "table") end
+
+function B:Join(cname, fpath)
+ assert(type(cname) == "string", "Type of #1 arg must be string")
+ assert(type(fpath) == "string", "Type of #2 arg must be string")
+ return self:_rootOp("$do", { [fpath] = { ["join"] = cname } })
+end
function B:Or(...)
self._or = self._or or {}
diff --git a/luaejdb/ejdb.luadoc b/luaejdb/ejdb.luadoc
index 2246f83..d0e3022 100644
--- a/luaejdb/ejdb.luadoc
+++ b/luaejdb/ejdb.luadoc
@@ -7,6 +7,7 @@ local ejdb = {}
--- Query/JSON builder is used to create EJDB queries or JSON objects with
-- preserverd keys order (Unlike lua tables).
+-- @{Q} **can be used to construct BSON objects as well as queries.**
-- @class table
-- @name Q
--
@@ -15,6 +16,7 @@ local ejdb = {}
-- @usage Q("likes", "toys"):OrderBy("name asc", "age desc")
-- @usage Q("name", "Andy"):F("_id"):Eq("510f7fa91ad6270a00000000"):F("age"):Gt(20):Lt(40):F("score"):In({ 11, 22.12333, 1362835380447, db.toNull() }):Max(232)
-- @usage Q():Or(Q("foo", "bar"), Q("foo", "bar6")):OrderBy({ foo = 1 })
+-- @see Q:F
-- @see Q:Eq
-- @see Q:ElemMatch
-- @see Q:Not
@@ -38,7 +40,7 @@ local ejdb = {}
-- @see Q:Upsert
-- @see Q:Upsert
-- @see Q:DropAll
--- @see Q:Do
+-- @see Q:Join
-- @see Q:Or
-- @see Q:Skip
-- @see Q:Skip
@@ -56,10 +58,47 @@ local Q = {}
-- @name DB
local DB = {}
+---
+-- Result set cursor object.
+-- @class table
+-- @name RS
+-- Usage:
+-- #res - length of result set
+-- res[i] - BSON representations of object as lua string
+-- res:object(i) - Lua table constructed from BSON data
+-- res:field(i, ) - Lua value of fetched BSON object
+-- res() - Creates iterator for pairs (obj, idx)
+-- where obj - Lua table constructed from BSON data
+-- idx - Index of fetched object in the result set
+--
+-- Examples:
+-- for i = 1, #res do
+-- local ob = res:object(i)
+-- ...
+-- end
+--
+-- OR
+--
+-- for i = 1, #res do
+-- res:field(i, "json field name")
+-- ...
+-- end
+--
+-- OR
+--
+-- for vobj, idx in res() do
+-- -- vobj is a lua table representation of fetched json object
+-- vobj["json field name"]
+-- ...
+-- end
+-- @see RS:object
+-- @see RS:field
+local RS = {}
+
--- Opens EJDB database.
-- @usage local db = ejdb.open("foodb", "wrc")
--- @param path {String} Database main file
--- @param mode {String?} Database open mode flags:
+-- @tparam string path Database main file
+-- @tparam ?string mode Database open mode flags:
-- `w`
Open as a writer
-- `r`
Open as a reader
-- `c`
Create db if it not exists
@@ -74,7 +113,7 @@ function ejdb.open(path, mode) end
function ejdb.close() end
--- Converts string OID into BSON oid table.
--- @param val {String} 24 hex chars BSON_OID
+-- @tparam string val 24 hex chars BSON_OID
function ejdb.toOID(val) end
--- Converts os.time table (or number of seconds since epoch) into BSON_DATE.
@@ -87,8 +126,8 @@ function ejdb.toDate(val) end
function ejdb.toDateNow() end
--- Builds BSON_REGEX value
--- @param re {String} Regular expression
--- @param opts {String} Regular expression flags
+-- @tparam string re Regular expression
+-- @tparam ?string opts Regular expression flags
-- @return BSON_REGEX table value
function ejdb.toRegexp(re, opts) end
@@ -137,8 +176,8 @@ function DB.toUndefined() end
-- Each persistent object has unique identifier (OID) placed in the `_id` property.
-- If a saved object does not have `_id` it will be autogenerated.
-- To identify and update object it should contains `_id` property.
--- @param cname {String} Name of collection.
--- @param obj Lua table or Q represents JSON object.
+-- @tparam string cname Name of collection.
+-- @tparam table|Q obj represents JSON object.
-- @param ... If last argument is True a saved object will be merged with who's
-- already persisted in db.
-- @usage dQ:save("parrots2", {foo = "bar"})
@@ -148,7 +187,9 @@ function DB:save(cname, obj, ...) end
--- Execute query on collection.
--
-- EJDB queries inspired by MongoDB (mongodb.org) and follows same philosophy.
--- - Supported queries:
+--
+-- Queries and query hints can be constructed by @{Q} query/json builder.
+-- - Supported queries:
-- - Simple matching of String OR Number OR Array value:
-- - {'fpath' : 'val', ...}
-- - $not Negate operation.
@@ -206,19 +247,20 @@ function DB:save(cname, obj, ...) end
-- Where 'fpath' value points to object's OIDs from 'collectionname'. Its value
-- can be OID, string representation of OID or array of this pointers.
--
--- NOTE: It is better to execute update queries with `$onlycount=true` hint flag
+-- **NOTE:** It is better to execute update queries with `$onlycount=true` hint flag
-- or use the special `update()` method to avoid unnecessarily data fetching.
--- NOTE: Negate operations: $not and $nin not using indexes
+--
+-- **NOTE:** Negate operations: $not and $nin not using indexes
-- so they can be slow in comparison to other matching operations.
--- NOTE: Only one index can be used in search query operation.
--- NOTE: If callback is not provided this function will be synchronous.
--
--- QUERY HINTS (specified by `hints` argument):
+-- **NOTE:** Only one index can be used in search query operation.
+--
+-- **NOTE:** If callback is not provided this function will be synchronous.
+--
+-- **QUERY HINTS** specified by calling @{Q:Skip} @{Q:Max}, @{Q:OrderBy}, @{Q:Fields}:
-- - $max Maximum number in the result set
-- - $skip Number of skipped results in the result set
-- - $orderby Sorting order of query fields.
--- - $onlycount true|false If `true` only count of matching records will be returned
--- without placing records in result set.
-- - $fields Set subset of fetched fields.
-- If field presented in $orderby clause it will be forced to include in resulting records.
-- Example:
@@ -264,88 +306,254 @@ function DB:save(cname, obj, ...) end
-- end
--
--
--- @param cname {String} Name of collection
--- @param q {table|Q} JSON query object
+-- @tparam string cname Name of collection
+-- @tparam Q q JSON query object
+-- @string flags Query control flags:
+-- `c`: only count of matching records will be returned without placing records in result set.
+-- `l`: return query execution log
+-- @treturn RS result set, it will be `nil` if `c` flag presented in the control `flags`
+-- @treturn number Count of matched/updated records
+-- @treturn ?string Query execution log if `l` flag presented in the control `flags`
+-- @usage db:find("mycoll", Q("foo", "bar")) => {"foo" : "bar"}
+-- @usage db:find("mycoll", Q("foo", "bar"):Max(10)) -- Limit results up to 10 records
+-- @usage db:find("parrots2", Q("likes", "toys"):OrderBy("name asc", "age desc"))
+-- @usage db:find("parrots2", Q():F("likes"):Eq("toys"):OrderBy({ name = 1 }, { age = -1 }))
-- @see Q
--
-function DB:find(cname, q, ...) end
+function DB:find(cname, q, flags) end
+
+--- Same as @{DB:find} but retrieves only first matching JSON object.
+-- @tparam string cname Name of collection
+-- @tparam Q q JSON query object
+-- @treturn table Lua table constructed from matched BSON record or `nil` of record not found
+-- @treturn number Count of matched/updated records
+-- @treturn ?string Query execution log if `l` flag presented in the control `flags`
+
+function DB:findOne(cname, q, ...) end
+
+--- Convenient method to execute update queries.
+-- @tparam string cname Name of collection
+-- @tparam Q q JSON query object
+-- @treturn number Count of matched/updated records
+-- @treturn ?string Query execution log if `l` flag presented in the control `flags`
+
+function DB:update(cname, q, ...) end
+
+--- Convenient `count(*)` operation.
+-- @tparam string cname Name of collection
+-- @tparam Q q JSON query object
+-- @treturn number Count of matched/updated records
+-- @treturn ?string Query execution log if `l` flag presented in the control `flags`
+
+function DB:count(cname, q, ...) end
+
+--- Returns result set lua table object at specified position `i`
+-- @tparam number i Position of record in the result set
+-- @treturn table Resulting lua object constructed from BSON record.
+function RS:object(i) end
---- Field eq restriction.
--- {fname : fval}
--- @usage Q():F("fname"):Eq()
--- @usage Q("fname", )
+--- Returns field value of lua object at specified position `i`
+-- @tparam number i Position of record in the result set
+-- @tparam string name JSON field name
+-- @return Value of field
+function RS:field(i, name) end
+
+--- Length of result set.
+function RS.__len() end
+
+
+--- Set current field for the next operation during query building.
+-- @string fname JSON field path
+-- @usage Q:F("name"):Eq("andy"):F("age"):Gt(30) => {"name" : "andy", "age" : {"$gt" : 30}}
+function Q:F(fname) end
+
+--- Field equality restriction.
+-- @param val any BSON value as Lua object including @{Q} instances.
+-- All usage samples represent same thing: `{"fname" : fval}`
+-- @usage Q():F("fname"):Eq(fval)
+-- @usage Q("fname", fval)
+-- @usage Q():F("fname", fval)
+-- @return Self @{Q}
function Q:Eq(val) self:_setop(nil, val, nil, true) end
--- Element match construction.
--- - $elemMatch The $elemMatch operator matches more than one component within an array element.
--- - { array: { $elemMatch: { value1 : 1, value2 : { $gt: 1 } } } }
--- Restriction: only one $elemMatch allowed in context of one array field.
+-- - $elemMatch The $elemMatch operator matches more than one component within an array element.
+-- - { array: { $elemMatch: { value1 : 1, value2 : { $gt: 1 } } } }
+-- Restriction: only one $elemMatch allowed in context of one array field.
+-- @return Self @{Q}
function Q:ElemMatch(val) end
--- The $not negatiation for `val` block
-- @usage Q():Not(Q("foo", "bar")) => {"$not" : {"foo" : "bar"}}
+-- @return Self @{Q}
function Q:Not(val) end
--- Greater than (val > arg)
+-- @number val
-- @usage Q():F("age"):Gt(29) => {"age" : {"$gt" : 29}}
+-- @return Self @{Q}
function Q:Gt(val) end
--- Greater than or equal (val >= arg)
+-- @number val
-- @usage Q():F("age"):Gt(29) => {"age" : {"$gte" : 29}}
+-- @return Self @{Q}
function Q:Gte(val) end
--- Lesser than (val < arg)
+-- @number val
-- @usage Q():F("age"):Lt(29) => {"age" : {"$lt" : 29}}
+-- @return Self @{Q}
function Q:Lt(val) end
--- Lesser than or equal (val <= arg)
+-- @number val
-- @usage Q():F("age"):Lt(29) => {"age" : {"$lte" : 29}}
+-- @return Self @{Q}
function Q:Lte(val) end
+--- Case insensitive string matching
+-- @tparam string|table|Q val
+-- @usage Q():F("name"):Icase("aNdY") => {"name" : {"$icase" : "aNdY"}}
+-- @usage Q():F("name"):Icase({[$in] = {"aNdY", "AnTon"}}) => {"name" : {"$icase" : {"$in" : ["aNdY", "AnTon"]}}}
+-- @return Self @{Q}
function Q:Icase(val) end
+--- String starts with prefix
+-- @string val
+-- @usage Q():F("fpath"):Begin("prefix") => {"fpath" : {"$begin" : "prefix"}}
+-- @return Self @{Q}
function Q:Begin(val) end
+--- Field value matched any value of specified in `val` table.
+-- @tparam table val Not empty lua array of values.
+-- @usage Q():F("fpath"):In({"val1", "val2", "val3"}) => {"fpath" : {"$in" : ["val1", "val2", "val3"]}}
+-- @return Self @{Q}
function Q:In(val) end
+--- Negation of @{Q:In}
+-- @see Q:In
+-- @return Self @{Q}
function Q:NotIn(val) end
-function Q:Bt(val) end
-
-function Q:StrAnd(val) end
-
+--- Between for number types
+-- @number n1
+-- @number n2
+-- @usage Q():F("age"):Bt(10, 20) => {"age" : {"$bt" : [10, 20]}}
+-- @return Self @{Q}
+function Q:Bt(n1, n2) end
+
+--- String tokens(or string array vals) matches **all** tokens in specified `val` array.
+-- @tparam table val Array of tokens to match.
+-- @usage Q():F("description"):StrAnd({"foo", "bar"}) -- descripton contains all tokens: 'foo' and 'bar'
+-- @return Self @{Q}
+function Q:StrAnd(val) end
+
+--- String tokens(or string array vals) matches **any** token in specified array.
+-- @tparam table val Array of tokens to match.
+-- @usage Q():F("description"):StrOr({"foo", "bar"}) -- descripton contains all tokens: 'foo' or 'bar'
+-- @return Self @{Q}
function Q:StrOr(val) end
+--- Increment current field. Only number types are supported.
+-- @number val
+-- @usage Q():F("count"):Inc(1):F("age"):Inc(-20) => {"$inc" : {"count" : 1, "age" : -20}}
+-- @return Self @{Q}
+-- @see Q:F
function Q:Inc(val) end
+--- Set fields to values.
+-- @tparam table|Q val Table of fields to set
+-- @usage Q():Set({age = 20, count = 1}) => {"$set" : {"age" : 20, count : 1}}
+-- @return Self @{Q}
function Q:Set(val) end
-function Q:AddToSet(val) end
+--- Atomic upsert.
+-- If matching records are found it will be `$set` operation,
+-- otherwise new record will be inserted with fields specified by `val` table.
+-- @tparam table|Q val Table of fields to set/insert
+-- Insert {"foo" : "bar"} if this object does not exists:
+-- @usage Q("foo","bar"):Upsert(Q("foo", "bar")) => {"foo" : "bar", "$upsert" : {"foo" : "bar"}}
+-- @usage Q("foo","bar"):Upsert({foo ="bar"}) => {"foo" : "bar", "$upsert" : {"foo" : "bar"}}
+-- @return Self @{Q}
+function Q:Upsert(val) end
-function Q:AddToSetAll(val) end
+--- Atomically adds `val` to the `array field` only if `val` not in the array already.
+-- If containing array is missing it will be created.
+-- @param val Value to add
+-- @usage Q():F("tags"):AddToSet("red") => {"$addToSet" : {"tags" : "red"}}
+-- @return Self @{Q}
+function Q:AddToSet(val) end
+--- Atomically performs `set union` with values in `val` for specified array field.
+-- @tparam table val Array of values to add
+-- @usage Q():F("tags"):AddToSetAll({"red", "green"})
+-- @see Q:F
+-- @return Self @{Q}
+function Q:AddToSetAll(val) end
+
+--- Atomically removes all occurrences of `val` from field, if field is an array.
+-- @param val Value to remove
+-- @usage Q():F("tags"):Pull("red") => {"$pull" : {"tags" : "red"}}
+-- @see Q:F
+-- @return Self @{Q}
function Q:Pull(val) end
+--- Atomically performs `set substraction` of values in `val` for specified array field.
+-- @tparam table val Array of values to remove from array field
+-- @usage Q():F("tags"):PullAll({"red", "green"}) => {"$pullAll" : {"tags" : ["red", "green"]}}
+-- @see Q:F
+-- @return Self @{Q}
function Q:PullAll(val) end
-function Q:Upsert(val) end
-
+--- In-place record removal operation.
+-- @usage db:update(Q():F("name", "andy"):DropAll()) -- Removes all records with name eq 'andy'
+-- @return Self @{Q}
function Q:DropAll() end
-function Q:Do(val) end
-
+--- Make collection join
+-- for select queries.
+-- @string cname Name for joined collection
+-- @string fpath Name of field with BSON OIDs of joined objects
+-- @return Self @{Q}
+function Q:Join(cname, fpath) end
+
+--- Add *OR* joined query restrictions.
+-- @tparam table|Q ... List of OR joined restrictions
+-- @usage Q():Or(Q("name", "anton"), Q("name", "andy"))
+-- Find records with "name" field eq "anton" or "andy"
+-- @return Self @{Q}
function Q:Or(...) end
+--- Sets number of skipped records in the result set.
+-- @number val
+-- @return Self @{Q}
function Q:Skip(val) end
+--- Sets max number of records in the result set.
+-- @number val
+-- @return Self @{Q}
function Q:Max(val) end
+--- Set sorting rules for query results.
+-- tparam table|string
+-- @usage Q:OrderBy("name asc", "age desc") => ORDER BY name ASC, age dESC
+-- @usage Q:OrderBy({name = 1}, {age = -1}) => ORDER BY name ASC, age dESC
function Q:OrderBy(...) end
+--- Sets fields to be included in resulting objects.
+-- If field presented in $orderby clause it will be forced to include in resulting records.
+-- @string ... Fields to be included in fetched objects.
+-- @usage Q:Fields("name", "age")
+-- @return Self @{Q}
function Q:Fields(...) end
+--- Sets fields to be excluded from resulting objects.
+-- @string ... Fields to be excluded from fetched objects.
+-- @usage Q:NotFields("name", "description")
+-- @return Self @{Q}
function Q:NotFields(...) end
diff --git a/luaejdb/test/t1.lua b/luaejdb/test/t1.lua
index 14369c6..59d2dcb 100644
--- a/luaejdb/test/t1.lua
+++ b/luaejdb/test/t1.lua
@@ -191,18 +191,23 @@ assert(log:find("MAIN IDX: 'NONE'"))
assert(db:getTransactionStatus("mycoll") == false)
db:beginTransaction("mycoll")
assert(db:getTransactionStatus("mycoll") == true)
-db:save("mycoll", {name=1})
+db:save("mycoll", { name = 1 })
assert(db:findOne("mycoll", Q("name", 1)));
db:rollbackTransaction("mycoll")
assert(db:getTransactionStatus("mycoll") == false)
assert(db:findOne("mycoll", Q("name", 1)) == nil);
-assert(db:update("ecoll", Q("k1", "v1"):Upsert({k1="v1"})) == 1)
+assert(db:update("ecoll", Q("k1", "v1"):Upsert({ k1 = "v1", k2 = 1, k3 = 2 })) == 1)
assert(db:update("ecoll", Q("k1", "v1"):Upsert(Q("k1", "v2"))) == 1)
assert(db:count("ecoll", Q("k1", "v2")) == 1)
+-- test $inc
+assert(db:update("ecoll", Q("k1", "v2"):F("k2"):Inc(1):F("k3"):Inc(-2)) == 1);
+assert(db:count("ecoll", Q():F("k2", 2):F("k3", 0)) == 1)
+
db:ensureStringIndex("mycoll", "foo")
+print(ejdb.print_bson(Q():F("tags"):AddToSetAll({"red", "green"}):toBSON()))
--print(inspect(db:getDBMeta()))
db:dropCollection("ecoll", true);
diff --git a/node/ejdb.js b/node/ejdb.js
index c58f935..31d4b3c 100644
--- a/node/ejdb.js
+++ b/node/ejdb.js
@@ -333,7 +333,7 @@ function parseQueryArgs(args) {
* - {.., '$inc' : {'field1' : number, ..., 'field1' : number}
* $dropall In-place record removal operation.
* - {.., '$dropall' : true}
- * $addToSet Atomically adds value to the array only if its not in the array already.
+ * $addToSet Atomically adds value to the array only if value not in the array already.
* If containing array is missing it will be created.
* - {.., '$addToSet' : {'fpath' : val1, 'fpathN' : valN, ...}}
* $addToSetAll Batch version if $addToSet
@@ -414,7 +414,7 @@ EJDB.prototype.find = function() {
};
/**
- * Same as #find() but retrieves only one matching JSON object.
+ * Same as #find() but retrieves only first matching JSON object.
* If callback is not provided this function will be synchronous.
*
* Call variations of findOne():
--
2.7.4