Awesome
Talking is like medicine, little of it benefits and lot of it harms. - Imam Ali
myCouch
CouchDB client wrtten in Nim.
currently it's based on CouchDB v3.1.1
note: deprecated & no-op APIs are not included
APIs
How can I know what proc
for API should I use?
- you go to the CoudhDB documentation link
- copy a API link (eg:
api/ddoc/render.html#db-design-design-doc-update-update-name
) - search that link in the
couchdb/api.nim
or [github-page] - you found the corresponding proc!
Limitation
- copy APIs are not supported:
- continuous feed API are not supported in:
- cluster_setup API is not available for now
note: examples are placed in tests/tapi.nim
Features
Mango Query-Lang
mango(
query= PS(@name == "hamid" and @year notin [1399])
fields= @["name", "stars"]
)
converts to =>
{
"selector" : {
"$and": {
"name": {
"$eq": "hamid"
},
"year": {
"$nin": [1399]
}
}
},
"fields": ["name", "stars"]
}
SQL-like Selector Parser
you can put the query im 2 ways: [PS
is an alias for parseSelector
]
PS( <query> )
-
PS: <query>
PS:
nil # {"_id": {"$gt": nil}}
# field name variants
# since nim doesn't support underline at the first character of an identifier, you can use -
field == true # {"<THE VALUE OF VAR 'field'>": {"$eq": true}}
@field == true # {"field" : {"$eq": true}}
@-field # "_field"
@"_field._sub" # "_field._sub"
# comparisions < <= == != >= >
@year < bad_year # 'year' is a field / 'bad_year' is var
@name =~ "ali" # regex match | $regex
@name =~ pat.pattern # ""
@year mod [4,2] # modular | $mod
@year in [2020, 2021] # in | $in
@year notin [2020, 2021] # not in | $nin
?= @genre or ?! @genre # (?=): exists, (?!): not exists | $exists
? @genre or ! @genre # (?): == true, (!): == false
@year is myType # is for type spesification | $type
@year is number # object, array, string, number, nil, bool
@list.size(3) # match array len | $size
@list.all(["hamid", "ali"]) # all function are the same for elemMatch, allMatch, keyMapMatch functions | $all
# or not | $and $or $not
not (@artist == "mohammadAli" and (@genre notin ["pop", "rock"] or @artist == "iman khodaee"))
(@field == 3 and @date == 12).nor(@field == 4) # since nim doesnt have 'nor' operator | $nor
async + sync!
you can use all of APIs with your favourite runtime(did i use the right word?).
Qeury Server
Do you remember some of Erlang's built-in View functions? here were gonna do something like that [but in nim]
we have 5 entry points:
mapfun
-> map functionsredfun
-> reduce functionsupdatefun
-> updatefilterfun
-> filtervalidatefun
-> validate
each one are name of a macro that must be associated with corresponding proc
.
every proc must be matched with it's corresponding pattern [you can see patterns in mycouch/queryServer/designDocuments.nim
] otherwise you'll get an error.
here's an exmaple of proc testMap
as an map function
import json, tables
import mycouch/queryServer/[protocol, designDocuments]
proc testMap(doc: JsonNode): seq[JsonNode] {.mapfun.}=
# emit values like: [genre, movie_name]
if ("title" in doc) and ("genres" in doc):
for genre in doc["genres"]:
emit(genre, doc["title"])
when isMainModule:
run()
notes:
- you can use quoted names for procs like `my-pretty-view-function`
- you have to import
tables
module wherever you define your entry procs - don't forget to call
run
proc in your code! it starts the query server
compile that file and config the query server doc
then you can create a design document with your query server: [design doc example for above code]
{
"_id": "_design/temp",
"language": "<your-language-server-name>",
"views": {
"myview": {
"map": "testMap"
}
}
}
done! your query server is ready!
[ examples with more details are placed in tests/queryServerInstance.nim
]
TODOs
- update docs on gh-pages [you can
nimble gen docs
by yourself btw] - add docs for all modules
- helper module
- add test coverage tag
Notes
contributions are welcome :D