Skip to content

javierg/couchx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

83 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Couchx

CouchDB Adapter for Ecto3.

The Adapter supports 1 main Repo, but also dynamic repos where you can querie on multiple Dbs with a dynamic supervisor.

To create a Repo follow the Ecto default instructions, but we will need to add returning true option in the Repo module, this is in order to have the _rev value updated into the documents.

defmodule MyApp.Repo do
  use Ecto.Repo,
    otp_app: :my_app,
    adapter: Couchx.Adapter

  def default_options(_), do: [returning: true]
end

The supported functions in this version are:

Repo.get Struct, doc_id
Repo.all(Struct)
Repo.all from doc in Struct, where: doc._id in ^doc_ids_list
Repo.all from doc in Struct, where: doc.field == ^field
Repo.one from doc in Struct, where doc.field == ^field
Repo.one from doc in Struct, where doc.field == ^field, select: ~w[field1 field2]a
Repo.insert Struct, doc
Repo.insert_all Struct, docs
Repo.delete Struct, %{_id: doc_id}
Repo.update changeset

To limit a query you can use:

Repo.all from doc in Struct, where: doc.field == ^field, limit: 1

A very basic version of sort is supported depending on the CouchDB version.

On version 1.x

The sort will only work with desc or asc on the results of _all_docs queries, which are the ones done by Repo.all

Repo.all from doc in Struct, order_by: [desc: doc._id]

On version >= 2.x

The sort will depend on the type of query being done, if it is an _all_docs query, the same rules as 1.x apply. But for simple field lookups depending on an index, it will follow the rules from Mango, where the order_by values will be parsed.

order_by [desc: doc.field]

will be parsed as

{"sort": [{"field": "desc"}]

It adds a simple way to execute JS view queries with:

  def query(name, design, view_map, key, opts \\ []) do
    {adapter, meta} = Ecto.Repo.Registry.lookup(name)
    adapter.execute(:view, meta, design, view_map, key, opts)
  end

Not ideal, so open to suggestions here.

Mango support

Currently support for mango is limited to do queries on single property, on previously created indexes. The selector is a map with the type property preset to the model namespace, such as:

%{
  selector: %{
    type: "user",
    email: "[email protected]"
  }
}

This will be the query generated by:

import Ecto.Query

Repo.all from u in User, where: u.email == "[email protected]"

It will also work with:

import Ecto.Query

email = "[email protected]"
Repo.all from u in User, where: u.email == ^email

Mango Index

Couchx have a couple of tasks to handle database indexing:

$ mix couchx.gen.mango_index -r MyApp.Repo -n my-mango-index -f name,email

This command will generate a index file on priv/my_app/repo/index/my-mango-index.exs It rely on repos declared under config.exs

import Config

config :my_app, ecto_repos: [MyApp.Repo]
...

And build a file with contents such as:

defmodule MyApp.Repo.Index.MyMangoIndex do
  use Couchx.MangoIndex, repo_name: MyApp.Repo

  def up do
    create_index "my-mango-index" do
      %{fields: ~w[name email]}
    end
  end

  def down do
    drop_index("my-mango-index")
  end

This file will be executed with

$ mix couchx.mango_index

which will persist the index document in the database defined by the repo. And if you want to remove the index you can call:

$ mix couch.mango_index.down -r MyApp.Repo, -n my-mango-index

Mango indexes could be run in the release like this:

defmodule MyApp.Release do
  @moduledoc """
  Used for executing DB release tasks when run in production without Mix
  installed.
  """

  @app :my_app

  def migrate do
    Application.ensure_all_started(@app)
    Couchx.Migrator.run(MyApp.Repo, :up)
  end
end

TODO:

  • Repo.insert_all
  • Repo.delete_all
  • Bulk doc updates
  • Better error handling
  • More Mango Queries
  • A better view query pattern
  • Auto indexing requested JS queries
  • JS view index management
  • Add tests

Installation

The package can be installed by adding couchx to your list of dependencies in mix.exs:

def deps do
  [
    {:couchx, "~> 0.1.0"}
  ]
end

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/couchx.