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

sql.join() for building dynamic queries #807

Open
DanielFGray opened this issue Feb 15, 2024 · 6 comments · May be fixed by #905
Open

sql.join() for building dynamic queries #807

DanielFGray opened this issue Feb 15, 2024 · 6 comments · May be fixed by #905
Labels
enhancement New feature or request

Comments

@DanielFGray
Copy link

DanielFGray commented Feb 15, 2024

postgres.js gives us parameterized tagged templates and the ability to nest sql partials, and this is fantastic, but I think it is missing a piece of the puzzle:

I want to be able concat partials together (that may contain query parameters), usually with some delimiter (eg whitespace, or a comma, or maybe an sql operator)

something like:

sql.join = (a: PendingQuery[] | Helper[], p: PendingQuery): PendingQuery {...}

would be amazing if this were a first-class feature in postgres.js

this should allow things like

let dynamicFilters = [
  sql`somecol = ${somevalue}`,
  sql`col2 = ${v2}`
];
const dynamicColumns = [sql('somecol'), sql('col2')]
await sql`
  select ${sql.join(dynamicColumns, sql`, `)} from t
  where ${sql.join(dynamicFilters, sql` and `)};
`;
@porsager
Copy link
Owner

Yeah, I think it makes sense to add, but I've just been doing this when needed

xs.flatMap((x, i) => i ? [sql`, `, x] : x)

You can fairly quickly make a function to use instead if you feel like it - eg 😋

sql.join = (xs, joiner) => xs.flatMap((x, i) => i ? [joiner, x] : x)

I'll keep the issue open for now.

@porsager porsager added the enhancement New feature or request label Feb 17, 2024
@DanielFGray
Copy link
Author

sql.join = (xs, joiner) => xs.flatMap((x, i) => i ? [joiner, x] : x)

oh interesting! i would never have come up with that on my own

do you have any reservations about adding this as a core feature?

@DanielFGray
Copy link
Author

and if no reservations, would you accept a PR adding this as a core feature?

@davepar
Copy link

davepar commented Jun 7, 2024

It would be great to at least add the work-around to the docs. It wasn't obvious to me how to join sql fragments with a comma. Glad I found this.

@DanielFGray
Copy link
Author

DanielFGray commented Jun 7, 2024

i'm working on a PR

anyone want to bike-shed over join vs concat to avoid confusion with sql joins?
or concat_ws to use actual postgres api 😁

@Destreyf
Copy link

Yeah, I think it makes sense to add, but I've just been doing this when needed

xs.flatMap((x, i) => i ? [sql`, `, x] : x)

You can fairly quickly make a function to use instead if you feel like it - eg 😋

sql.join = (xs, joiner) => xs.flatMap((x, i) => i ? [joiner, x] : x)

I'll keep the issue open for now.

This was insanely helpful, I have a really nested structure so my version is slightly different, and I am monkey patching the sql/database variable.

// Dumb placeholder to shorten code
export type PendingQuery<T extends postgres.Row = postgres.Row> =
  postgres.PendingQuery<T[]>;

// Hack to add the "join" method.
export type sql = ReturnType<typeof postgres> & {
  join: (a: Array<PendingQuery | null>, b: PendingQuery) => PendingQuery;
};

const db = postgres(config) as sql;

db["join"] = (fragments: (PendingQuery | null)[], joiner: PendingQuery) =>
  fragments.flatMap((x, i) => {
    if (!i) return x;

    if (Array.isArray(x)) {
      // already an array, means we're nested, so lets spread it
      return [joiner, ...x];
    }

    return [joiner, x];
  }) as unknown as PendingQuery;

It's typescript, but you can strip the types and it should work, usage is:

db.join([
  db`name = 'test1'`,
  db`name = 'test2'`,
  db`name = 'test3'`,
  db.join([
    db`updated_at >= 2024-01-01`,
    db`updated_at <= '2024-12-31`
  ],db`AND`)
], db`OR`)

Hopefully this can make it into somewhere in the codebase as it's super useful for report building.

@DanielFGray hopefully this code can help if you haven't figured out this part.

@DanielFGray DanielFGray linked a pull request Jun 27, 2024 that will close this issue
@porsager porsager changed the title postgres.js needs something like slonik's sql.join() for building dynamic queries sql.join() for building dynamic queries Jun 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants