135
135
$$ LANGUAGE plpgsql STABLE STRICT;
136
136
137
137
-- - 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 )
139
142
RETURNS text AS $$
140
143
DECLARE
141
144
q text = ' ' ;
@@ -214,6 +217,7 @@ BEGIN
214
217
ELSE
215
218
q := ' SELECT json_agg(' || column_expression || ' )' || q;
216
219
END IF;
220
+ q := q || format(' AS %I' , COALESCE(label, name(tab)));
217
221
END;
218
222
q := q || format(E' \n FROM %I' , tab);
219
223
FOR i IN 1 ..cardinality(subselects) LOOP
@@ -297,7 +301,6 @@ DECLARE
297
301
-- - If `selector` is a JOIN table, then `okey` is used to store a REFERENCE
298
302
-- - to the table with the actual data.
299
303
okey record;
300
- fks graphql .fk []; -- Reuses the type defined by the VIEW, below
301
304
BEGIN
302
305
BEGIN
303
306
SELECT * INTO STRICT ikey -- Find the first foreign key in column order
@@ -319,21 +322,19 @@ BEGIN
319
322
-- - the table that JOINs with us.
320
323
IF NOT FOUND AND (SELECT count (1 ) FROM graphql .fk (selector)) = 2 THEN
321
324
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 );
325
333
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' );
328
337
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;
337
338
RETURN q;
338
339
END
339
340
$$ LANGUAGE plpgsql STABLE;
@@ -439,6 +440,33 @@ RETURNS text AS $$
439
440
array_to_string((SELECT array_agg(col) FROM ys), ' , ' ))
440
441
$$ LANGUAGE sql STABLE STRICT;
441
442
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
+
442
470
CREATE FUNCTION format_comparison (x regclass, xs name[], ys jsonb)
443
471
RETURNS text AS $$
444
472
WITH xs(col) AS (SELECT format(' %I.%I' , x, col) FROM unnest(xs) AS _(col)),
@@ -451,14 +479,61 @@ RETURNS text AS $$
451
479
array_to_string((SELECT array_agg(val) FROM casted), ' , ' ))
452
480
$$ LANGUAGE sql STABLE STRICT;
453
481
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
+
454
500
CREATE FUNCTION format_join (tab regclass,
455
501
cols name[],
456
502
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)
458
525
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' )
462
537
$$ LANGUAGE sql STABLE STRICT;
463
538
464
- COMMIT ;
539
+ END ;
0 commit comments