Giter Site home page Giter Site logo

annkissam / rummage_ecto Goto Github PK

View Code? Open in Web Editor NEW
209.0 12.0 38.0 3.73 MB

Search, Sort and Pagination for ecto queries

License: MIT License

Elixir 100.00%
search elixir elixir-programming-language ecto pagination paginate sorting rummage sorting-ecto sort ransack metasearch

rummage_ecto's Introduction

Rummage.Ecto

https://hexdocs.pm/rummage_ecto/Rummage.Ecto.html

Build Status Coverage Status Hex Version hex.pm downloads Hex docs docs MIT licensed

If you're looking for full Phoenix support, Rummage.Phoenix uses Rummage.Ecto and adds HTML and Controller support to it. You can check Rummage.Phoenix out by clicking here

Please refer for CHANGELOG for version specific changes

Rummage.Ecto is a light weight, but powerful framework that can be used to alter Ecto queries with Search, Sort and Paginate operations.

It accomplishes the above operations by using Hooks, which are modules that implement Rummage.Ecto.Hook behavior. Each operation: Search, Sort and Paginate have their hooks defined in Rummage. By doing this, Rummage is completely configurable.

For example, if you don't like one of the hooks of Rummage, but you do like the other two, you can configure Rummage to not use it and write your own custom hook.

NOTE: Rummage is not like Ransack, and it doesn't intend to be like Ransack. It doesn't define functions based on search parameters. If you'd like to have something like that, you can always configure Rummage to use your Search module for that model. This is why Rummage has been made configurable.

To see an example usage of rummage, check this repository.

Installation

This package is available in Hex, and can be installed as:

  • Add rummage_ecto to your list of dependencies in mix.exs:

    def deps do
      [{:rummage_ecto, "~> 2.0.0-rc.0"}]
    end

Blogs

Current Blogs:

Coming up next:

  • Using Rummage.Phoenix: Part 2
  • Using the Rummage Search hook
  • Using the Rummage Sort hook
  • Writing a Custom Rummage.Ecto Hook
  • Writing a Custom Rummage.Phoenix HTML helper

Hooks

  • Hooks are modules (that use Rummage.Ecto.Hook) and implement callbacks for Rummage.Ecto.Hook behaviour. Each ecto operation which can transform the query is defined by a Hook. Hooks have run/2 function using which they can transform an Ecto.Queryable variable and have format_params/3 function using which they can transform params passed to them through rummage_ecto

Configuration

  • NOTE: This is Optional. If no configuration is provided, Rummage will use default hooks and AppName.Repo as the repo

  • If you want to override any of the Rummage default hooks, add rummage_ecto config to your list of configs in dev.exs:

    config :rummage_ecto,
      Rummage.Ecto,
      search: MyApp.SearchModule
  • For configuring a repo:

    config :rummage_ecto,
      Rummage.Ecto,
      repo: MyApp.Repo # This can be overridden per model basis, if need be.
  • Other config options are: repo, sort, paginate, per_page

  • Rummage.Ecto can be configured globally with a per_page value (which can be overridden for a model). If you want to set different per_page for different the models, add it to model.exs file while using Rummage.Ecto as shown in the Advanced Usage Section.

Usage

Rummage.Ecto comes with a lot of powerful features which are available right away, without writing a whole lot of code.

Below are the ways Rummage.Ecto can be used:

Basic Usage:

  • Add the Repo of your app and the desired per_page (if using Rummage's Pagination) to the rummage_ecto configuration in config.exs:
config :rummage_ecto, Rummage.Ecto,
  repo: MyApp.Repo,
  per_page: 10
  • And you should be able to use Rummage.Ecto with any Ecto model.

Advanced Usage:

  • If you'd like to override any of Rummage's default hooks with your custom hook, add the CustomHook of your app with the desired operation to the rummage_ecto configuration in config.exs:
config :rummage_ecto, Rummage.Ecto,
  repo: MyApp.Repo,
  search: MyApp.SearchModule,
  paginate: MyApp.PaginateModule
  • When using Rummage.Ecto with an app that has multiple Repos, or when there's a need to configure Repo per model basis, it can be passed along with with the call to Rummage.Ecto. This overrides the default repo set in the configuration:
{queryable, rummage} = Product
  |> Rummage.Ecto.rummage(rummage, repo: MyApp.Repo2)
  • And you should be able to use Rummage.Ecto with Product model which is in a different Repo than the default one.

Examples

  • Setting up the application above will allow us to do the following:
rummage = %{
  search: %{field_1 => %{search_type: :like, search_term: "field_!"}},
  sort: %{field: :field1, order: :asc},
  paginate: %{per_page: 5, page: 1}
}

{queryable, rummage} = Product
  |> Rummage.Ecto.rummage(rummage)

products = queryable
  |> Product.another_operation # <-- Since `Rummage` is Ecto, we can pipe the result queryable into another queryable operation.
  |> Repo.all
  • Rummage responds to params with keys: search, sort and/or paginate. It doesn't need to have all the keys, or any keys for that matter. If invalid keys are passed, they won't alter any operations in rummage. Here's an example of Rummage params:
rummage = %{
  search: %{field_1 => %{search_type: :like, search_term: "field_!"}},
  sort: %{field: :field1, order: :asc},
  paginate: %{per_page: 5, page: 1}
}

rummage_ecto's People

Contributors

chilian avatar ericsullivan avatar iv-3an-ev avatar mrkaspa avatar ohmycto avatar thebugcatcher avatar yuchunc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rummage_ecto's Issues

** (UndefinedFunctionError) function Rummage.Ecto.__using__/1 is undefined or private

i use rummage_ecto 1.2.0, when downgrading to 1.0.0 it works.
offending line is just "use Rummage.Ecto"

also, i get a warning when compiling:

warning: the dependency :rummage_phoenix requires Elixir "~> 1.3.4" but you are running on v1.4.2
but probably this doesnt work because of the v, as 1.4.2 is greater than 1.3.4
os is freebsd if that matters
thanks

Make README awesome!

  • Add better README with BASIC USAGE and ADVANCED USAGE
  • Add Blog links (after editing the blogs to work with 1.0)
  • Update version for rummage_ecto in the deps to 1.0
  • Give Custom hooks usage example
  • Some screenshots of the terminal with commands

How to add search items in search

I want to search multiple columns at the same time and return the results that may appear in every column of the search column.
"search" => %{"field_1" => %{"assoc" => [], "search_type" => "like", "search_term" => "field_!"}, 
That is: field_1 = [name, age, address]
How to do it??

Model count query does not work without implicit `id` field

Hello,

I noticed when I try to get a .rummage, a count query executes such as SELECT count(t0.id) FROM table AS t0. My issue is that I don't have an implicit id field in my models, rather a prefixed table id name such as table.table_id instead of table.id.

I noticed in the function get_total_count, the query, count(b.id), confirms this. It could have been any key which could have been inferred by Schema.__schema__(:fields) |> List.first(). (https://hexdocs.pm/ecto/Ecto.Schema.html#module-reflection)

Although this may not be fixed, the documentation should include that implicit field or have it configurable. For the meantime, I added the implicit blank id field as a workaround.

Search operation, the total_count that is taken is not in conformity with the actual

To do query operation, the value of total_count is not the expected result.
The following is the IEX operation:

iex(4)rummage = %{
...(4)>       search: %{name:  %{search_type: :like, search_term: "c"}},
...(4)>       sort: %{field: :name, order: :asc},
...(4)>       paginate: %{page: 1}
...(4)>     }
%{paginate: %{page: 1},
search: %{name: %{search_term: "c", search_type: :like}},
sort: %{field: :name, order: :asc}}

iex(5)> {queryable, rummage} = ZergApi.Base.Exchange.rummage(rummage)
[debug] QUERY OK source="exchanges" db=0.1ms
SELECT count(DISTINCT e0.`id`) FROM `exchanges` AS e0 []
{#Ecto.Query<from e in subquery(from e in subquery(from e in ZergApi.Base.Exchange),
where: like(e.name, ^"%c%")),
order_by: [asc: e.name], limit: ^10, offset: ^0>,
%{paginate: %{max_page: 1, page: 1, per_page: 10, total_count: 10},
 search: %{name: %{assoc: [], search_expr: :where, search_term: "c",
     search_type: :like}},
 sort: %{assoc: [], field: :name, order: :asc}}}

To do query operation, the value of total_countde is not the expected result.
The following is the IEX operation
There are ten pieces of data in this table. After the search operation, three data should be returned, that is, total_count=3, and the actually returned total_count =10, and the following is the actual data.
and the following is the actual data

iex(6)> exchanges = queryable |> ZergApi.Repo.all
[debug] QUERY OK db=0.4ms
SELECT s0.`id`, s0.`name`, s0.`cn_name`, s0.`home_page`, s0.`timezone`, s0.`inserted_at`, s0.`updated_at` FROM (SELECT s0.`id` AS `id`, s0.`name` AS `name`, s0.`cn_name` AS `cn_name`, s0.`home_page` AS `home_page`, s0.`timezone` AS `timezone`, s0.`inserted_at` AS `inserted_at`, s0.`updated_at` AS `updated_at` FROM (SELECT e0.`id` AS `id`, e0.`name` AS `name`, e0.`cn_name` AS `cn_name`, e0.`home_page` AS `home_page`, e0.`timezone` AS `timezone`, e0.`inserted_at` AS `inserted_at`, e0.`updated_at` AS `updated_at` FROM `exchanges` AS e0) AS s0 WHERE (s0.`name` LIKE ?)) AS s0 ORDER BY s0.`name` LIMIT ? OFFSET ? ["%c%", 10, 0]
[%ZergApi.Base.Exchange{__meta__: #Ecto.Schema.Metadata<:loaded, "exchanges">,
  cn_name: "", home_page: "", id: 5,
  inserted_at: ~N[2018-04-10 14:02:17.000000], name: "",
  products: #Ecto.Association.NotLoaded<association :products is not loaded>,
  timezone: "Asia/Shanghai", updated_at: ~N[2018-04-10 14:02:17.000000]},
 %ZergApi.Base.Exchange{__meta__: #Ecto.Schema.Metadata<:loaded, "exchanges">,
  cn_name: "", home_page: "", id: 6,
  inserted_at: ~N[2018-04-10 14:02:17.000000], name: "",
  products: #Ecto.Association.NotLoaded<association :products is not loaded>,
  timezone: "Asia/Shanghai", updated_at: ~N[2018-04-10 14:02:17.000000]},
 %ZergApi.Base.Exchange{__meta__: #Ecto.Schema.Metadata<:loaded, "exchanges">,
  cn_name: "", home_page: "", id: 4,
  inserted_at: ~N[2018-04-10 14:02:17.000000], name: "",
  products: #Ecto.Association.NotLoaded<association :products is not loaded>,
  timezone: "Asia/Shanghai", updated_at: ~N[2018-04-10 14:02:17.000000]}]

Can you tell me how to solve this problem?

default config not loaded

hey i get the following error:

(RuntimeError) Expected key `repo` in `opts`, got []

heres my config:

config :plonquo_api, Rummage.Ecto,
  repo: PlonquoApi.Repo,
  per_page: 300

and the controller code:

  def index(conn, %{"per_page" => per, "page" => page}) do
    {query, _rummage} = Rummage.Ecto.rummage(Activity, %{paginate: %{per_page: per, page: page}})

    data = query
           |> Activity.preload
           |> Repo.all
    render conn, "index.json-api", data: data
  end

Don't run in umbrella app

I have separated model and web in differents apps.

My model:

defmodule Tools.Model.Schemas.Vendor do
  use Ecto.Schema
  use Rummage.Ecto

  import Ecto.Changeset

  defmodule Type do
    use Exnumerator, values: [
      :constructor, :person, :corporation, :company, :real_state, :other
    ]
  end

  defmodule Size do
    use Exnumerator, values: [
      :small, :medium, :large, :unknown, :na
    ]
  end

  schema "vendors" do
    field :vendor_id, :string
    field :name, :string
    field :city, :string
    field :state, Tools.Model.Type.State
    field :description, :string
    field :notes, :string
    field :logo, :string
    field :size, Size
    field :type, Type

    timestamps()
  end

  @allowed [:name, :description, :notes, :logo, :size, :city, :type]
  @allowed_new [:vendor_id]
  @required [:vendor_id, :name, :type]

  def changeset_new(vendor, params \\ %{}) do
    vendor
    |> cast(params, (@allowed ++ @allowed_new))
    |> validate_required(@required)
    |> unique_constraint(:vendor_id)
  end

  def changeset_edit(vendor, params \\ %{}) do
    vendor
    |> cast(params, @allowed)
    |> validate_required(@required)
    |> unique_constraint(:vendor_id)
  end
end

The config and deps is ok

#IN config.exs
config :rummage_ecto, Rummage.Ecto,
  default_repo: Tools.Model.Repo,
  default_per_page: 10

#in mix.exs

defp deps do
   [{:ecto, "~> 2.1"},
    {:postgrex, "~> 0.13.2"},
    {:poison, "~> 3.1"},
    {:timex, "~> 3.1"},
    {:exnumerator, "~> 1.2"},
    {:rummage_ecto, "~> 1.1"}]
end

When I exec mix compile I got this:

== Compilation error on file lib/tools_model/feed_web/schemas/vendor.ex ==
** (UndefinedFunctionError) function Rummage.Ecto.__using__/1 is undefined or private
    Rummage.Ecto.__using__([])
    lib/tools_model/feed_web/schemas/vendor.ex:3: (module)
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6

May I need to add something like use Tools.Feed.Web, :model in the model?
If yes, I need to make Model app dependent of the Web, to see this module, this is not right...

Using rummage search with jsonb

Can rummage be used to search through jsonb properties, in that case is there an example? Also some of the fields are optional and rummage (inheriting pg behavior I guess) throws an error when field doesn't exist, so is there a way to support optional fields?

Thanks

Search on Optional Column

Hello, I am wondering does search options generate on_where queries?
I am trying to search name of city, state, and country in one single search box, I am wondering if out of box rummage hook provides a way to do this.

Thank you!

Mix error when installing.

I am building an App with Phoenix that connects to a MySQL DB, when trying to use rummage I get an error:
** (Mix) Could not start application sqlite_ecto2: could not find application file: sqlite_ecto2.app

When I remove the {:rummage_ecto, "~> 1.3.0-rc.0"} dependency from mix everything starts working again.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.