Skip to content

Commit 5ebf0e1

Browse files
committed
Merge branch 'master' into not-master
2 parents edf909f + b7aa63c commit 5ebf0e1

25 files changed

+403
-111
lines changed

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,29 @@
1+
## 0.7.4
2+
* Enhancements
3+
* added a new option to specify a timeout, when increasing the connction pool is no option
4+
5+
## 0.7.3
6+
7+
* Enhancements
8+
* added support for OTP 24
9+
* Add support for tls setting in connection string (tschmittni)
10+
* Replace deprecated functions (OTP 24) (aenglisc )
11+
12+
## 0.7.2
13+
14+
* Enhancements
15+
* Adds test to cover one of Mongo.find/4 errors (vukanac)
16+
* Update specs for Mongo.find/4 with error tuple (vukanac)
17+
* Fix build warnings and correct typespec (joeapearson)
18+
* Update db_connection version to remove System.stacktrace warnings (vukanac)
19+
* Update SCRAM auth procedure (LetThereBeDwight)
20+
21+
## 0.7.1
22+
23+
* Enhancements
24+
* upgraded decimal to 2.0, jason to 1.2
25+
* Add proper support for tailable cursors and awaitData (PR #74)
26+
127
## 0.7.0
228

329
* Enhancements

README.md

Lines changed: 63 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# An alternative Mongodb driver for Elixir
1+
# An Alternative Elixir Driver for MongoDB
22
[![Build Status](https://travis-ci.org/zookzook/elixir-mongodb-driver.svg?branch=master)](https://travis-ci.org/zookzook/elixir-mongodb-driver)
33
[![Coverage Status](https://coveralls.io/repos/github/zookzook/elixir-mongodb-driver/badge.svg?branch=master)](https://coveralls.io/github/zookzook/elixir-mongodb-driver?branch=master)
44
[![Hex.pm](https://img.shields.io/hexpm/v/mongodb_driver.svg)](https://hex.pm/packages/mongodb_driver)
@@ -24,7 +24,7 @@
2424
* support for retryable reads ([See](https://github.com/mongodb/specifications/blob/master/source/retryable-reads/retryable-reads.rst))
2525
* support for retryable writes ([See](https://github.com/mongodb/specifications/blob/master/source/retryable-writes/retryable-writes.rst))
2626

27-
## Data representation
27+
## Data Representation
2828

2929
BSON Elixir
3030
---------- ------
@@ -50,19 +50,19 @@ BSON symbols can only be decoded.
5050

5151
## Usage
5252

53-
### Installation:
53+
### Installation
5454

5555
Add `mongodb_driver` to your mix.exs `deps`.
5656

5757
```elixir
5858
defp deps do
59-
[{:mongodb_driver, "~> 0.6"}]
59+
[{:mongodb_driver, "~> 0.7"}]
6060
end
6161
```
6262

6363
Then run `mix deps.get` to fetch dependencies.
6464

65-
### Simple connection to MongoDB
65+
### Simple Connection to MongoDB
6666

6767
```elixir
6868
# Starts an unpooled connection
@@ -112,7 +112,7 @@ Failing operations return a `{:error, error}` tuple where `error` is a
112112
}}
113113
```
114114

115-
### Connection pooling
115+
### Connection Pooling
116116
The driver supports pooling by DBConnection (2.x). By default `mongodb_driver` will start a single
117117
connection, but it also supports pooling with the `:pool_size` option. For 3 connections add the `pool_size: 3` option to `Mongo.start_link` and to all
118118
function calls in `Mongo` using the pool:
@@ -148,17 +148,31 @@ Due to the mongodb specification, an additional connection is always set up for
148148

149149
### Replica Sets
150150

151-
To connect to a Mongo cluster that is using replica sets, it is recommended to use the `:seeds` list instead
152-
of a `:hostname` and `:port` pair.
151+
By default, the driver will discover the deployment's topology and will connect
152+
to the replica set automatically, using either the seed list syntax or the URI
153+
syntax. Assuming the deployment has nodes at `hostname1.net:27017`,
154+
`hostname2.net:27017` and `hostname3.net:27017`, either of the following
155+
invocations will discover the entire deployment:
153156

154157
```elixir
155-
{:ok, pid} = Mongo.start_link(database: "test", seeds: ["hostname1.net:27017", "hostname2.net:27017"])
158+
{:ok, pid} = Mongo.start_link(database: "test", seeds: ["hostname1.net:27017"])
159+
160+
{:ok, pid} = Mongo.start_link(url: "mongodb://hostname1.net:27017/test")
161+
```
162+
163+
To ensure that the connection succeeds even when some of the nodes are not
164+
available, it is recommended to list all nodes in both the seed list and the
165+
URI, as follows:
166+
167+
```elixir
168+
{:ok, pid} = Mongo.start_link(database: "test", seeds: ["hostname1.net:27017", "hostname2.net:27017", "hostname3.net:27017"])
169+
170+
{:ok, pid} = Mongo.start_link(url: "mongodb://hostname1.net:27017,hostname2.net:27017,hostname3.net:27017/test")
156171
```
157172

158-
This will allow for scenarios where the first `"hostname1.net:27017"` is unreachable for any reason
159-
and will automatically try to connect to each of the following entries in the list to connect to the cluster.
173+
Using an SRV URI also discovers all nodes of the deployment automatically.
160174

161-
### Auth mechanisms
175+
### Auth Mechanisms
162176

163177
For versions of Mongo 3.0 and greater, the auth mechanism defaults to SCRAM.
164178
If you'd like to use [MONGODB-X509](https://docs.mongodb.com/manual/tutorial/configure-x509-client-authentication/#authenticate-with-a-x-509-certificate)
@@ -168,7 +182,7 @@ authentication, you can specify that as a `start_link` option.
168182
{:ok, pid} = Mongo.start_link(database: "test", auth_mechanism: :x509)
169183
```
170184

171-
### AWS, TLS and Erlang SSL ciphers
185+
### AWS, TLS and Erlang SSL Ciphers
172186

173187
Some MongoDB cloud providers (notably AWS) require a particular TLS cipher that isn't enabled
174188
by default in the Erlang SSL module. In order to connect to these services,
@@ -204,14 +218,18 @@ Using `$in`
204218
Mongo.find(:mongo, "users", %{email: %{"$in" => ["[email protected]", "[email protected]"]}})
205219
```
206220

207-
### Change streams
221+
### Change Streams
222+
223+
Change streams are available in replica set and sharded cluster deployments
224+
and tell you about changes to documents in collections. They work like endless
225+
cursors.
226+
227+
The special thing about change streams is that they are resumable: in case of
228+
a resumable error, no exception is propagated to the application, but instead
229+
the cursor is re-scheduled at the last successful location.
208230

209-
Change streams exist in replica set and cluster systems and tell you about changes to collections.
210-
They work like endless cursors.
211-
The special thing about the change streams is that they are resumable. In the case of a resumable error,
212-
no exception is made, but the cursor is re-scheduled at the last successful location.
213-
The following example will never stop,
214-
so it is a good idea to use a process for change streams.
231+
The following example will never stop, thus it is a good idea to use a process
232+
for reading from change streams:
215233

216234
```elixir
217235
seeds = ["hostname1.net:27017", "hostname2.net:27017", "hostname3.net:27017"]
@@ -220,7 +238,7 @@ cursor = Mongo.watch_collection(top, "accounts", [], fn doc -> IO.puts "New Tok
220238
cursor |> Enum.each(fn doc -> IO.puts inspect doc end)
221239
```
222240

223-
An example with a spawned process that sends message to the monitor process:
241+
An example with a spawned process that sends messages to the monitor process:
224242

225243
```elixir
226244
def for_ever(top, monitor) do
@@ -231,7 +249,7 @@ end
231249
spawn(fn -> for_ever(top, self()) end)
232250
```
233251

234-
For more information see
252+
For more information see:
235253

236254
* [Mongo.watch_collection](https://hexdocs.pm/mongodb_driver/Mongo.html#watch_collection/5)
237255

@@ -252,7 +270,22 @@ Mongo.insert_many(top, "users", [
252270
])
253271
```
254272

255-
### Bulk writes
273+
### Indexes
274+
275+
To create indexes you can call the function `Mongo.createIndexed/4`:
276+
277+
```elixir
278+
indexes = [[key: [files_id: 1, n: 1], name: "files_n_index", unique: true]]
279+
Mongo.create_indexes(topology_pid, "my_collection", indexes, opts)
280+
```
281+
282+
You specify the `indexes` parameter as a keyword list with all options described in the documentation of the [createIndex](https://docs.mongodb.com/manual/reference/command/createIndexes/#dbcmd.createIndexes) command.
283+
284+
For more information see:
285+
* [Mongo.create_indexes](https://hexdocs.pm/mongodb_driver/Mongo.html#create_indexes/4)
286+
* [Mongo.drop_index](https://hexdocs.pm/mongodb_driver/Mongo.html#drop_index/4)
287+
288+
### Bulk Writes
256289

257290
The motivation for bulk writes lies in the possibility of optimization, the same operations
258291
to group. Here, a distinction is made between disordered and ordered bulk writes.
@@ -316,10 +349,8 @@ and have a look at the test units as well.
316349

317350
### GridFS
318351

319-
The driver supports the GridFS specifications. You create a `Mongo.GridFs.Bucket` struct and with this struct you can
320-
upload and download files.
321-
322-
### Example
352+
The driver supports the GridFS specifications. You create a `Mongo.GridFs.Bucket`
353+
struct and with this struct you can upload and download files. For example:
323354

324355
```elixir
325356
bucket = Bucket.new(top)
@@ -405,8 +436,6 @@ iex> Mongo.find_one(conn, "test", %{})
405436
The `travis.yml` file uses only the latest MongoDB. It creates a replica set of three nodes and disables the SSL test case. If you want to
406437
run the test cases against other MongoDB deployments or older versions, you can use the [mtools](https://github.com/rueckstiess/mtools) for deployment and run the test cases locally:
407438

408-
### Example
409-
410439
```bash
411440
pyenv global 3.6
412441
pip3 install --upgrade pip
@@ -418,11 +447,11 @@ mix test --exclude ssl --exclude socket
418447

419448
The SSL test suite is disabled by default.
420449

421-
### Enable the SSL tests
450+
### Enable the SSL Tests
422451

423452
`mix test --exclude ssl`
424453

425-
### Enable SSL on your Mongo server
454+
### Enable SSL on Your MongoDB Server
426455

427456
```bash
428457
$ openssl req -newkey rsa:2048 -new -x509 -days 365 -nodes -out mongodb-cert.crt -keyout mongodb-cert.key
@@ -433,21 +462,21 @@ $ mongod --sslMode allowSSL --sslPEMKeyFile /path/to/mongodb.pem
433462
* For `--sslMode` you can use one of `allowSSL` or `preferSSL`
434463
* You can enable any other options you want when starting `mongod`
435464

436-
## More examples
465+
## More Examples
437466

438467
There are some basic examples in the `example` folder. But if you want to see the driver in action
439468
take a look at [Vega](https://github.com/zookzook/vega), especially the [Board.ex](https://github.com/zookzook/vega/blob/master/lib/vega/board.ex) module for using the transaction api together with
440469
bulk operations.
441470

442-
## Special thanks
471+
## Special Thanks
443472

444473
Special thanks to [JetBrains](https://www.jetbrains.com/?from=elixir-mongodb-driver) for providing a free JetBrains Open Source license for their complete toolbox.
445474

446475
The [Documentation](https://hexdocs.pm/mongodb_driver/readme.html) is online, but currently not up to date.
447476
This will be done as soon as possible. In the meantime, look in the source code. Especially
448477
for the individual options.
449478

450-
This driver is based on [original](https://github.com/ankhers/mongodb).
479+
This driver is based on the [original Elixir driver for MongoDB](https://github.com/ankhers/mongodb).
451480

452481
## License
453482

lib/bson/types.ex

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,32 @@ defmodule BSON.Binary do
99
}
1010
defstruct [binary: nil, subtype: :generic]
1111

12-
defimpl Inspect do
13-
def inspect(%BSON.Binary{binary: value, subtype: :generic}, _opts) do
14-
"#BSON.Binary<#{Base.encode16(value, case: :lower)}>"
15-
end
16-
def inspect(%BSON.Binary{binary: value, subtype: :uuid}, _opts) do
12+
defimpl String.Chars, for: BSON.Binary do
13+
def to_string(%BSON.Binary{binary: value, subtype: subtype}) when subtype in [:uuid, :uuid_old] do
1714
p1 = binary_part(value, 0, 4)
1815
p2 = binary_part(value, 4, 2)
1916
p3 = binary_part(value, 6, 2)
2017
p4 = binary_part(value, 8, 2)
2118
p5 = binary_part(value, 10, 6)
22-
"#BSON.UUID<#{Base.encode16(p1, case: :lower)}-#{Base.encode16(p2, case: :lower)}-#{Base.encode16(p3, case: :lower)}-#{Base.encode16(p4, case: :lower)}-#{Base.encode16(p5, case: :lower)}>"
19+
"#{Base.encode16(p1, case: :lower)}-#{Base.encode16(p2, case: :lower)}-#{Base.encode16(p3, case: :lower)}-#{Base.encode16(p4, case: :lower)}-#{Base.encode16(p5, case: :lower)}"
20+
end
21+
def to_string(%BSON.Binary{binary: value}) do
22+
Base.encode16(value, case: :lower)
23+
end
24+
end
25+
26+
defimpl Inspect do
27+
def inspect(%BSON.Binary{subtype: :generic} = binary, _opts) do
28+
"#BSON.Binary<#{to_string(binary)}>"
29+
end
30+
def inspect(%BSON.Binary{subtype: :uuid} = binary, _opts) do
31+
"#BSON.UUID<#{to_string(binary)}>"
32+
end
33+
def inspect(%BSON.Binary{subtype: :uuid_old} = binary, _opts) do
34+
"#BSON.LUUID<#{to_string(binary)}>"
2335
end
24-
def inspect(%BSON.Binary{binary: value, subtype: subtype}, _opts) do
25-
"#BSON.Binary<#{Base.encode16(value, case: :lower)}, #{subtype}>"
36+
def inspect(%BSON.Binary{subtype: subtype} = binary, _opts) do
37+
"#BSON.Binary<#{to_string(binary)}, #{subtype}>"
2638
end
2739
end
2840
end

lib/mongo.ex

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ defmodule Mongo do
1010
* `:timeout` - The maximum time that the caller is allowed the to hold the
1111
connection’s state (ignored when using a run/transaction connection,
1212
default: `15_000`)
13+
* `:checkout_timeout` - The maximum time for checking out a new session and connection (default: `60_000`).
14+
When the connection pool exhausted then the function call times out after :checkout_timeout.
1315
* `:pool` - The pooling behaviour module to use, this option is required
1416
unless the default `DBConnection.Connection` pool is used
1517
* `:pool_timeout` - The maximum time to wait for a reply when making a
@@ -636,7 +638,7 @@ defmodule Mongo do
636638
Mongo.find(top, "jobs", %{}, batch_size: 2)
637639
638640
"""
639-
@spec find(GenServer.server, collection, BSON.document, Keyword.t) :: cursor
641+
@spec find(GenServer.server, collection, BSON.document, Keyword.t) :: cursor | {:error, term()}
640642
def find(topology_pid, coll, filter, opts \\ []) do
641643

642644
filter = case normalize_doc(filter) do
@@ -657,7 +659,6 @@ defmodule Mongo do
657659
showRecordId: opts[:show_record_id],
658660
tailable: opts[:tailable],
659661
oplogReplay: opts[:oplog_replay],
660-
tailable: opts[:tailable],
661662
noCursorTimeout: opts[:no_cursor_timeout],
662663
awaitData: opts[:await_data],
663664
batchSize: opts[:batch_size],
@@ -670,7 +671,7 @@ defmodule Mongo do
670671

671672
cmd = filter_nils(cmd)
672673

673-
drop = ~w(limit hint single_batch read_concern max min collation return_key show_record_id tailable no_cursor_timeout await_data batch_size projection comment max_time skip sort)a
674+
drop = ~w(limit hint single_batch read_concern max min collation return_key show_record_id tailable no_cursor_timeout await_data projection comment skip sort)a
674675
opts = Keyword.drop(opts, drop)
675676
try do
676677
get_stream(topology_pid, cmd, opts)
@@ -1202,9 +1203,14 @@ defmodule Mongo do
12021203
end
12031204

12041205
@doc """
1205-
Convenient function to creates new indexes in the collection `coll`.
1206+
Convenient function to creates new indexes in the collection `coll`. The `indexes` parameter is a
1207+
list with all options for creating indexes in the MongoDB.
1208+
1209+
See
1210+
[options](https://docs.mongodb.com/manual/reference/command/createIndexes/#dbcmd.createIndexes)
1211+
about the details of each parameter.
12061212
"""
1207-
@spec create_indexes(GenServer.server, String.t, Keyword.t, Keyword.t) :: :ok | {:error, Mongo.Error.t}
1213+
@spec create_indexes(GenServer.server, String.t, [Keyword.t], Keyword.t) :: :ok | {:error, Mongo.Error.t}
12081214
def create_indexes(topology_pid, coll, indexes, opts \\ []) do
12091215
cmd = [createIndexes: coll, indexes: indexes]
12101216
with {:ok, _} <- Mongo.issue_command(topology_pid, cmd, :write, opts) do

0 commit comments

Comments
 (0)