What does HackerNews think of ecto?

A toolkit for data mapping and language integrated query.

Language: Elixir

To me this looks a lot like ecto https://github.com/elixir-ecto/ecto

Is there a significant difference?

May I ask why CouchDB though? Is it for the offline support?

Phoenix comes with its own database tool called Ecto[0] which is excellent, and it uses Postgres by default. If you're not intended to leverage CouchDB for offline support you should go Postgres without a second thought.

That said, I'm also curious about how to implement offline support with Phoenix in a nice and trivial way.

[0] https://github.com/elixir-ecto/ecto

Phoenix apps don't typically use Mnesia; they use a relational database through Ecto [1].

[1]: https://github.com/elixir-ecto/ecto

Ecto the database driver for Phoenix is probably the most amazing piece of software I've used. Elegant dx, performant and just enough of an abstraction on SQL.

[1]: https://github.com/elixir-ecto/ecto

> SQL doesn't compose all that well.

On that topic, I really enjoy working in Elixir because Ecto [1] lets you write "SQL" with Elixir's composable functional syntax. It sits somewhere between "the language is compiled to SQL" and ORM. The Ruby-esque syntax took some getting used to, but once I was past that hurdle my productivity skyrocketed. It's not 100% feature complete compatibility with all the different SQL dialects, but most of what you'll need is there.

[1] https://github.com/elixir-ecto/ecto

For web applications, Phoenix is very popular: https://github.com/phoenixframework/phoenix; it uses some OTP directly and its dependencies like the web-server Cowboy use it as well.

DB development usually uses Ecto: https://github.com/elixir-ecto/ecto, it has OTP servers for connection pooling and other tasks.

For managing background tasks I use Honeydew: https://github.com/koudelka/honeydew

I think Ecto has the best of both worlds (a useful abstraction over SQL and is low level enough) and the right approach:

"Ecto is a toolkit for data mapping and language integrated query for Elixir."

https://github.com/elixir-ecto/ecto

Long ago I liked ActiveRecord(AR), then I worked at a company that did large aggregations in SQL and found it to be severely limited in working with complex queries which use many JOIN statement and sub-queries. During that time I came to enjoy working with the Sequel[0] gem, and its fantastic documentation. Now, after working with Ecto[1] in Elixir, I've found that the ROM[2] builder pattern is a better approach to abstracting SQL and mapping the results to Ruby objects. It's much cleaner and more maintainable than a long mess of AR queries.

Ryan Bigg wrote a great book about breaking away from AR in Rails called Exploding Rails[3]. It's a good read.

[0] http://sequel.jeremyevans.net/

[1] https://github.com/elixir-ecto/ecto

[2] https://rom-rb.org/5.0/learn/introduction/active-record/

[3] https://leanpub.com/explodingrails

So don't map DB records to objects, then. DB records are records, and their proper typing in your business logic is as records—chunks of plain old data, strongly-typed, that your (OO or otherwise) code can declare DB-side interfaces against. The only responsibilities of the module/class that owns the record type, should be getting things converted into and out of that record type.

Plain-old-data DB record types (and their respective owner modules) are to ORMs, as code-gen'ed wire record types (and their respective owner modules) are to ProtoBuf-like wire-format codec libraries. They're the containers you put data into and take it out of, to ensure it's in the right types when being sent to, or received from, your DB. No more than that.

And, corollary to this idea: the POD record-type MyDB.FooTable shouldn't be taken as a type to use to stuff in the results from any random query you run against the DB table `foo`. It should be taken to represent the specific row type that the DB table `foo` has—the one you get when you `SELECT * from foo`. If you do an SQL query, and the result of that SQL query has fewer or extra or differently-typed columns, then the resulting row-set will have a different record type, and so you should have a separate POD data-type that does match these records. (Example: if you join two tables with a query, you don't need the ORM to spit out two records objects with a fancy OO-style relationship between them; you just need one record type that represents the resulting joined rows, without any particular idea that it happens to be an amalgamation of data from two tables.)

For an example of this approach to ORM, see Elixir's https://github.com/elixir-ecto/ecto.

Interesting approach! I've been contemplating a similar query DSL for compressed time-series data on embedded devices. It's easier to make a specialized language than commonly thought. Though generally the trickiest part is creating appropriate tooling for things like source maps, debugging, etc.

It surprises me that the author used Elixir for implementation but didn't just write a query DSL utilizing the Elixir macro facilities [0]. A macro based DSL likely would be much simpler than writing a new grammar and builds on existing language tooling. Ecto for example does a great job (IMHO) of making a sane DSL for SQL [1]. Given data processing primitives provided by Elixir libraries like Streams and GenStage [2] it seems it'd be pretty straightforward to implement.

Take for example the "segmented query path expression". It is handled fine with a minor modification as an Elixir quoted statement:

`quote do: @query_path//foo/goo[instance='a2']/blah/x[a='S 512']/y`

That yields a well defined AST tree base on the Elixir syntax: ``` {:@, [context: Elixir, import: Kernel], [ {:path, [context: Elixir], [ {:/, [context: Elixir, import: Kernel], [ ... ```

The closures work as well by switching the dollar signs to ampersands: `quote do: select(@path/foo/&x/&goo/z/y/w, { value(&1) < 3 })`

Makes me want to write an Ecto adapter for dealing with Elixir Streams. =)

0: https://hackernoon.com/understanding-elixir-macros-3464e1414... 1: https://github.com/elixir-ecto/ecto 2: https://hexdocs.pm/gen_stage/GenStage.html

Elixir's primary database wrapper, Ecto [0], lets you dynamically build queries at runtime, and also isn't an ORM. Here's two examples directly from the docs:

  # Query all rows in the "users" table, filtering for users whose age is > 18, and selecting their name
  "users"
  |> where([u], u.age > 18)
  |> select([u], u.name)

  # Build a dynamic query fragment based on some parameters
  dynamic = false
  
  dynamic =
    if params["is_public"] do
      dynamic([p], p.is_public or ^dynamic)
    else
      dynamic
    end
  
  dynamic =
    if params["allow_reviewers"] do
      dynamic([p, a], a.reviewer == true or ^dynamic)
    else
      dynamic
    end
  
  from "posts", where: ^dynamic
Across all the different means of interacting with a database I have experience with (from full-fledged ORMs like ActiveRecord, to sprocs in ASP.NET), I've found that it offers the best compromise between providing an ergonomic abstraction over the database, and not hiding all of the nitty-gritty details you need to worry about in order to write performant queries or use database-specific features like triggers or window functions.

My main point, though, is that you don't need to reach for NoSQL if all you need is a way to compose queries without string interpolation.

[0] https://github.com/elixir-ecto/ecto

I like the name but there's potential for confusion with Ecto[1]

[1] https://github.com/elixir-ecto/ecto

Curious about your thoughts on Ecto: https://github.com/elixir-ecto/ecto. Seems to be the most popular solution for database access.
Agreed.

In the functional world, there obviously aren't objects and structs are not the same things as objects in the OOP sense.

Even then the key part of a ORM is the "R". ORMs allow you to utilize a RDBMS transparently as if you were manipulating the OOP objects.

A couple of projects that this is closer to than Django ORM.

https://github.com/elixir-ecto/ecto -> "Database Wrapper" http://www.yesodweb.com/book/persistent -> "data store interface" https://hackage.haskell.org/package/groundhog -> "Database Mapping"

Totaly agree. Dialyzer/Dialyxir can provide a high degree of confidence about types.

The wonderful thing about it is that you don't have to get all type annotations since the begining, you can add them over the time. This allows to use "unspecified" types for quick prototyping, and make them more specific when the project evolves, which is a major complain of traditional type systems such as Java's.

Another tool that I find useful is Credo[1] which "is a static code analysis tool for the Elixir language with a focus on teaching and code consistency".

The Ecto[2] project uses a tool called Ebert[3] that automatically runs Credo for each pull-request and comments with the issues found. Here you can see an example of Ebert's bot commenting on a PR[4]

[1] https://github.com/rrrene/credo [2] https://github.com/elixir-ecto/ecto [3] https://ebertapp.io/ [4] https://github.com/elixir-ecto/ecto/pull/1785