How do I add CYCLE id SET is_cycle USING cycle_path in the query to avoid cycle in recursive query
{:with-recursive
[[:employee-rl
{:union-all
[{:select [:id [(utils-sql-casts/as-jsonb-array [:array []]) :reporting-line]]
:from [:employees]
:where [:= :manager 123]}
{:select [:rem.id
[[:array_prepend [:jsonb_build_object
"employee-id", :rem.manager]
:er.reporting-line]]]
:from [[:employees :rem]]
:inner-join [[:employee-rl :er] [:= :rem.manager :er.id]]}]}]]
:select [:ejr.employee-id
[[:array_to_json :erl.reporting-line] :reporting-line]]
:from [[:employees :e]]
:inner-join [[:employee-rl :erl] [:= :e.id :erl.id]]}
I tried adding it using raw
(honey.sql/format
{:with-recursive
[[:employee-rl
{:union-all
[{:select [:id [(utils-sql-casts/as-jsonb-array [:array []]) :reporting-line]]
:from [:employees]
:where [:= :manager 123]}
{:select [:rem.id
[[:array_prepend [:jsonb_build_object
"employee-id", :rem.manager]
:er.reporting-line]]]
:from [[:employees :rem]]
:inner-join [[:employee-rl :er] [:= :rem.manager :er.id]]}]}]]
:raw ["CYCLE id SET is_cycle USING cycle_path"]
:select [:ejr.employee-id
[[:array_to_json :erl.reporting-line] :reporting-line]]
:from [[:employees :e]]
:inner-join [[:employee-rl :erl] [:= :e.id :erl.id]]}
{:inline true})
But this generates unexpected output
CYCLE id SET is_cycle USING cycle_path WITH RECURSIVE employee_rl AS (
SELECT
id,
CAST(ARRAY[] AS jsonb[]) AS reporting_line FROM employees
WHERE
manager = 123
UNION ALL
SELECT
rem.id,
ARRAY_PREPEND(JSONB_BUILD_OBJECT('employee-id', rem.manager), er.reporting_line)
FROM
employees AS rem
INNER JOIN employee_rl AS er ON rem.manager = er.id
)
SELECT
ejr.employee_id,
ARRAY_TO_JSON(erl.reporting_line) AS reporting_line
FROM
employees AS e
INNER JOIN employee_rl AS erl ON e.id = erl.id
Where should i place the raw query to generate the output
WITH RECURSIVE employee_rl AS (
SELECT
id,
CAST(ARRAY[] AS jsonb[]) AS reporting_line
FROM
employees
WHERE
manager = 123
UNION ALL
SELECT
rem.id,
ARRAY_PREPEND(JSONB_BUILD_OBJECT('employee-id', rem.manager), er.reporting_line)
FROM
employees AS rem
INNER JOIN employee_rl AS er ON rem.manager = er.id) CYCLE id SET is_cycle USING cycle_path
SELECT
ejr.employee_id, ARRAY_TO_JSON(erl.reporting_line) AS reporting_line FROM employees AS e
INNER JOIN employee_rl AS erl ON e.id = erl.idI am using postgresql version 14 so CYCLE is supported
Given the current impl of :with and :with-recursive, it doesn't seem like you can do that without creating your own clause.
E.g. you can override :with with a formatter that accepts not two items but three, with the last optional one dictating CYCLE.
But that's a decent amount of work, especially given that format-with is private.
So it seems to be that the best approach would be to extend HoneySQL itself so that :with accepts three parts.
And, of course, the third part should not be hard-coded to support only CYCLE. PostgreSQL supports also SEARCH and maybe other DBMS's support other clauses.
@seancorfield Checked all the other databases that I know of - only PostgreSQL seems to support extra settings in CTEs, and only for WITH RECURSIVE.
It's not hard to extend honey.sql/format-with so it has [x expr extra :as with] instead of [x expr :as with]. But I don't know how best to process that extra.
If CYCLE and SEARCH (the only two things supported by PostgreSQL in that context) are used with function-like syntax it will break any code that already uses :cycle or :search as functions.
If they're made into proper SQL clauses akin to :select, it might also be confusing and potentially conflicting with other DBs.
Maybe it makes sense to register functions like :pg/cycle and :pg/search?
One of you please create a GH issue with links to the relevant PG docs (since I don't use PG), and I'll take a look...
@p-himik Thank you for your effort and time
@jabhi207 The solution I've implemented for issue 542 would support {:with-recursive [[:employee-rl {:union-all ...} :cycle :id :set :is-cycle :using :cycle-path]]}