-
Notifications
You must be signed in to change notification settings - Fork 53
Implement values #174
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?
Implement values #174
Conversation
fffc849
to
5ceeb65
Compare
Before you get too deep on this, this is going to clash with anyone that uses with_cte/3 |
Why? Because of the hardcoded Or is there another reason why it could clash with other CTEs? |
5ceeb65
to
cafc720
Compare
Well since you are lifting this into a with cte example. You'll need to make a test that has someone using both |
I'll definitely create a test for that. I think it works based on the already passing tests, but I'm not sure.
This is already proven to work, e.g. this test passes: https://github.com/elixir-ecto/ecto/blob/cd0f70b4cdd949767ea7cbe7d635e70917384b38/integration_test/cases/repo.exs#L2250 Btw, all tests with :values_list are passing, the only one that doesn't pass is this one: https://github.com/elixir-ecto/ecto/blob/cd0f70b4cdd949767ea7cbe7d635e70917384b38/integration_test/cases/repo.exs#L2266 |
I've added a test to see if there is any conflict with I find this surprising as well, so maybe there would still be a more subtle issue with this... |
What does the SQL look like when you render run Like this:
|
integration_test/values_test.exs
Outdated
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.
I think you can shove this into the test/
directory under the connection/
directory as values_test
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.
Inside test/ecto/adapters/sqlite3/connection
?
If I do that I get ** (Exqlite.Error) no such table: posts
. So there is some setup missing there.
Also, I didn't see any other similar tests in that directory, tests that actually operate on a Repo. Only in integration_test/
end | ||
|
||
assert ~s{SELECT s0."id", v1."x" FROM "schema" AS s0 } <> | ||
~s{INNER JOIN (WITH xxx(y, x) AS (VALUES ($1,$2),($3,$4)) SELECT * FROM xxx) AS v1 } <> |
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.
This tests fails with OTP 25, as the order of x, y is swapped in xxx(y, x)
.
This is because types
is a map and therefore unordered.
It's not a bug, since if the order is different here, it will also be different later when passed as parameters. Both orders are correct and lead to the same query.
I'm not sure how to solve this, any idea?
Here is the formatted SQL output of from(p in Post,
right_join: params in values(params, types),
on: params.post_id == p.id,
left_join: c in Comment,
on: c.post_id == p.id and fragment("LENGTH(?)", c.text) > params.n,
group_by: params.id,
select: {params.id, count(c.id)}
) SELECT v1."id",
count(c2."id")
FROM "posts" AS p0
RIGHT OUTER JOIN (
WITH xxx(id, n, post_id) AS (
VALUES ($1, $2, $3),
($4, $5, $6)
)
SELECT *
FROM xxx
) AS v1 ON v1."post_id" = p0."id"
LEFT OUTER JOIN " comments " AS c2 ON (c2." post_id " = p0." id ")
AND (LENGTH(c2." text ") > v1." n ")
GROUP BY v1." id " |
I have tested this PR within my project with my actual use case and it passes all my tests ✔️ |
In the latest commit I changed the hardcoded |
20743a9
to
2054a79
Compare
integration_test/test_helper.exs
Outdated
:values_list | ||
# Run all with tag values_list, except for the "delete_all" test, | ||
# as JOINS are not supported on DELETE statements by SQLite. | ||
{:location, {"ecto/integration_test/cases/repo.exs", 2281}} |
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.
Seems like :location
was not added yet in ExUnit v1.15.
Any idea how we could get this to work with elixir 1.15?
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.
Would it be acceptable to skip all :values_list
if running on Elixir v1.15?
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.
No ideas. But when elixir 1.19 is released, I am dropping support for 1.15. I could drop support for it now since I typically only like to support 3 versions back including current. 1.18, 1.17, 1.16 and otp 28, 27, 26
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.
Ok, in that case I think it makes sense to not run those tests for 1.15. Then you can remove that once you decide to drop support. I've done that in the latest commit
|
||
defp values_expr(types, idx) do | ||
intersperse_reduce(types, ?,, idx, fn {_field, type}, idx -> | ||
{[?$, Integer.to_string(idx), ?:, ?: | column_type(type, nil)], idx + 1} |
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.
I've added the type casting as in the postgres version.
It's probably only needed in a couple of cases, so it might do some unnecessary casting, but I don't think this will hurt.
Without it we were completely ignoring the types that the user supplied, so I think it makes more sense to just always cast.
I think this one is now ready. Sorry for the chaotic start, I was just excited that it worked at all... |
I'll take a look at this soon. I'm gonna check this out and see if I can come up with a breaking use case. It's hard to come up with concrete examples, but I'll see if I can blow it up. Overall, the main point I am having a hard time with is naming the cte selection as |
I've already addressed this in e851684, table names now contain a random number. I did not want to enumerate the variable names, since that would have required introducing state to |
#138
I have no idea what I'm doing, but it seems to actually work and pass some tests!
I just tried to follow https://github.com/elixir-ecto/ecto_sql/blob/v3.13.2/lib/ecto/adapters/postgres.ex and adapt it to use a CTE combined with values as is needed in sqlite to be able to rename the table + the columns.
TODO:
xxx
temporary table name ok? Is there a better way? -> changed to random name