Giter Club home page Giter Club logo

ecto's Introduction

Ecto

Ecto


Build Status Hex.pm Documentation

Installation

Add :ecto to the list of dependencies in mix.exs:

def deps do
  [
    {:ecto, "~> 3.10"}
  ]
end

About

Ecto is a toolkit for data mapping and language integrated query for Elixir. Here is an example:

# In your config/config.exs file
config :my_app, ecto_repos: [Sample.Repo]

config :my_app, Sample.Repo,
  database: "ecto_simple",
  username: "postgres",
  password: "postgres",
  hostname: "localhost",
  port: "5432"

# In your application code
defmodule Sample.Repo do
  use Ecto.Repo,
    otp_app: :my_app,
    adapter: Ecto.Adapters.Postgres
end

defmodule Sample.Weather do
  use Ecto.Schema

  schema "weather" do
    field :city     # Defaults to type :string
    field :temp_lo, :integer
    field :temp_hi, :integer
    field :prcp,    :float, default: 0.0
  end
end

defmodule Sample.App do
  import Ecto.Query
  alias Sample.{Weather, Repo}

  def keyword_query do
    query =
      from w in Weather,
           where: w.prcp > 0 or is_nil(w.prcp),
           select: w

    Repo.all(query)
  end

  def pipe_query do
    Weather
    |> where(city: "Kraków")
    |> order_by(:temp_lo)
    |> limit(10)
    |> Repo.all
  end
end

Ecto is commonly used to interact with databases, such as PostgreSQL and MySQL via Ecto.Adapters.SQL (source code). Ecto is also commonly used to map data from any source into Elixir structs, whether they are backed by a database or not.

See the getting started guide and the online documentation for more information. Other resources available are:

  • Programming Ecto, by Darin Wilson and Eric Meadows-Jönsson, which guides you from fundamentals up to advanced concepts

  • The Little Ecto Cookbook, a free ebook by Dashbit, which is a curation of the existing Ecto guides with some extra contents

Usage

You need to add both Ecto and the database adapter as a dependency to your mix.exs file. The supported databases and their adapters are:

Database Ecto Adapter Dependencies
PostgreSQL Ecto.Adapters.Postgres ecto_sql + postgrex
MySQL Ecto.Adapters.MyXQL ecto_sql + myxql
MSSQL Ecto.Adapters.Tds ecto_sql + tds
SQLite3 Ecto.Adapters.SQLite3 ecto_sqlite3
ClickHouse Ecto.Adapters.ClickHouse ecto_ch
ETS     Etso   etso

For example, if you want to use PostgreSQL, add to your mix.exs file:

defp deps do
  [
    {:ecto_sql, "~> 3.0"},
    {:postgrex, ">= 0.0.0"}
  ]
end

Then run mix deps.get in your shell to fetch the dependencies. If you want to use another database, just choose the proper dependency from the table above.

Finally, in the repository definition, you will need to specify the adapter: respective to the chosen dependency. For PostgreSQL it is:

defmodule MyApp.Repo do
  use Ecto.Repo,
    otp_app: :my_app,
    adapter: Ecto.Adapters.Postgres,
  ...

Supported Versions

Branch Support
v3.11 Bug fixes
v3.10 Security patches only
v3.9 Security patches only
v3.8 Security patches only
v3.7 Security patches only
v3.6 and earlier Unsupported

With version 3.0, Ecto API has become stable. Our main focus is on providing bug fixes and incremental changes.

Important links

Running tests

Clone the repo and fetch its dependencies:

$ git clone https://github.com/elixir-ecto/ecto.git
$ cd ecto
$ mix deps.get
$ mix test

Note that mix test does not run the tests in the integration_test folder. To run integration tests, you can clone ecto_sql in a sibling directory and then run its integration tests with the ECTO_PATH environment variable pointing to your Ecto checkout:

$ cd ..
$ git clone https://github.com/elixir-ecto/ecto_sql.git
$ cd ecto_sql
$ mix deps.get
$ ECTO_PATH=../ecto mix test.all

Running containerized tests

It is also possible to run the integration tests under a containerized environment using earthly:

$ earthly -P +all

You can also use this to interactively debug any failing integration tests using:

$ earthly -P -i --build-arg ELIXIR_BASE=1.8.2-erlang-21.3.8.21-alpine-3.13.1 +integration-test

Then once you enter the containerized shell, you can inspect the underlying databases with the respective commands:

PGPASSWORD=postgres psql -h 127.0.0.1 -U postgres -d postgres ecto_test
MYSQL_PASSWORD=root mysql -h 127.0.0.1 -uroot -proot ecto_test
sqlcmd -U sa -P 'some!Password'

Logo

"Ecto" and the Ecto logo are Copyright (c) 2020 Dashbit.

The Ecto logo was designed by Dane Wesolko.

License

Copyright (c) 2013 Plataformatec
Copyright (c) 2020 Dashbit

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

ecto's People

Contributors

andrewdryga avatar briksoftware avatar enders avatar ericmj avatar erol avatar fishcakez avatar fuelen avatar gjaldon avatar greg-rychlewski avatar josevalim avatar joshnuss avatar kianmeng avatar laurocaetano avatar lexmag avatar lostkobrakai avatar mathieuprog avatar michalmuskala avatar mitchellhenke avatar msch avatar nathanl avatar parkerl avatar qcam avatar tanyewwei avatar thiagoarrais avatar tony612 avatar v0idpwn avatar whatyouhide avatar wojtekmach avatar zachdaniel avatar zoldar 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  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

ecto's Issues

Full stack tests

We need to start writing full stack tests. For example, that Repo.create actually creates a record in the database and that a query can get records back. We have a couple challenges here:

  1. How to setup the database before the test suite;
  2. How to clean up the database after each test. Rails, for example, wraps each test in a transaction, so there is no need for a clean up (ExUnit.CaseTemplate could be useful here);
  3. How to organize the tests independency. In the future, when we have more than one adapter, we should be able to run just postgresql tests, or just mysql tests. Maybe they should live in a special directory and we would have specific tasks for each of them, like mix test.pg. Unsure.

Clean up Ecto.Query functions

Since we will import Ecto.Query, internal functions like normalize, merge and validate need to be moved elsewhere.

Support for Repo.update_all/2 and Repo.delete_all/1

Repo.update_all/2 will receive a query expression (a Queryable) as first parameter and the values to update as the second one:

q = from p in Post, where: p.published == false
Repo.update_all(q, published: true)

Repo.delete_all/1 receives just a query. We will probably need to extend the validator to check for update and delete queries (the validator could likely have three functions, select, update and delete, one for each operation except create).

Add order to queries

Proposed syntax:

  from p in Post,
order: [p.posted, p.last_comment]

  from p in Post,
order: p.posted,
order: p.last_comment

  from p in Post,
order: [asc: p.posted, asc: p.last_comment]

The above queries are all equivalent.

Support for Repo.update/1 and Repo.delete/2

Receives an entity and updates it based on its primary key. If the entity has no id or no primary key, it should raise.

It is unclear how validations and callbacks will integrate this feature, so it should not be a concern for now.

Add Repo.get(entity, id)

Fetches a single entity by primary key. id can be a string that will be converted to integer for convenience.

What should the two query types be called?

We have the ordinary keyword queries that are keyword lists of query expressions. I think "keyword query" is a good name for them. A keyword query compiles to a recursive function application on the underlying query functions.

Example:

from c in City,
where: c.population > 10_000,
select: c.name

from(c in City) |> where([c], c.population > 10_000) |> select([c], c.name)

select(where(from(c in City), [c], c.population > 10_000), [c], c.name)

The keyword syntax will be the main syntax that most people will use. We still need to document the query functions, because some may use them, and mainly because that is where we will document all the different query expressions that can go in the keyword query.

Suggestions:
query unit
query fragment
query expression

Add documentation for query macros

There is no documentation (or maybe I missed it) on how the from(..., where: ...) syntax translates underlying. How to add new keywords to the query? The docs for Ecto.Query needs to mention this and give more examples of queries, including dynamically creating queries (if some_value do query = extend(...) end).

We also need to document each of extend, where, select, with examples both in the keywords syntax as in the binding syntax.

Subexpressions that contain nothing escaped should be evaluated

Today:

select(p in query, (1 + 2) + p.x) # => "SELECT (1 + 2) + p.x ..."

Future:

select(p in query, (1 + 2) + p.x) # => "SELECT 3 + p.x ..."

There should be an Ecto.Query.Helpers function that will force an expression to be escaped:

select(p in query, escape(1 + 2) + p.x) # => "SELECT (1 + 2) + p.x ..."

Support shorthand extend syntax

Today we have extend(query, [p], select: p.title) the shorthand should be extend(p in query, select: p.title). Will only work when a single variable is bound in the query.

Normalizer and query merger can combine more query expressions

Before we couldn't combine multiple wheres with and in the normalizer because they used different bindings. Now that we don't have named bindings internally we can combine them.

Same goes for order_by etc. order_by and friends can probably be combined in the query merger.

Entity should not be passed to the adapter

All type validation happens at the repo and the adapter should receive the "digested" information. This makes it easy for us to test the adapter with no dependency on the entity.

Implement a mechanism for more robust queries

Today, we can't call:

require Ecto.Query
Ecto.Query.from p in Post, where: p.published_at != nil

Nor can we write:

import Ecto.Query, only: [from: 2]
Ecto.Query.from p in Post, where: p.published_at != nil

We should add a small heuristic:

  1. When we see a keyword, loop __CALLER__.macros looking for an import of that keyword with arity of 3. If one is found, we generate a local call (like today);
  2. If not, call Module.defines? (or something of sorts), looking for a public or private macro with the same name and arity. If one is found, we generate a local call (like today);
  3. If not, generate a full dispatch to Ecto.Query.unquote(keyword).

Notice I have mentioned we should lookup just for macros. I am not sure if we should lookup for functions as well. The reason for not looking up for functions is that they will always raise due to the binding. So it is a matter of automatically ignoring them or using them but letting them fail. Right now, I am more inclined in looking up just for macros.

Add group_by and having query expressions

We keep the semantics close to SQL's.

from(w in Weather,
group_by: w.city,
having: max(w.temp) > 25,
select: { w.city, max(w.temp) }

"""
SELECT w.city, max(w.temp)
FROM weather AS w
GROUP BY w.city
HAVING max(w.temp) > 20
"""

group_by takes a single field or a list of fields. having takes an expression that have to evaluate to a boolean value.

If fields that weren't expressed in the group by and non-aggregate functions appear in the select or having query expression validation will fail.

(Query functions only used here for illustration. Will be introduced in a separate issue.)

Improve internal docs

There are two kinds of documentation. The API documentation and code documentation, for developers working with the code. We are working on the API documentation but the code documentation is non existent.

For example, what is the responsibility of escape in where builder? And in order build? What is the normalization step in the normalizer?

Tip: even if the module has @moduledoc false, we can still add @doc ... clauses to it and it won't show up in exdoc.

from(x in query) should be supported

All those syntaxes are valid:

from(query, limit: 10)
from(x in query, where: x.published_at == nil)
from([x, p] in query, where: ...)

We are going to invoke to Ecto.Queryable on the argument and the number of bindings needs to be less than or equal the bindings on the query.

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.