Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [unreleased]

### Breaking Changes
- JSON path will now be used in full for virtual fields, instead of being cut off at the first section (for all virtual fields except a list of Maps).
## [0.5.1] - 2025-11-20

### Added
- The `any` predicate has been added for single and virtual fields.
### Bugfixes

### Changed
- Empty `path` now throws an error in most cases. Exception: sub-predicates inside `any`.
- An error will now be correctly raised when unsupported arguments (non-strings) are passed as an argument to String comparators (`like`, `ilike`, `starts_with`, `ends_with`)

## [0.5.0] - 2025-10-31

Expand All @@ -24,11 +21,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `like`, `ilike`, `starts_with` operators now escape `arg` s.t. `%` and `_` characters are not interpreted as
placeholders anymore.
- Field names are now converted to atoms using `String.to_existing_atom/1`, failing for unknown field names.
- JSON path will now be used in full for virtual fields, instead of being cut off at the first section (for all virtual fields except a list of Maps).

### Added

- `not_eq` operator
- `ends_with` operator
- The `any` predicate has been added for single and virtual fields.

### Deprecated

Expand All @@ -39,13 +38,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- `PredicateError`'s message now uses `inspect` on the offending predicate instead of JSON serialization to reduce
library dependencies
- Empty `path` now throws an error in most cases. Exception: sub-predicates inside `any`.

## [0.4.0] - 2025-09-25

### Breaking Changes

- Renamed `Utils` module to `Predicates.Utils` to avoid module name collision

[unreleased]: https://github.com/box-id/ecto_predicates/compare/0.5.0...HEAD
[unreleased]: https://github.com/box-id/ecto_predicates/compare/0.5.1...HEAD
[0.5.1]: https://github.com/box-id/ecto_predicates/compare/0.5.0...0.5.1
[0.5.0]: https://github.com/box-id/ecto_predicates/compare/0.4.0...0.5.0
[0.4.0]: https://github.com/box-id/ecto_predicates/compare/0.3.0...0.4.0
12 changes: 9 additions & 3 deletions lib/utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,13 @@ defmodule Predicates.Utils do
It does not add any wildcards characters to the beginning/end of the input.
"""
@spec search_to_like_pattern(search :: String.t()) :: String.t()
def search_to_like_pattern(search) when is_binary(search) do
String.replace(search, ~r/([%_])/, "\\\\\\1")
end
def search_to_like_pattern(search) when is_binary(search),
do: String.replace(search, ~r/([%_])/, "\\\\\\1")

def search_to_like_pattern(_search),
do:
raise(Predicates.PredicateError,
message:
"Argument is required to be a string for operators 'like/ilike/starts_with/ends_with'."
)
end
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Predicates.MixProject do
def project do
[
app: :ecto_predicates,
version: "0.5.0",
version: "0.5.1",
elixir: "~> 1.15",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
Expand Down
52 changes: 52 additions & 0 deletions test/predicates_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,58 @@ defmodule PredicatesTest do
})
|> Predicates.Repo.all()
end

test "unsupported values for #{op}" do
assert_raise PredicateError,
"Argument is required to be a string for operators 'like/ilike/starts_with/ends_with'.",
fn ->
Converter.build_query(Author, %{
"op" => unquote(op),
"path" => "name",
"arg" => nil
})
end

assert_raise PredicateError,
"Argument is required to be a string for operators 'like/ilike/starts_with/ends_with'.",
fn ->
Converter.build_query(Author, %{
"op" => unquote(op),
"path" => "name",
"arg" => 123
})
end

assert_raise PredicateError,
"Argument is required to be a string for operators 'like/ilike/starts_with/ends_with'.",
fn ->
Converter.build_query(Author, %{
"op" => unquote(op),
"path" => "name",
"arg" => %{"foo" => "bar"}
})
end

assert_raise PredicateError,
"Argument is required to be a string for operators 'like/ilike/starts_with/ends_with'.",
fn ->
Converter.build_query(Author, %{
"op" => unquote(op),
"path" => "name",
"arg" => ["foo", "bar"]
})
end

assert_raise PredicateError,
"Argument is required to be a string for operators 'like/ilike/starts_with/ends_with'.",
fn ->
Converter.build_query(Author, %{
"op" => unquote(op),
"path" => "name",
"arg" => true
})
end
end
end
end

Expand Down