-
Notifications
You must be signed in to change notification settings - Fork 329
Support JSONB operators for shapes #3711
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
base: main
Are you sure you want to change the base?
Changes from all commits
aece8b6
a320e98
e96a313
fdb1c4b
caed062
e993db9
23b4a99
9877390
543a3a8
8224bda
0fe479b
f584616
dc0d82c
dfaae95
fcf4373
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| --- | ||
| '@core/sync-service': patch | ||
| --- | ||
|
|
||
| Add JSONB operators for where clauses: | ||
| - `->` and `->>` for field access (returns JSONB and text respectively) | ||
| - `@>` and `<@` for containment checks | ||
| - `?`, `?|`, and `?&` for key existence checks | ||
|
|
||
| Example shape requests: | ||
|
|
||
| ``` | ||
| # Filter by nested field value | ||
| GET /v1/shapes?table=users&where=(metadata ->> 'status') = 'active' | ||
|
|
||
| # Filter by JSON containment | ||
| GET /v1/shapes?table=orders&where=data @> '{"type": "premium"}' | ||
|
|
||
| # Filter by key existence | ||
| GET /v1/shapes?table=events&where=payload ? 'user_id' | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -151,6 +151,178 @@ defmodule Electric.Replication.Eval.Env.KnownFunctions do | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres("anyenum = anyenum -> bool", delegate: &Kernel.==/2) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres("anyenum <> anyenum -> bool", delegate: &Kernel.!=/2) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## JSONB functions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Parse text to jsonb | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres "jsonb(text) -> jsonb" do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def parse_jsonb(text) when is_binary(text), do: Jason.decode!(text) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Output jsonb as text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres "jsonbout(jsonb) -> text" do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_out(nil), do: nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_out(value), do: Jason.encode!(value) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Get object field or array element as jsonb | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres "jsonb -> text -> jsonb" do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_get_by_key(json, key) when is_map(json) and is_binary(key) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Map.get(json, key) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_get_by_key(_, _), do: nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres "jsonb -> int4 -> jsonb" do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_get_by_index(json, index) when is_list(json) and is_integer(index) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # PostgreSQL uses 0-based indexing for JSON arrays | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Negative indices count from the end (e.g., -1 is last element) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Enum.at(json, index) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_get_by_index(_, _), do: nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+176
to
+184
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Negative index handling does not match PostgreSQL semantics. PostgreSQL's 🐛 Proposed fix defpostgres "jsonb -> int4 -> jsonb" do
def jsonb_get_by_index(json, index) when is_list(json) and is_integer(index) do
- # PostgreSQL uses 0-based indexing for JSON arrays
- # Negative indices count from the end (e.g., -1 is last element)
- Enum.at(json, index)
+ # PostgreSQL uses 0-based indexing for JSON arrays
+ # Negative indices return NULL (unlike Elixir's Enum.at)
+ if index >= 0, do: Enum.at(json, index), else: nil
end
def jsonb_get_by_index(_, _), do: nil
end🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Get object field or array element as text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres "jsonb ->> text -> text" do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_get_text_by_key(json, key) when is_map(json) and is_binary(key) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case Map.get(json, key) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nil -> nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value -> jsonb_value_to_text(value) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_get_text_by_key(_, _), do: nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defp jsonb_value_to_text(value) when is_binary(value), do: value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defp jsonb_value_to_text(value) when is_integer(value), do: Integer.to_string(value) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defp jsonb_value_to_text(value) when is_float(value), do: Float.to_string(value) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defp jsonb_value_to_text(true), do: "true" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defp jsonb_value_to_text(false), do: "false" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defp jsonb_value_to_text(nil), do: nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # For nested objects/arrays, return JSON string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defp jsonb_value_to_text(value), do: Jason.encode!(value) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+186
to
+205
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check all occurrences of jsonb_value_to_text in the file
rg -n "jsonb_value_to_text" packages/sync-service/lib/electric/replication/eval/env/known_functions.ex -B2 -A2Repository: electric-sql/electric Length of output: 798 🏁 Script executed: #!/bin/bash
# Look at the jsonb ->> int4 operator implementation to see if it also uses jsonb_value_to_text
rg -n "jsonb.*int4|int4.*jsonb" packages/sync-service/lib/electric/replication/eval/env/known_functions.ex -A20Repository: electric-sql/electric Length of output: 1521 🏁 Script executed: #!/bin/bash
# Get broader context around lines 190-209 to understand the defpostgres structure
sed -n '180,220p' packages/sync-service/lib/electric/replication/eval/env/known_functions.exRepository: electric-sql/electric Length of output: 1481 Extract the value-to-text conversion logic as a shared module-level helper to avoid duplication. The The PostgreSQL null behavior is correctly implemented: 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres "jsonb ->> int4 -> text" do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_get_text_by_index(json, index) when is_list(json) and is_integer(index) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Negative indices count from the end (e.g., -1 is last element) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| json |> Enum.at(index) |> jsonb_value_to_text() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_get_text_by_index(_, _), do: nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+207
to
+214
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Undefined function: Line 210 calls Additionally, the same negative index issue exists here - the implementation should return NULL for negative indices per PostgreSQL semantics. 🐛 Proposed fix - inline the helper and fix negative index handling defpostgres "jsonb ->> int4 -> text" do
def jsonb_get_text_by_index(json, index) when is_list(json) and is_integer(index) do
- # Negative indices count from the end (e.g., -1 is last element)
- json |> Enum.at(index) |> jsonb_value_to_text()
+ # Negative indices return NULL (PostgreSQL semantics)
+ if index >= 0 do
+ case Enum.at(json, index) do
+ nil -> nil
+ value -> jsonb_value_to_text(value)
+ end
+ else
+ nil
+ end
end
def jsonb_get_text_by_index(_, _), do: nil
+
+ defp jsonb_value_to_text(value) when is_binary(value), do: value
+ defp jsonb_value_to_text(value) when is_integer(value), do: Integer.to_string(value)
+ defp jsonb_value_to_text(value) when is_float(value), do: Float.to_string(value)
+ defp jsonb_value_to_text(true), do: "true"
+ defp jsonb_value_to_text(false), do: "false"
+ defp jsonb_value_to_text(nil), do: nil
+ defp jsonb_value_to_text(value), do: Jason.encode!(value)
endAlternatively, consider extracting 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # JSONB equality | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres("jsonb = jsonb -> bool", delegate: &Kernel.==/2) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres("jsonb <> jsonb -> bool", delegate: &Kernel.!=/2) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # JSONB containment operators | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # @> checks if left contains right, <@ checks if left is contained by right | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres "jsonb @> jsonb -> bool" do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Top-level: Arrays may contain primitive values (special-case in Postgres) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # e.g., '["foo", "bar"]'::jsonb @> '"bar"'::jsonb returns true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # This only applies at the top level, not in recursive array element checks | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_contains?(left, right) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| when is_list(left) and not is_list(right) and not is_map(right) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Enum.member?(left, right) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_contains?(left, right), do: do_jsonb_contains?(left, right) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Objects: all key-value pairs in right must exist in left | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defp do_jsonb_contains?(left, right) when is_map(left) and is_map(right) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Enum.all?(right, fn {key, right_value} -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case Map.fetch(left, key) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {:ok, left_value} -> do_jsonb_contains?(left_value, right_value) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| :error -> false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Arrays: all elements in right must exist somewhere in left | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defp do_jsonb_contains?(left, right) when is_list(left) and is_list(right) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Enum.all?(right, fn right_elem -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Enum.any?(left, fn left_elem -> do_jsonb_contains?(left_elem, right_elem) end) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Scalars: must be equal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defp do_jsonb_contains?(left, right), do: left == right | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # <@ is the inverse of @>: x <@ y is equivalent to y @> x | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres "jsonb <@ jsonb -> bool" do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Top-level: Arrays may contain primitive values (special-case in Postgres) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # For <@, we check if right (container) is an array containing left (primitive) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_contained_by?(left, right) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| when is_list(right) and not is_list(left) and not is_map(left) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Enum.member?(right, left) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_contained_by?(left, right), do: do_jsonb_contained_by?(right, left) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defp do_jsonb_contained_by?(left, right) when is_map(left) and is_map(right) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Enum.all?(right, fn {key, right_value} -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case Map.fetch(left, key) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {:ok, left_value} -> do_jsonb_contained_by?(left_value, right_value) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| :error -> false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defp do_jsonb_contained_by?(left, right) when is_list(left) and is_list(right) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Enum.all?(right, fn right_elem -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Enum.any?(left, fn left_elem -> do_jsonb_contained_by?(left_elem, right_elem) end) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defp do_jsonb_contained_by?(left, right), do: left == right | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # JSONB key existence operators | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ? checks if key exists in object or string exists in array | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres "jsonb ? text -> bool" do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_key_exists?(json, key) when is_map(json) and is_binary(key) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Map.has_key?(json, key) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # For arrays, check if the string exists as a top-level element | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_key_exists?(json, key) when is_list(json) and is_binary(key) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Enum.member?(json, key) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_key_exists?(_, _), do: false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ?| checks if any of the keys exist | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres "jsonb ?| text[] -> bool" do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_any_key_exists?(json, keys) when is_map(json) and is_list(keys) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Enum.any?(keys, &Map.has_key?(json, &1)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_any_key_exists?(json, keys) when is_list(json) and is_list(keys) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key_set = MapSet.new(keys) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Enum.any?(json, &(&1 in key_set)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_any_key_exists?(_, _), do: false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ?& checks if all of the keys exist | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres "jsonb ?& text[] -> bool" do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_all_keys_exist?(json, keys) when is_map(json) and is_list(keys) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Enum.all?(keys, &Map.has_key?(json, &1)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_all_keys_exist?(json, keys) when is_list(json) and is_list(keys) do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key_set = MapSet.new(keys) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Enum.all?(key_set, &Enum.member?(json, &1)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def jsonb_all_keys_exist?(_, _), do: false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+312
to
+324
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Performance inconsistency in The array implementation at lines 292-294 iterates over For consistency with ♻️ Proposed performance improvement def jsonb_all_keys_exist?(json, keys) when is_list(json) and is_list(keys) do
- key_set = MapSet.new(keys)
- Enum.all?(key_set, &Enum.member?(json, &1))
+ json_set = MapSet.new(json)
+ Enum.all?(keys, &MapSet.member?(json_set, &1))
end📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Array functions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres("anyarray = anyarray -> bool", delegate: &Kernel.==/2) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defpostgres("anyarray <> anyarray -> bool", delegate: &Kernel.!=/2) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider adding a language specifier for the code block.
The fenced code block could benefit from a language specifier for better syntax highlighting. Since these are HTTP requests, consider using
httporbash.🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
12-12: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents