Skip to content

Commit

Permalink
add operator !>, add example for to overload, close #10
Browse files Browse the repository at this point in the history
  • Loading branch information
mashingan committed Sep 26, 2020
2 parents 7442017 + a134f0e commit 2562534
Show file tree
Hide file tree
Showing 11 changed files with 111 additions and 73 deletions.
2 changes: 1 addition & 1 deletion anonimongo.nimble
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Package

version = "0.4.9"
version = "0.4.10"
author = "Rahmatullah"
description = "Anonimongo - Another pure Nim Mongo driver"
license = "MIT"
Expand Down
67 changes: 50 additions & 17 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,19 +92,35 @@ let id5doc = waitfor coll.findOne(bson({
doAssert id5doc["datetime"] == currtime + initDuration(hours = 5)
# find one and modify, return the old document by default
# since `v0.4.10`, the operator `!>` is added as syntax convenience
# for `bson`. Visually `!>` can be (forcefully) looked like `b`.
let oldid8doc = waitfor coll.findAndModify(
bson({ insertId: 8},
bson({ "$set": { insertId: 80 }}))
)
!>{ insertId: 8},
!>{ "$set": { insertId: 80 }})
# find documents with combination of find which return query and one/all/iter
let query = coll.find()
query.limit = 5.int32 # limit the documents we'll look
let fivedocs = waitfor query.all()
doAssert fivedocs.len == 5
# let's iterate the documents instead of bulk find
# this iteration is bit different with iterating result
# from `query.all` because `query.iter` is returning `Future[Cursor]`
# which then the Cursor has `items` iterator.
var count = 0
for doc in waitfor query.iter:
inc count
doAssert count == 5
# find one document, which newly modified
let newid8doc = waitfor coll.findOne(bson({ insertId: 80}))
let newid8doc = waitfor coll.findOne(!>{ insertId: 80 })
doAssert oldid8doc["datetime"].ofTime == newid8doc["datetime"]
# remove a document
let delStat = waitfor coll.remove(bson({
let delStat = waitfor coll.remove(!>{
insertId: 9,
}), justone = true)
}, justone = true)
doAssert delStat.success # must be true if query success
Expand Down Expand Up @@ -239,10 +255,11 @@ type
field1*: int
field2*: string
var bintstr = bson({
# the `!>` operator is added since `v0.4.10`
var bintstr = !>{
field1: 1000,
field2: "power-level"
})
}
let ourObj = bintstr.to IntString
doAssert ourObj.field1 == 1000
Expand Down Expand Up @@ -357,7 +374,7 @@ var bov = bson({
truthy: true,
},
})
var outb = bson({ objectVariant: bov })
var outb = !>{ objectVariant: bov }
# let's see if it's converted to OVKind ovMany
var outer: OuterObject
Expand Down Expand Up @@ -534,7 +551,10 @@ for most cases of working with Bson and Json.
Bson module has some functionalities to convert to and from the Object. However there are
some points to be aware:

1. User can provide the custom proc, func, or converter with pattern of `of{Typename}` which
1. The `to` macro is working exlusively converting object typedesc converting basic types already
supplied with `ofType` (with `Type` is `Int|Int32|Int64|Double|String|Time|Embedded|ObjectId`).

2. User can provide the custom proc, func, or converter with pattern of `of{Typename}` which
accepting a `BsonBase` and return `Typename`. For example:

```nim
Expand Down Expand Up @@ -580,24 +600,37 @@ func, or converter isn't checked as it becomes meaningless to use `to` macro
when the user can simply calling it directly. So any most outer type won't check whether
the user provides `of{MostOuterTypename}` implementation or not.

2. Auto Bson to Type conversion can only be done to the fields that are exported or
3. Auto Bson to Type conversion can only be done to the fields that are exported or
has custom pragma `bsonExport` as shown in this [example](#convert-from-bson-to-object-variant).

3. ~It potentially breaks when there's some arbitrary hierarchy of types definition. While it can handle
4. ~It potentially breaks when there's some arbitrary hierarchy of types definition. While it can handle
any deep of `distinct` types (that's distinct of distinct of distinct of .... of Type), but this
should be indication of some broken type definition and better be remedied from
the type design itself. If user thinks otherwise, please report this issue with the example code.~
As with v2 of `to` macro, the conversion of arbitrary `ref` and `distinct` is supported. It cannot support the
`ref distinct Type` as it's not making any sense but it supports the `distinct ref Type`. Please report the issue
if user finds the otherwise.

4. In case the user wants to persist with the current definition of any custom deep of `distinct` type,
5. In case the user wants to persist with the current definition of any custom deep of `distinct` type,
user should define the custom mechanism mentioned in point #1 above.

5. With `v0.4.5`, users are able to extract custom Bson key to map with specific field name by supplying the pragma
6. With `v0.4.5`, users are able to extract custom Bson key to map with specific field name by supplying the pragma
`bsonKey` e.g. `{.bsonKey: "theBsonKey".}`. Refer to the example [above](#convert-with-custom-key-bson). The key is **case-sensitive**.

6. `to` macro doesn't support for cyclic object types.
7. `to` macro doesn't support for cyclic object types.

8. As mentioned in point #1, the `to` macro is working exclusively converting the defined object type. As
pointed out that here, [issue/10](https://github.com/mashingan/anonimongo/issues/10), `to` make it generic, it's
reasonable for uniformed `to` convert any `typedesc`. Because the `ofType` variants for basic types are implemented
as `converters`, it's easy for user to supply the `to` overload:

```nim
template to(b: BsonBase, name: typedesc): untyped =
var r: name = b
move r
```

There's no plan to add this snippet to the library but it maybe changed in later version.

[TOC](#table-of-content)

Expand All @@ -610,7 +643,7 @@ For installation, we can choose several methods will be mentioned below.
Using Nimble package:

```
nimble install anonimongo@" >= 0.4.9"
nimble install anonimongo@" >= 0.4.10"
```

Or to install it locally
Expand Down Expand Up @@ -641,7 +674,7 @@ is usually only changes in something unrelated to the code itself.
### For dependency

```
requires "anonimongo >= 0.4.9"
requires "anonimongo >= 0.4.10"
```

or directly from Github repo
Expand Down
3 changes: 2 additions & 1 deletion src/anonimongo/collections.nim
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,10 @@ proc findOne*(c: Collection, query = bson(), projection = bsonNull(),
result = await q.one

proc findAll*(c: Collection, query = bson(), projection = bsonNull(),
sort = bsonNull()): Future[seq[BsonDocument]] {.async.} =
sort = bsonNull(), limit = 0): Future[seq[BsonDocument]] {.async.} =
var q = c.find(query, projection)
q.sort = sort
q.limit = int32 limit
result = await q.all

proc findIter*(c: Collection, query = bson(), projection = bsonNull(),
Expand Down
12 changes: 6 additions & 6 deletions src/anonimongo/core/auth.nim
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ proc authenticate*(sock: AsyncSocket, user, pass: string,
var user = user
let fst = scram.prepareFirstMessage(move user)

var q = bson({
var q = !>{
saslStart: int32 1,
mechanism: mechanism,
payload: bsonBinary fst,
})
}

when T is SHA256Digest:
q["options"] = bson({skipEmptyExchange: true})
Expand All @@ -46,11 +46,11 @@ proc authenticate*(sock: AsyncSocket, user, pass: string,
var strres = res1.documents[0]["payload"].ofBinary.stringBytes
let msgf = scram.prepareFinalMessage(msg, move strres)
stream = newStringStream()
discard stream.prepareQuery(0, 0, opQuery.int32, 0, dbname, 0, 1, bson({
discard stream.prepareQuery(0, 0, opQuery.int32, 0, dbname, 0, 1, !>{
saslContinue: int32 1,
conversationId: res1.documents[0]["conversationId"].ofInt32,
payload: bsonBinary msgf
}))
})
await sock.send stream.readAll()
let res2 = await sock.getReply
if res2.documents.len >= 1 and not res2.documents[0].ok:
Expand All @@ -66,11 +66,11 @@ proc authenticate*(sock: AsyncSocket, user, pass: string,
result = true
return
stream = newStringStream()
discard stream.prepareQuery(0, 0, opQuery.int32, 0, dbname, 0, 1, bson({
discard stream.prepareQuery(0, 0, opQuery.int32, 0, dbname, 0, 1, !>{
saslContinue: int32 1,
conversationId: res2.documents[0]["conversationId"].ofInt32,
payload: bsonBinary ""
}))
})
await sock.send stream.readAll()
when verbose:
let res3 = await sock.getReply
Expand Down
5 changes: 4 additions & 1 deletion src/anonimongo/core/bson.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1039,4 +1039,7 @@ converter ofTimestamp*(b: BsonBase): TimestampInternal =
bsonFetcher(b, bkTimestamp, BsonTimestamp, TimestampInternal)

template bson*(): untyped = bson({})
## Convenience for empty bson.
## Convenience for empty bson.

template `!>`*(b: untyped): BsonDocument = bson(b)
## Convenient operator over `bson`
2 changes: 1 addition & 1 deletion src/anonimongo/dbops/client.nim
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ when verbose:
const
drivername = "anonimongo"
description = "nim mongo driver"
anonimongoVersion* = "0.4.9"
anonimongoVersion* = "0.4.10"

proc handshake(m: Mongo, isMaster: bool, s: AsyncSocket, db: string, id: int32,
appname = "Anonimongo client apps"):Future[ReplyFormat] {.async.} =
Expand Down
8 changes: 4 additions & 4 deletions src/anonimongo/dbops/freemonitoring.nim
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import ../core/[bson, types, utils, wire]

proc getFreeMonitoringStatus*(db: Database): Future[BsonDocument] {.async.} =
result = await db.crudops(bson({
result = await db.crudops(!>{
getFreeMonitoringStatus: 1
}), "admin")
}, "admin")

proc setFreeMonitoring*(db: Database, action = "enable"):
Future[BsonDocument] {.async.} =
let q = bson({
let q = !>{
setFreeMonitoring: 1,
action: action,
})
}
result = await db.crudops(q, "admin", cmd = ckWrite)

proc enableFreeMonitoring*(db: Database): Future[BsonDocument] {.async.} =
Expand Down
18 changes: 9 additions & 9 deletions src/anonimongo/dbops/rolemgmt.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ import ../core/[bson, types, wire, utils]
proc createRole*(db: Database, name: string, privileges, roles: seq[BsonDocument],
authRestrict: seq[BsonDocument] = @[], wt = bsonNull()):
Future[WriteResult]{.async.} =
var q = bson({
var q = !>{
createRole: name,
privileges: privileges.map toBson,
roles: roles.map toBson,
})
}
if authRestrict.len >= 0:
q["authenticationRestriction"] = authRestrict.map toBson
q.addWriteConcern(db, wt)
Expand All @@ -37,9 +37,9 @@ proc updateRole*(db: Database, name: string,
if privlen == 0 and rolelen == 0:
result.reason = "Both privileges and roles cannot be empty."
return
var q = bson({
var q = !>{
updateRole: name,
})
}
if privlen > 0:
q["privileges"] = privileges.map toBson
if rolelen > 0:
Expand All @@ -51,13 +51,13 @@ proc updateRole*(db: Database, name: string,

proc dropRole*(db: Database, role: string, wt = bsonNull()):
Future[WriteResult]{.async.} =
var q = bson({ dropRole: role })
var q = !>{ dropRole: role }
q.addWriteConcern(db, wt)
result = await db.proceed(q)

proc dropAllRolesFromDatabase*(db: Database, wt = bsonNull()):
Future[WriteResult] {.async.} =
var q = bson({ dropAllRolesFromDatabase: 1 })
var q = !>{ dropAllRolesFromDatabase: 1 }
q.addWriteConcern(db, wt)
result = await db.proceed(q)

Expand All @@ -80,7 +80,7 @@ proc grantRolesToRole*(db: Database, role: string, roles: seq[BsonDocument],
result = await db.proceed(q)

proc invalidateUserCache*(db: Database): Future[WriteResult] {.async.} =
result = await db.proceed(bson({ invalidateUserCache: 1 }))
result = await db.proceed(!>{ invalidateUserCache: 1 })

proc revokePrivilegesFromRole*(db: Database, role: string, privileges: seq[BsonDocument],
wt = bsonNull()): Future[WriteResult] {.async.} =
Expand All @@ -94,9 +94,9 @@ proc revokeRolesFromRole*(db: Database, role: string, roles: seq[BsonDocument],

proc rolesInfo*(db: Database, info: BsonBase, showPriv = false,
showBuiltin = false): Future[ReplyFormat] {.async.} =
let q = bson({
let q = !>{
rolesInfo: info,
showPrivileges: showPriv,
showBuiltinRoles: showBuiltin,
})
}
result = await sendops(q, db, cmd = ckRead)
Loading

0 comments on commit 2562534

Please sign in to comment.