Skip to content

Commit a18ad82

Browse files
committed
Rework JOINs and handling of JOIN tables.
1 parent a54a433 commit a18ad82

File tree

1 file changed

+95
-20
lines changed

1 file changed

+95
-20
lines changed

graphql.sql

Lines changed: 95 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,10 @@ END
135135
$$ LANGUAGE plpgsql STABLE STRICT;
136136

137137
--- Base case (and entry point): looking up a row from a table.
138-
CREATE FUNCTION to_sql(selector regclass, predicate text, body text)
138+
CREATE FUNCTION to_sql(selector regclass,
139+
predicate text,
140+
body text,
141+
label name DEFAULT NULL)
139142
RETURNS text AS $$
140143
DECLARE
141144
q text = '';
@@ -214,6 +217,7 @@ BEGIN
214217
ELSE
215218
q := 'SELECT json_agg(' || column_expression || ')' || q;
216219
END IF;
220+
q := q || format(' AS %I', COALESCE(label, name(tab)));
217221
END;
218222
q := q || format(E'\n FROM %I', tab);
219223
FOR i IN 1..cardinality(subselects) LOOP
@@ -297,7 +301,6 @@ DECLARE
297301
--- If `selector` is a JOIN table, then `okey` is used to store a REFERENCE
298302
--- to the table with the actual data.
299303
okey record;
300-
fks graphql.fk[]; -- Reuses the type defined by the VIEW, below
301304
BEGIN
302305
BEGIN
303306
SELECT * INTO STRICT ikey -- Find the first foreign key in column order
@@ -319,21 +322,19 @@ BEGIN
319322
--- the table that JOINs with us.
320323
IF NOT FOUND AND (SELECT count(1) FROM graphql.fk(selector)) = 2 THEN
321324
SELECT * INTO STRICT okey FROM graphql.fk(selector) WHERE fk != ikey;
322-
q := graphql.to_sql(okey.other, NULL, body);
323-
fks := fks || (okey.other, okey.refs, selector, okey.cols)::graphql.fk;
324-
fks := fks || (selector, ikey.cols, tab, ikey.refs)::graphql.fk;
325+
q := graphql.to_sql(okey.other, NULL, body, name(selector))
326+
|| E'\n ' || graphql.format_join_table_lookup(tab,
327+
ikey.refs,
328+
ikey.cols,
329+
selector,
330+
okey.cols,
331+
okey.refs,
332+
okey.other);
325333
ELSE
326-
q := graphql.to_sql(selector, NULL, body);
327-
fks := fks || (selector, ikey.cols, tab, ikey.refs)::graphql.fk;
334+
q := graphql.to_sql(selector, NULL, body, name(selector))
335+
|| E'\n '
336+
|| graphql.format_join(selector, ikey.cols, tab, ikey.refs, 'join/1');
328337
END IF;
329-
FOR i IN 1..cardinality(fks) LOOP
330-
--- Because there is no predicate, `q` will not have a WHERE clause; so we
331-
--- can concatenate the JOINs to it.
332-
q := q || E'\n ' || graphql.format_join(fks[i].tab,
333-
fks[i].cols,
334-
fks[i].other,
335-
fks[i].refs);
336-
END LOOP;
337338
RETURN q;
338339
END
339340
$$ LANGUAGE plpgsql STABLE;
@@ -439,6 +440,33 @@ RETURNS text AS $$
439440
array_to_string((SELECT array_agg(col) FROM ys), ', '))
440441
$$ LANGUAGE sql STABLE STRICT;
441442

443+
CREATE FUNCTION format_comparison(x name, xs name[], y regclass, ys name[])
444+
RETURNS text AS $$
445+
WITH xs(col) AS (SELECT format('%I.%I', x, col) FROM unnest(xs) AS _(col)),
446+
ys(col) AS (SELECT format('%I.%I', y, col) FROM unnest(ys) AS _(col))
447+
SELECT format('(%s) = (%s)',
448+
array_to_string((SELECT array_agg(col) FROM xs), ', '),
449+
array_to_string((SELECT array_agg(col) FROM ys), ', '))
450+
$$ LANGUAGE sql STABLE STRICT;
451+
452+
CREATE FUNCTION format_comparison(x regclass, xs name[], y name, ys name[])
453+
RETURNS text AS $$
454+
WITH xs(col) AS (SELECT format('%I.%I', x, col) FROM unnest(xs) AS _(col)),
455+
ys(col) AS (SELECT format('%I.%I', y, col) FROM unnest(ys) AS _(col))
456+
SELECT format('(%s) = (%s)',
457+
array_to_string((SELECT array_agg(col) FROM xs), ', '),
458+
array_to_string((SELECT array_agg(col) FROM ys), ', '))
459+
$$ LANGUAGE sql STABLE STRICT;
460+
461+
CREATE FUNCTION format_comparison(x name, xs name[], y name, ys name[])
462+
RETURNS text AS $$
463+
WITH xs(col) AS (SELECT format('%I.%I', x, col) FROM unnest(xs) AS _(col)),
464+
ys(col) AS (SELECT format('%I.%I', y, col) FROM unnest(ys) AS _(col))
465+
SELECT format('(%s) = (%s)',
466+
array_to_string((SELECT array_agg(col) FROM xs), ', '),
467+
array_to_string((SELECT array_agg(col) FROM ys), ', '))
468+
$$ LANGUAGE sql STABLE STRICT;
469+
442470
CREATE FUNCTION format_comparison(x regclass, xs name[], ys jsonb)
443471
RETURNS text AS $$
444472
WITH xs(col) AS (SELECT format('%I.%I', x, col) FROM unnest(xs) AS _(col)),
@@ -451,14 +479,61 @@ RETURNS text AS $$
451479
array_to_string((SELECT array_agg(val) FROM casted), ', '))
452480
$$ LANGUAGE sql STABLE STRICT;
453481

482+
CREATE FUNCTION format_join(tab name, -- When tab is an alias given with AS
483+
cols name[],
484+
other regclass,
485+
refs name[],
486+
label name DEFAULT NULL)
487+
RETURNS text AS $$
488+
SELECT CASE WHEN label IS NULL THEN
489+
format('JOIN %I ON (%s)',
490+
other,
491+
graphql.format_comparison(tab, cols, other, refs))
492+
ELSE
493+
format('JOIN %I AS %I ON (%s)',
494+
other,
495+
label,
496+
graphql.format_comparison(tab, cols, label, refs))
497+
END
498+
$$ LANGUAGE sql STABLE STRICT;
499+
454500
CREATE FUNCTION format_join(tab regclass,
455501
cols name[],
456502
other regclass,
457-
refs name[])
503+
refs name[],
504+
label name DEFAULT NULL)
505+
RETURNS text AS $$
506+
SELECT CASE WHEN label IS NULL THEN
507+
format('JOIN %I ON (%s)',
508+
other,
509+
graphql.format_comparison(tab, cols, other, refs))
510+
ELSE
511+
format('JOIN %I AS %I ON (%s)',
512+
other,
513+
label,
514+
graphql.format_comparison(tab, cols, label, refs))
515+
END
516+
$$ LANGUAGE sql STABLE STRICT;
517+
518+
CREATE FUNCTION format_join_table_lookup(main_table regclass,
519+
main_refs name[],
520+
main_cols name[],
521+
join_table regclass,
522+
data_cols name[],
523+
data_refs name[],
524+
data_table regclass)
458525
RETURNS text AS $$
459-
SELECT format('JOIN %I ON (%s)',
460-
other,
461-
graphql.format_comparison(tab, cols, other, refs))
526+
SELECT graphql.format_join(data_table,
527+
data_refs,
528+
join_table,
529+
data_cols,
530+
'join/1')
531+
|| E'\n '
532+
|| graphql.format_join('join/1',
533+
main_cols,
534+
main_table,
535+
main_refs,
536+
'join/2')
462537
$$ LANGUAGE sql STABLE STRICT;
463538

464-
COMMIT;
539+
END;

0 commit comments

Comments
 (0)