-
Notifications
You must be signed in to change notification settings - Fork 282
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
Support json_agg(column_ref) #1316
base: v0.28
Are you sure you want to change the base?
Support json_agg(column_ref) #1316
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
Open in Stackblitz • kysely_koa_example
commit: |
Since it's likely that people will use this functionality with |
6be68bc
to
63ce1a6
Compare
Co-authored-by: Simon Schick <[email protected]>
Hey 👋 Thanks! 💪
I'll need to think about the helper. You're right about the usage pattern due to nullability.
(eb) => eb.coalesce(eb.jsonAgg("col"), sql<string[]>`[]`) vs. import { someHelper } from 'kysely/helpers/postgres'
(eb) => someHelper(eb.ref("col")) The existing helpers were born out of a LOT of signals from the community needing something after they ditched some ORM and did not know how to do nested stuff with SQL. Regardless, this shouldn't be part of this PR. |
src/query-builder/function-module.ts
Outdated
@@ -696,6 +723,10 @@ export interface FunctionModule<DB, TB extends keyof DB> { | |||
: never | |||
> | |||
|
|||
jsonAgg<RE extends StringReference<DB, TB>>( | |||
column: RE, | |||
): RawBuilder<ExtractTypeFromStringReference<DB, TB, RE>[] | null> |
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.
Why is a RawBuilder
returned here and not AggregateFunctionBuilder
?
By not returning the latter you're stripping downstream capabilities.
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.
e.g. this is valid SQL:
SELECT name,
coalesce(json_agg(laptop.model order by laptop.model DESC) filter (where laptop.model != 'Core 2 Duo'), '[]') as models
from employee
left join laptop on employee.empId = laptop.assignedTo
group by employee.empId;
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.
It's due to my inexperience with this library 😅 Thanks for pointing this out. Should I add a query like this to the tests as well?
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.
It's due to my inexperience with this library 😅
When you're new to a codebase, it's perfectly fine to not get things right the first time.
I'm just asking questions to get a feel for your thought process here.
You either have a good reason for your choice or by asking, I could find something that could be improved, so the next time, it's clearer what the correct choice should be.
Should I add a query like this to the tests as well?
To runtime tests, maybe.
|
||
const r6 = await db | ||
.selectFrom('person') | ||
.select((eb) => [ | ||
'first_name', | ||
eb | ||
.selectFrom('pet') | ||
.select((eb) => [eb.fn.jsonAgg('pet.owner_id').as('pet_names')]) | ||
.whereRef('pet.owner_id', '=', 'person.id') | ||
.as('pet_names'), | ||
]) | ||
.execute() | ||
|
||
expectType< | ||
{ | ||
first_name: string | ||
pet_names: number[] | null | ||
}[] | ||
>(r6) |
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 one doesn't add much value, let's remove it.
const r6 = await db | |
.selectFrom('person') | |
.select((eb) => [ | |
'first_name', | |
eb | |
.selectFrom('pet') | |
.select((eb) => [eb.fn.jsonAgg('pet.owner_id').as('pet_names')]) | |
.whereRef('pet.owner_id', '=', 'person.id') | |
.as('pet_names'), | |
]) | |
.execute() | |
expectType< | |
{ | |
first_name: string | |
pet_names: number[] | null | |
}[] | |
>(r6) |
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.
Could be that this typing-wise doesn't make a difference, but to me this is another use-case. It's using the json-agg in a subquery rather than in a joined table. In a joined table you need a groupBy
, but in a subquery you don't.
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.
Typings tests are there to ensure we got things right on the type-level. Not to document the SQL spec.
The relationship between a root query and its sub-queries has been thoroughly tested elsewhere.
groupBy
doesn't affect anything on the type-level. This test case doesn't add any value here.
Excessive tests mean:
- more stuff to maintain.
- more stuff to wait for locally or in CI.
This could really use a unit test. |
Could you assist me in writing a unit test? What unit do you think should be tested though not to make it an integration test? |
Sure. We could also pair up on this if you want (DM on Discord). We have a suite for aggregate functions, probably there. |
Fixes #1280.
Wow, my first PR in this repo 🤩
If there was something wrong about what I wrote - e.g. if the types are too narrow or wide, please let me know.
Here's what I know about this:
According to the docs, this method does only exist for Postgresql, and I therefore didn't look into any other of the options.