Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesign metadata and Query Builder #31

Merged
merged 15 commits into from
Apr 2, 2017

Conversation

crbelaus
Copy link
Owner

@crbelaus crbelaus commented Mar 31, 2017

The Trans.QueryBuilder module is one of the main selling points of Trans. It allows easy generation of queries with conditions on translated fields, avoiding the need for joining tables or writing SQL fragments.

The Trans.QueryBuilder module uses a very naive (you may even say flawed) approach for generating and refining queries. Basically it must receive an Ecto.Queryable which will then be refined with extra conditions. This has two main flaws:

  • Queries must be built before being passed to the Trans.QueryBuilder module. Ideally, we want to state the conditions directly when building the query. This way we can use the functions already provided by Ecto.Query for comparisons, etc.
  • Trans.QueryBuilder can only add conditions to the first schema selected in the Ecto.Queryable that it receives. If you want to add conditions to a joined schema, you are out of luck.

This PR fixes those mistakes by rewriting the Trans and Trans.QueryBuilder modules. The changes are:

  • Convenience functions don't exist anymore. When a schema module uses Trans it will only obtain a __trans__/1 function, which provides the metadata required for Trans modules. This avoids adding extra concerns and keeps the schema modules clean.
  • Fields declared as translatable are now validated during compilation time. If a field declared as translatable is not present in the module's struct or schema declaration, Trans will raise an error and abort the compilation.
  • All functions in the Trans.QueryBuilder have been replaced by the Trans.QueryBuilder.translated/2 macro. This macro can be used directly when building an Ecto.Query and generates an SQL fragment that interoperates seamlessly with the rest of functions provided by Ecto.Query.
  • There is not possible anymore for customizing the name of the translation container field. Trans will always look for a translations field. I plan to add this functionality back after this update has been released and tested properly.
  • Improves error messages.

To Do

  • Fix tests. Keep in mind that operator precendce rules changed between Postgres 9.4 and 9.5 or higher. We need to add parentheses around JSONB accessed to avoid troubles.
  • Validate translatable fields
  • Update docs
  • Validate provided fields during query generation. The schema module can be provided to the translated/2 macro and will be used for validating if the required field is among the translatable fields.

When a module uses `Trans`, two underscore functions will be added to provide
the necessary metadata for the `Trans.QueryBuilder` and `Trans.Translator`
functions.

This underscore functions are:
- `__trans__(:container)`, which returns the name of the translation container field.
- `__trans__(:fields)`, which returns a list of the translatable fields.
The translation container customization allowed users to declare an
alternative field (the default was `:translations`) as the field that
contained the translations for the schema.

This customization has been sacrificed to ease the rewrite of the
QueryBuilder module. Now, Trans will always look in the `:translations`
field and there is no way to customize it.
All the functions of the `Trans.QueryBuilder` module have been removed
and replaced with the macro `translated/2`. This macro generates
an SQL Fragment and can be directly used from inside an `Ecto.Query`.

This removes the necessity of building the query before calling the
`Trans.QueryBuilder` functions and integrates seamelessly with
`Ecto.Query` provided functions for comparisons, etc.
This also permits adding conditions on joined schemas.
The QueryBuilder tests have been updated to use the newly introduced
`translated` macro.
The translator module does not require to be passed the name of the
translation container field. The test have also been updated to reflect
this change.
@crbelaus crbelaus self-assigned this Mar 31, 2017
@crbelaus crbelaus force-pushed the issues/28-redesign-query-builder branch 2 times, most recently from 1c4cdb8 to 70e3e2b Compare March 31, 2017 22:13
In PostgreSQL 9.4 [1] the operators had different precedence rules than in
PostgreSQL 9.5 or higher [2] (take a look at "any other operator" in the table.

This differences caused errors when triggering a query that contained something
similar to `where a->b is not null`, which 9.4 would interpret as
`where a->(b is not null)` and 9.5 or higher would interpret as
`where (a->b) is not null`.

This commits adds parentheses around the JSONB accesses to avoid this kind of
problems by stating the desired preference explicitly.

[1] https://www.postgresql.org/docs/9.4/static/sql-syntax-lexical.html
[2] https://www.postgresql.org/docs/9.5/static/sql-syntax-lexical.html
@crbelaus crbelaus force-pushed the issues/28-redesign-query-builder branch from 70e3e2b to e8d0d20 Compare March 31, 2017 22:36
Options provided when using `Trans` are now stored into a module
attribute.
`Trans` will validate the fields declared as translatable and raise an
error during compilation time if they are not declared in the module's
struct or schema definition.
@crbelaus crbelaus changed the title Redesign the Query Builder Redesign metadta and Query Builder Apr 1, 2017
Trans.Translator now validates that whether the field is translatable and
provides a useful error message instead of the default `KeyError`.

Docs have been updated and typespecs added.
The function `Trans.translatable?/2` checks whether a field is
translatable or not.
@crbelaus crbelaus changed the title Redesign metadta and Query Builder Redesign metadata and Query Builder Apr 2, 2017
The macro `Trans.QueryBuilder.translated/3` now validates the translated
fields before the macro expansion step. We will receive an error in
compilation time when adding conditions on untranslatable fields.
@crbelaus crbelaus force-pushed the issues/28-redesign-query-builder branch from 0549fcf to cbb6ba1 Compare April 2, 2017 12:26
@crbelaus
Copy link
Owner Author

crbelaus commented Apr 2, 2017

Ready to be merged 🚀

@crbelaus crbelaus merged commit 5ef7ee4 into releases/2.0.0 Apr 2, 2017
@crbelaus crbelaus deleted the issues/28-redesign-query-builder branch April 2, 2017 16:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant