functions.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. GENERATE_ISSUE_TSVECTOR = """
  2. CREATE OR REPLACE FUNCTION generate_issue_tsvector(jsonb) RETURNS tsvector AS $$
  3. BEGIN
  4. RETURN strip(jsonb_to_tsvector($1, '["string"]'));
  5. EXCEPTION WHEN program_limit_exceeded THEN
  6. RETURN null;
  7. END;
  8. $$ LANGUAGE plpgsql;;
  9. """
  10. # https://stackoverflow.com/a/42998229/443457
  11. JSONB_RECURSIVE_MERGE = """
  12. create or replace function remove_dupes(p_array jsonb)
  13. returns jsonb
  14. as
  15. $$
  16. select jsonb_agg(distinct e)
  17. from jsonb_array_elements(p_array) as t(e);
  18. $$
  19. language sql;
  20. create or replace function jsonb_merge_deep(jsonb, jsonb)
  21. returns jsonb
  22. language sql
  23. immutable
  24. as $func$
  25. select case jsonb_typeof($1)
  26. when 'object' then case jsonb_typeof($2)
  27. when 'object' then (
  28. select jsonb_object_agg(k, case
  29. when e2.v is null then e1.v
  30. when e1.v is null then e2.v
  31. else jsonb_merge_deep(e1.v, e2.v)
  32. end)
  33. from jsonb_each($1) e1(k, v)
  34. full join jsonb_each($2) e2(k, v) using (k)
  35. )
  36. else $2
  37. end
  38. when 'array' then remove_dupes($1 || $2)
  39. else $2
  40. end
  41. $func$;
  42. """
  43. # Limits:
  44. # Don't update search_vector past it's postgresql system limit
  45. # Don't update issue tags (used in filtering) beyond 10MB
  46. UPDATE_ISSUE_INDEX = """
  47. CREATE OR REPLACE FUNCTION concat_tsvector(tsvector, tsvector) RETURNS tsvector AS $$
  48. BEGIN
  49. RETURN $1 || $2;
  50. EXCEPTION WHEN program_limit_exceeded THEN
  51. RETURN $1;
  52. END;
  53. $$ LANGUAGE plpgsql;;
  54. CREATE OR REPLACE FUNCTION collect_tag (jsonb, hstore)
  55. returns jsonb language sql
  56. as $$
  57. SELECT jsonb_merge_deep(jsonb_object_agg(y.key, y.values), $1) FROM (
  58. SELECT (a).key, array_agg(distinct(a).value) as values FROM (
  59. select each($2) as a
  60. ) t GROUP by key
  61. ) y
  62. $$;
  63. CREATE OR REPLACE AGGREGATE agg_collect_tags (hstore) (
  64. sfunc = collect_tag,
  65. stype = jsonb,
  66. initcond = '{}'
  67. );
  68. DROP PROCEDURE IF EXISTS update_issue_index;
  69. CREATE OR REPLACE PROCEDURE update_issue_index(update_issue_id integer)
  70. LANGUAGE SQL
  71. AS $$
  72. WITH event_agg as (
  73. SELECT COUNT(events_event.event_id) as new_count,
  74. MAX(events_event.created) as new_last_seen,
  75. MAX(events_event.level) as new_level,
  76. agg_collect_tags(events_event.tags) as new_tags
  77. FROM events_event
  78. LEFT JOIN issues_issue ON issues_issue.id = events_event.issue_id
  79. WHERE events_event.issue_id=update_issue_id
  80. AND events_event.created > issues_issue.last_seen
  81. ), event_vector as (
  82. SELECT strip(COALESCE(generate_issue_tsvector(data), ''::tsvector)) as vector
  83. FROM events_event
  84. LEFT JOIN issues_issue on issues_issue.id = events_event.issue_id
  85. WHERE events_event.issue_id=update_issue_id
  86. AND events_event.created > issues_issue.last_seen
  87. limit 1
  88. )
  89. UPDATE issues_issue
  90. SET
  91. count = event_agg.new_count + issues_issue.count,
  92. last_seen = GREATEST(event_agg.new_last_seen, issues_issue.last_seen),
  93. level = GREATEST(event_agg.new_level, issues_issue.level),
  94. search_vector = CASE WHEN pg_column_size(COALESCE(search_vector, ''::tsvector)) < 500000 THEN concat_tsvector(COALESCE(search_vector, ''::tsvector), event_vector.vector) ELSE search_vector END,
  95. tags = CASE WHEN pg_column_size(tags) < 10000000 THEN COALESCE(jsonb_merge_deep(event_agg.new_tags, tags), '{}') ELSE tags END
  96. FROM event_agg, event_vector
  97. WHERE issues_issue.id = update_issue_id;
  98. $$;
  99. """