honeysql

itaied 2025-02-19T09:58:28.678989Z

does honeysql support XTDB assert?

ASSERT NOT EXISTS (SELECT 1 FROM users WHERE email = '')

INSERT INTO users (_id, name, email) VALUES ('james', 'James', '')

p-himik 2025-02-19T11:15:56.320729Z

Is it a single statement with assert and insert? Or two separate statements? If it's the former and the semantics is "insert if it doesn't exist", then I'm very surprised they decided to create a custom syntax for it instead of just using a CTE.

p-himik 2025-02-19T11:54:16.478389Z

Since it's a top-level clause, I don't think there's anything built into HoneySQL that would result in that query, apart from :raw maybe. But it's trivial to add on your end with honey.sql/register-clause!.

itaied 2025-02-19T12:08:49.683059Z

it is displayed as a single statement but actually to run it i had to concat the statements with ;

(jdbc/execute! conn [(str "assert (select count(*) from test_03 where name = 'unique3') < 1;"
                            "insert into test_03 (_id, name) values (05, 'unique3');")])
i will take a look at register-clause, thanks!

refset 2025-02-19T12:33:22.119779Z

> I'm very surprised they decided to create a custom syntax for it instead of just using a CTE This is an interesting observation, thank you for mentioning it. Right now XTDB doesn't support CTEs as part of INSERT statements, but it definitely could 🤔 In any case the explicit ASSERT statement is intended as a useful primitive in its own right as it gives stronger guarantees around failure, which are needed because XTDB doesn't support interactive transactions. Therefore it's quite handy if you want the entire transaction to fail, rather than silently skip over a single statement. Does that make sense? /cc @jarohen

p-himik 2025-02-19T12:42:30.145359Z

Yeah, if it's a separate statement then there's no surprise on my side. :) FWIW, I personally still wouldn't add a separate clause that's not SQL-compliant (well, AFAIK). Instead, I'd use some function that throws, like SELECT throw('The email already exists') FROM users WHERE email = '...', which also has a benefit of providing a friendly text message and using any data from the offending rows.

🙏 1
jarohen 2025-02-19T12:50:11.487289Z

yes, separating by semi-colon is expected - we'll then create an implicit transaction for you (as Postgres does too)

jarohen 2025-02-19T12:51:00.807959Z

you can also do this explicitly with next.jdbc's transaction API, or simply wrap it in BEGIN/COMMIT (again, all same as Postgres)

jarohen 2025-02-19T12:57:15.367299Z

@seancorfield has very kindly added https://github.com/seancorfield/honeysql/blob/develop/doc/xtdb.md of support for XTDB extensions, I'm sure he'd accept a patch for ASSERT too 🙂

jarohen 2025-02-19T13:00:50.216419Z

@itai I'd probably go for ASSERT NOT EXISTS (SELECT 1 FROM ...) in your case 🙂 slight perf improvement through not having to count the rows

seancorfield 2025-02-19T17:44:32.610349Z

Feel free to create GH issues for any XTDB syntax that is not currently supported. I prefer to have issues first, with PRs following. PRs should include tests and doc updates as well (so a lot of folks create an issue and leave it at that, for me to write tests and docs 🙂 ).

seancorfield 2025-02-19T17:45:07.898189Z

(and please link to XTDB docs for any missing syntax so I know what HoneySQL is supposed to do!)

seancorfield 2025-02-19T17:47:24.574929Z

HoneySQL has no support for ;-separated statements either (because it's generally discouraged by most database drivers), but having a helper function to merge across multiple honey.sql/format results would be a reasonable addition (GH issue welcome for that too).

jarohen 2025-02-19T19:15:18.329789Z

yeah, Postgres JDBC driver doesn't really support it, it splits them apart. thinking about the issue for the ASSERT support, reckon that's a good first issue for someone looking to contribute to honeysql 🙂

seancorfield 2025-02-21T01:20:50.709429Z

The latest snapshot (and git deps) has support for ASSERT. And IS DISTINCT FROM / IS NOT DISTINCT FROM which was another recently requested addition. I have not (yet) added a helper to merge multiple sql+params vectors for the multi-statement case but I'm about to create a ticket for that too.

seancorfield 2025-02-21T05:37:19.345509Z

And now I've added semicolon to merge multiple SQL+params vectors. Ugh! 🙂 But (sql/semicolon (sql/format {:assert ...}) (sql/format {:insert-into ...})) should give you what you need @itai

🙏 1
🙌 1