@pgflow/core 0.0.5-prealpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/LICENSE.md +660 -0
  2. package/README.md +373 -0
  3. package/__tests__/mocks/index.ts +1 -0
  4. package/__tests__/mocks/postgres.ts +37 -0
  5. package/__tests__/types/PgflowSqlClient.test-d.ts +59 -0
  6. package/dist/LICENSE.md +660 -0
  7. package/dist/README.md +373 -0
  8. package/dist/index.js +54 -0
  9. package/docs/options_for_flow_and_steps.md +75 -0
  10. package/docs/pgflow-blob-reference-system.md +179 -0
  11. package/eslint.config.cjs +22 -0
  12. package/example-flow.mermaid +5 -0
  13. package/example-flow.svg +1 -0
  14. package/flow-lifecycle.mermaid +83 -0
  15. package/flow-lifecycle.svg +1 -0
  16. package/out-tsc/vitest/__tests__/mocks/index.d.ts +2 -0
  17. package/out-tsc/vitest/__tests__/mocks/index.d.ts.map +1 -0
  18. package/out-tsc/vitest/__tests__/mocks/postgres.d.ts +15 -0
  19. package/out-tsc/vitest/__tests__/mocks/postgres.d.ts.map +1 -0
  20. package/out-tsc/vitest/__tests__/types/PgflowSqlClient.test-d.d.ts +2 -0
  21. package/out-tsc/vitest/__tests__/types/PgflowSqlClient.test-d.d.ts.map +1 -0
  22. package/out-tsc/vitest/tsconfig.spec.tsbuildinfo +1 -0
  23. package/out-tsc/vitest/vite.config.d.ts +3 -0
  24. package/out-tsc/vitest/vite.config.d.ts.map +1 -0
  25. package/package.json +28 -0
  26. package/pkgs/core/dist/index.js +54 -0
  27. package/pkgs/core/dist/pkgs/core/LICENSE.md +660 -0
  28. package/pkgs/core/dist/pkgs/core/README.md +373 -0
  29. package/pkgs/dsl/dist/index.js +123 -0
  30. package/pkgs/dsl/dist/pkgs/dsl/README.md +11 -0
  31. package/project.json +125 -0
  32. package/prompts/architect.md +87 -0
  33. package/prompts/condition.md +33 -0
  34. package/prompts/declarative_sql.md +15 -0
  35. package/prompts/deps_in_payloads.md +20 -0
  36. package/prompts/dsl-multi-arg.ts +48 -0
  37. package/prompts/dsl-options.md +39 -0
  38. package/prompts/dsl-single-arg.ts +51 -0
  39. package/prompts/dsl-two-arg.ts +61 -0
  40. package/prompts/dsl.md +119 -0
  41. package/prompts/fanout_steps.md +1 -0
  42. package/prompts/json_schemas.md +36 -0
  43. package/prompts/one_shot.md +286 -0
  44. package/prompts/pgtap.md +229 -0
  45. package/prompts/sdk.md +59 -0
  46. package/prompts/step_types.md +62 -0
  47. package/prompts/versioning.md +16 -0
  48. package/queries/fail_permanently.sql +17 -0
  49. package/queries/fail_task.sql +21 -0
  50. package/queries/sequential.sql +47 -0
  51. package/queries/two_roots_left_right.sql +59 -0
  52. package/schema.svg +1 -0
  53. package/scripts/colorize-pgtap-output.awk +72 -0
  54. package/scripts/run-test-with-colors +5 -0
  55. package/scripts/watch-test +7 -0
  56. package/src/PgflowSqlClient.ts +85 -0
  57. package/src/database-types.ts +759 -0
  58. package/src/index.ts +3 -0
  59. package/src/types.ts +103 -0
  60. package/supabase/config.toml +32 -0
  61. package/supabase/migrations/000000_schema.sql +150 -0
  62. package/supabase/migrations/000005_create_flow.sql +29 -0
  63. package/supabase/migrations/000010_add_step.sql +48 -0
  64. package/supabase/migrations/000015_start_ready_steps.sql +45 -0
  65. package/supabase/migrations/000020_start_flow.sql +46 -0
  66. package/supabase/migrations/000030_read_with_poll_backport.sql +70 -0
  67. package/supabase/migrations/000040_poll_for_tasks.sql +100 -0
  68. package/supabase/migrations/000045_maybe_complete_run.sql +30 -0
  69. package/supabase/migrations/000050_complete_task.sql +98 -0
  70. package/supabase/migrations/000055_calculate_retry_delay.sql +11 -0
  71. package/supabase/migrations/000060_fail_task.sql +124 -0
  72. package/supabase/migrations/000_edge_worker_initial.sql +86 -0
  73. package/supabase/seed.sql +202 -0
  74. package/supabase/tests/add_step/basic_step_addition.test.sql +29 -0
  75. package/supabase/tests/add_step/circular_dependency.test.sql +21 -0
  76. package/supabase/tests/add_step/flow_isolation.test.sql +26 -0
  77. package/supabase/tests/add_step/idempotent_step_addition.test.sql +20 -0
  78. package/supabase/tests/add_step/invalid_step_slug.test.sql +16 -0
  79. package/supabase/tests/add_step/nonexistent_dependency.test.sql +16 -0
  80. package/supabase/tests/add_step/nonexistent_flow.test.sql +13 -0
  81. package/supabase/tests/add_step/options.test.sql +66 -0
  82. package/supabase/tests/add_step/step_with_dependency.test.sql +36 -0
  83. package/supabase/tests/add_step/step_with_multiple_dependencies.test.sql +46 -0
  84. package/supabase/tests/complete_task/archives_message.test.sql +67 -0
  85. package/supabase/tests/complete_task/completes_run_if_no_more_remaining_steps.test.sql +62 -0
  86. package/supabase/tests/complete_task/completes_task_and_updates_dependents.test.sql +64 -0
  87. package/supabase/tests/complete_task/decrements_remaining_steps_if_completing_step.test.sql +62 -0
  88. package/supabase/tests/complete_task/saves_output_when_completing_run.test.sql +57 -0
  89. package/supabase/tests/create_flow/flow_creation.test.sql +27 -0
  90. package/supabase/tests/create_flow/idempotency_and_duplicates.test.sql +26 -0
  91. package/supabase/tests/create_flow/invalid_slug.test.sql +13 -0
  92. package/supabase/tests/create_flow/options.test.sql +57 -0
  93. package/supabase/tests/fail_task/exponential_backoff.test.sql +70 -0
  94. package/supabase/tests/fail_task/mark_as_failed_if_no_retries_available.test.sql +49 -0
  95. package/supabase/tests/fail_task/respects_flow_retry_settings.test.sql +48 -0
  96. package/supabase/tests/fail_task/respects_step_retry_settings.test.sql +48 -0
  97. package/supabase/tests/fail_task/retry_task_if_retries_available.test.sql +39 -0
  98. package/supabase/tests/is_valid_slug.test.sql +72 -0
  99. package/supabase/tests/poll_for_tasks/builds_proper_input_from_deps_outputs.test.sql +35 -0
  100. package/supabase/tests/poll_for_tasks/hides_messages.test.sql +35 -0
  101. package/supabase/tests/poll_for_tasks/increments_attempts_count.test.sql +35 -0
  102. package/supabase/tests/poll_for_tasks/multiple_task_processing.test.sql +24 -0
  103. package/supabase/tests/poll_for_tasks/polls_only_queued_tasks.test.sql +35 -0
  104. package/supabase/tests/poll_for_tasks/reads_messages.test.sql +38 -0
  105. package/supabase/tests/poll_for_tasks/returns_no_tasks_if_no_step_task_for_message.test.sql +34 -0
  106. package/supabase/tests/poll_for_tasks/returns_no_tasks_if_queue_is_empty.test.sql +19 -0
  107. package/supabase/tests/poll_for_tasks/returns_no_tasks_when_qty_set_to_0.test.sql +22 -0
  108. package/supabase/tests/poll_for_tasks/sets_vt_delay_based_on_opt_timeout.test.sql +41 -0
  109. package/supabase/tests/poll_for_tasks/tasks_reapppear_if_not_processed_in_time.test.sql +59 -0
  110. package/supabase/tests/start_flow/creates_run.test.sql +24 -0
  111. package/supabase/tests/start_flow/creates_step_states_for_all_steps.test.sql +25 -0
  112. package/supabase/tests/start_flow/creates_step_tasks_only_for_root_steps.test.sql +54 -0
  113. package/supabase/tests/start_flow/returns_run.test.sql +24 -0
  114. package/supabase/tests/start_flow/sends_messages_on_the_queue.test.sql +50 -0
  115. package/supabase/tests/start_flow/starts_only_root_steps.test.sql +21 -0
  116. package/supabase/tests/step_dsl_is_idempotent.test.sql +34 -0
  117. package/tsconfig.json +16 -0
  118. package/tsconfig.lib.json +26 -0
  119. package/tsconfig.spec.json +35 -0
  120. package/vite.config.ts +57 -0
@@ -0,0 +1,47 @@
1
+ begin;
2
+
3
+ select pgflow_tests.reset_db();
4
+ select pgflow_tests.setup_flow('sequential');
5
+
6
+ select pgflow.start_flow('sequential', '"hello"'::jsonb);
7
+ select * from pgflow.step_states;
8
+ select * from pgflow.step_tasks;
9
+
10
+ select * from pgflow.poll_for_tasks('sequential', 1, 1);
11
+ select * from pgflow.step_states;
12
+ select * from pgflow.step_tasks;
13
+
14
+ select pgflow.complete_task(
15
+ (select run_id from pgflow.runs limit 1),
16
+ 'first',
17
+ 0,
18
+ '"first completed"'::jsonb
19
+ );
20
+ select * from pgflow.step_states;
21
+ select * from pgflow.step_tasks;
22
+
23
+ select * from pgflow.poll_for_tasks('sequential', 1, 1);
24
+
25
+ select pgflow.complete_task(
26
+ (select run_id from pgflow.runs limit 1),
27
+ 'second',
28
+ 0,
29
+ '"second completed"'::jsonb
30
+ );
31
+ select * from pgflow.step_states;
32
+ select * from pgflow.step_tasks;
33
+
34
+ select * from pgflow.poll_for_tasks('sequential', 1, 1);
35
+
36
+ select pgflow.complete_task(
37
+ (select run_id from pgflow.runs limit 1),
38
+ 'last',
39
+ 0,
40
+ '"last completed"'::jsonb
41
+ );
42
+ select * from pgflow.step_states;
43
+ select * from pgflow.step_tasks;
44
+
45
+ select * from pgflow.runs;
46
+
47
+ rollback;
@@ -0,0 +1,59 @@
1
+ \x
2
+ begin;
3
+
4
+ select pgflow_tests.reset_db();
5
+ select pgflow_tests.setup_flow('two_roots_left_right');
6
+
7
+ select pgflow.start_flow('two_roots_left_right', '"hello"'::jsonb);
8
+ select pgflow.poll_for_tasks('two_roots_left_right', 1, 1);
9
+ select pgflow.complete_task(
10
+ (select run_id from pgflow.runs limit 1),
11
+ 'connected_root',
12
+ 0,
13
+ '"connected_root completed"'::jsonb
14
+ );
15
+ select pgflow.poll_for_tasks('two_roots_left_right', 1, 1);
16
+ select pgflow.complete_task(
17
+ (select run_id from pgflow.runs limit 1),
18
+ 'left',
19
+ 0,
20
+ '"left completed"'::jsonb
21
+ );
22
+ select * from pgflow.step_tasks;
23
+ select pgflow.poll_for_tasks('two_roots_left_right', 1, 1);
24
+ select pgflow.complete_task(
25
+ (select run_id from pgflow.runs limit 1),
26
+ 'disconnected_root',
27
+ 0,
28
+ '"disconnected_root completed"'::jsonb
29
+ );
30
+ select pgflow.poll_for_tasks('two_roots_left_right', 1, 1);
31
+ -- select pgflow.complete_task(
32
+ -- (select run_id from pgflow.runs limit 1),
33
+ -- 'right',
34
+ -- 0,
35
+ -- '"right completed"'::jsonb
36
+ -- );
37
+ select pgflow.fail_task(
38
+ (select run_id from pgflow.runs limit 1),
39
+ 'right',
40
+ 0,
41
+ 'invalid http request'
42
+ );
43
+ select pgflow.fail_task(
44
+ (select run_id from pgflow.runs limit 1),
45
+ 'right',
46
+ 0,
47
+ 'invalid http request'
48
+ );
49
+ select pgflow.fail_task(
50
+ (select run_id from pgflow.runs limit 1),
51
+ 'right',
52
+ 0,
53
+ 'invalid http request'
54
+ );
55
+
56
+ select * from pgflow.runs;
57
+ select * from pgflow.step_tasks;
58
+ select * from pgflow.step_states;
59
+ rollback;
package/schema.svg ADDED
@@ -0,0 +1 @@
1
+ <svg aria-roledescription="er" role="graphics-document document" viewBox="0 0 449.7414245605469 982" style="max-width: 449.741px; background-color: white;" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="100%" id="my-svg"><style>#my-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#my-svg .error-icon{fill:#552222;}#my-svg .error-text{fill:#552222;stroke:#552222;}#my-svg .edge-thickness-normal{stroke-width:1px;}#my-svg .edge-thickness-thick{stroke-width:3.5px;}#my-svg .edge-pattern-solid{stroke-dasharray:0;}#my-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#my-svg .edge-pattern-dashed{stroke-dasharray:3;}#my-svg .edge-pattern-dotted{stroke-dasharray:2;}#my-svg .marker{fill:#333333;stroke:#333333;}#my-svg .marker.cross{stroke:#333333;}#my-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#my-svg p{margin:0;}#my-svg .entityBox{fill:#ECECFF;stroke:#9370DB;}#my-svg .attributeBoxOdd{fill:#ffffff;stroke:#9370DB;}#my-svg .attributeBoxEven{fill:#f2f2f2;stroke:#9370DB;}#my-svg .relationshipLabelBox{fill:hsl(80, 100%, 96.2745098039%);opacity:0.7;background-color:hsl(80, 100%, 96.2745098039%);}#my-svg .relationshipLabelBox rect{opacity:0.5;}#my-svg .relationshipLine{stroke:#333333;}#my-svg .entityTitleText{text-anchor:middle;font-size:18px;fill:#333;}#my-svg #MD_PARENT_START{fill:#f5f5f5!important;stroke:#333333!important;stroke-width:1;}#my-svg #MD_PARENT_END{fill:#f5f5f5!important;stroke:#333333!important;stroke-width:1;}#my-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g/><defs><marker orient="auto" markerHeight="240" markerWidth="190" refY="7" refX="0" id="MD_PARENT_START"><path d="M 18,7 L9,13 L1,7 L9,1 Z"/></marker></defs><defs><marker orient="auto" markerHeight="28" markerWidth="20" refY="7" refX="19" id="MD_PARENT_END"><path d="M 18,7 L9,13 L1,7 L9,1 Z"/></marker></defs><defs><marker orient="auto" markerHeight="18" markerWidth="18" refY="9" refX="0" id="ONLY_ONE_START"><path d="M9,0 L9,18 M15,0 L15,18" fill="none" stroke="gray"/></marker></defs><defs><marker orient="auto" markerHeight="18" markerWidth="18" refY="9" refX="18" id="ONLY_ONE_END"><path d="M3,0 L3,18 M9,0 L9,18" fill="none" stroke="gray"/></marker></defs><defs><marker orient="auto" markerHeight="18" markerWidth="30" refY="9" refX="0" id="ZERO_OR_ONE_START"><circle r="6" cy="9" cx="21" fill="white" stroke="gray"/><path d="M9,0 L9,18" fill="none" stroke="gray"/></marker></defs><defs><marker orient="auto" markerHeight="18" markerWidth="30" refY="9" refX="30" id="ZERO_OR_ONE_END"><circle r="6" cy="9" cx="9" fill="white" stroke="gray"/><path d="M21,0 L21,18" fill="none" stroke="gray"/></marker></defs><defs><marker orient="auto" markerHeight="36" markerWidth="45" refY="18" refX="18" id="ONE_OR_MORE_START"><path d="M0,18 Q 18,0 36,18 Q 18,36 0,18 M42,9 L42,27" fill="none" stroke="gray"/></marker></defs><defs><marker orient="auto" markerHeight="36" markerWidth="45" refY="18" refX="27" id="ONE_OR_MORE_END"><path d="M3,9 L3,27 M9,18 Q27,0 45,18 Q27,36 9,18" fill="none" stroke="gray"/></marker></defs><defs><marker orient="auto" markerHeight="36" markerWidth="57" refY="18" refX="18" id="ZERO_OR_MORE_START"><circle r="6" cy="18" cx="48" fill="white" stroke="gray"/><path d="M0,18 Q18,0 36,18 Q18,36 0,18" fill="none" stroke="gray"/></marker></defs><defs><marker orient="auto" markerHeight="36" markerWidth="57" refY="18" refX="39" id="ZERO_OR_MORE_END"><circle r="6" cy="18" cx="9" fill="white" stroke="gray"/><path d="M21,18 Q39,0 57,18 Q39,36 21,18" fill="none" stroke="gray"/></marker></defs><path style="stroke: gray; fill: none;" marker-start="url(#ONLY_ONE_START)" marker-end="url(#ZERO_OR_MORE_END)" d="M160.633,128L150.532,136.333C140.43,144.667,120.226,161.333,110.125,178C100.023,194.667,100.023,211.333,100.023,219.667L100.023,228" class="er relationshipLine"/><path style="stroke: gray; fill: none;" marker-start="url(#ONLY_ONE_START)" marker-end="url(#ZERO_OR_MORE_END)" d="M68.473,399L65.398,407.333C62.323,415.667,56.173,432.333,58.531,454.25C60.89,476.167,71.756,503.333,77.19,516.917L82.623,530.5" class="er relationshipLine"/><path style="stroke: gray; fill: none;" marker-start="url(#ONLY_ONE_START)" marker-end="url(#ZERO_OR_MORE_END)" d="M148.023,399L152.701,407.333C157.379,415.667,166.736,432.333,163.148,454.25C159.56,476.167,143.028,503.333,134.761,516.917L126.495,530.5" class="er relationshipLine"/><path style="stroke: gray; fill: none;" marker-start="url(#ONLY_ONE_START)" marker-end="url(#ZERO_OR_MORE_END)" d="M291.552,128L301.654,136.333C311.756,144.667,331.959,161.333,342.061,179.75C352.163,198.167,352.163,218.333,352.163,228.417L352.163,238.5" class="er relationshipLine"/><path style="stroke: gray; fill: none;" marker-start="url(#ONLY_ONE_START)" marker-end="url(#ZERO_OR_MORE_END)" d="M352.163,388.5L352.163,398.583C352.163,408.667,352.163,428.833,352.163,447.25C352.163,465.667,352.163,482.333,352.163,490.667L352.163,499" class="er relationshipLine"/><path style="stroke: gray; fill: none;" marker-start="url(#ONLY_ONE_START)" marker-end="url(#ZERO_OR_MORE_END)" d="M352.163,649L352.163,657.333C352.163,665.667,352.163,682.333,352.163,699C352.163,715.667,352.163,732.333,352.163,740.667L352.163,749" class="er relationshipLine"/><g transform="translate(153.99402618408203,20 )" id="entity-flows-f18f0530-88df-544b-a742-e42ede14479d"><rect height="108" width="144.19744873046875" y="0" x="0" class="er entityBox"/><text style="dominant-baseline: middle; text-anchor: middle; font-size: 12px;" transform="translate(72.09872436523438,12)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d" class="er entityLabel">flows</text><rect height="21" width="26.5899658203125" y="24" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,34.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-1-type" class="er entityLabel">text</text><rect height="21" width="93.8125" y="24" x="26.5899658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,34.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-1-name" class="er entityLabel">flow_slug</text><rect height="21" width="23.79498291015625" y="24" x="120.4024658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,34.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-1-key" class="er entityLabel">PK</text><rect height="21" width="26.5899658203125" y="45" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,55.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-2-type" class="er entityLabel">int</text><rect height="21" width="93.8125" y="45" x="26.5899658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,55.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-2-name" class="er entityLabel">opt_max_attempts</text><rect height="21" width="23.79498291015625" y="45" x="120.4024658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,55.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-2-key" class="er entityLabel"/><rect height="21" width="26.5899658203125" y="66" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,76.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-3-type" class="er entityLabel">int</text><rect height="21" width="93.8125" y="66" x="26.5899658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,76.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-3-name" class="er entityLabel">opt_base_delay</text><rect height="21" width="23.79498291015625" y="66" x="120.4024658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,76.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-3-key" class="er entityLabel"/><rect height="21" width="26.5899658203125" y="87" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,97.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-4-type" class="er entityLabel">int</text><rect height="21" width="93.8125" y="87" x="26.5899658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,97.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-4-name" class="er entityLabel">opt_timeout</text><rect height="21" width="23.79498291015625" y="87" x="120.4024658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,97.5)" y="0" x="0" id="text-entity-flows-f18f0530-88df-544b-a742-e42ede14479d-attr-4-key" class="er entityLabel"/></g><g transform="translate(20,228 )" id="entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66"><rect height="171" width="160.0457763671875" y="0" x="0" class="er entityBox"/><text style="dominant-baseline: middle; text-anchor: middle; font-size: 12px;" transform="translate(80.02288818359375,12)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66" class="er entityLabel">steps</text><rect height="21" width="26.5899658203125" y="24" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,34.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-1-type" class="er entityLabel">text</text><rect height="21" width="93.8125" y="24" x="26.5899658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,34.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-1-name" class="er entityLabel">flow_slug</text><rect height="21" width="39.643310546875" y="24" x="120.4024658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,34.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-1-key" class="er entityLabel">PK,FK</text><rect height="21" width="26.5899658203125" y="45" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,55.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-2-type" class="er entityLabel">text</text><rect height="21" width="93.8125" y="45" x="26.5899658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,55.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-2-name" class="er entityLabel">step_slug</text><rect height="21" width="39.643310546875" y="45" x="120.4024658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,55.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-2-key" class="er entityLabel">PK</text><rect height="21" width="26.5899658203125" y="66" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,76.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-3-type" class="er entityLabel">text</text><rect height="21" width="93.8125" y="66" x="26.5899658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,76.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-3-name" class="er entityLabel">step_type</text><rect height="21" width="39.643310546875" y="66" x="120.4024658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,76.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-3-key" class="er entityLabel"/><rect height="21" width="26.5899658203125" y="87" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,97.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-4-type" class="er entityLabel">int</text><rect height="21" width="93.8125" y="87" x="26.5899658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,97.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-4-name" class="er entityLabel">deps_count</text><rect height="21" width="39.643310546875" y="87" x="120.4024658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,97.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-4-key" class="er entityLabel"/><rect height="21" width="26.5899658203125" y="108" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,118.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-5-type" class="er entityLabel">int</text><rect height="21" width="93.8125" y="108" x="26.5899658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,118.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-5-name" class="er entityLabel">opt_max_attempts</text><rect height="21" width="39.643310546875" y="108" x="120.4024658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,118.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-5-key" class="er entityLabel"/><rect height="21" width="26.5899658203125" y="129" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,139.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-6-type" class="er entityLabel">int</text><rect height="21" width="93.8125" y="129" x="26.5899658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,139.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-6-name" class="er entityLabel">opt_base_delay</text><rect height="21" width="39.643310546875" y="129" x="120.4024658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,139.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-6-key" class="er entityLabel"/><rect height="21" width="26.5899658203125" y="150" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,160.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-7-type" class="er entityLabel">int</text><rect height="21" width="93.8125" y="150" x="26.5899658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,160.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-7-name" class="er entityLabel">opt_timeout</text><rect height="21" width="39.643310546875" y="150" x="120.4024658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.4024658203125,160.5)" y="0" x="0" id="text-entity-steps-9f52b7fe-5175-560c-8193-e79d92ebca66-attr-7-key" class="er entityLabel"/></g><g transform="translate(39.93402099609375,530.5 )" id="entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e"><rect height="87" width="120.177734375" y="0" x="0" class="er entityBox"/><text style="dominant-baseline: middle; text-anchor: middle; font-size: 12px;" transform="translate(60.0888671875,12)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e" class="er entityLabel">deps</text><rect height="21" width="26.5899658203125" y="24" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,34.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-1-type" class="er entityLabel">text</text><rect height="21" width="53.9444580078125" y="24" x="26.5899658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,34.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-1-name" class="er entityLabel">flow_slug</text><rect height="21" width="39.643310546875" y="24" x="80.534423828125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(85.534423828125,34.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-1-key" class="er entityLabel">PK,FK</text><rect height="21" width="26.5899658203125" y="45" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,55.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-2-type" class="er entityLabel">text</text><rect height="21" width="53.9444580078125" y="45" x="26.5899658203125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,55.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-2-name" class="er entityLabel">dep_slug</text><rect height="21" width="39.643310546875" y="45" x="80.534423828125" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(85.534423828125,55.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-2-key" class="er entityLabel">PK,FK</text><rect height="21" width="26.5899658203125" y="66" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,76.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-3-type" class="er entityLabel">text</text><rect height="21" width="53.9444580078125" y="66" x="26.5899658203125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(31.5899658203125,76.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-3-name" class="er entityLabel">step_slug</text><rect height="21" width="39.643310546875" y="66" x="80.534423828125" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(85.534423828125,76.5)" y="0" x="0" id="text-entity-deps-e5301c36-0cf6-5c3a-a840-98a74414ff8e-attr-3-key" class="er entityLabel">PK,FK</text></g><g transform="translate(280.0457763671875,238.5 )" id="entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf"><rect height="150" width="144.23367309570312" y="0" x="0" class="er entityBox"/><text style="dominant-baseline: middle; text-anchor: middle; font-size: 12px;" transform="translate(72.11683654785156,12)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf" class="er entityLabel">runs</text><rect height="21" width="35.688690185546875" y="24" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,34.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-1-type" class="er entityLabel">uuid</text><rect height="21" width="84.75" y="24" x="35.688690185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,34.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-1-name" class="er entityLabel">run_id</text><rect height="21" width="23.79498291015625" y="24" x="120.43869018554688" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.43869018554688,34.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-1-key" class="er entityLabel">PK</text><rect height="21" width="35.688690185546875" y="45" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,55.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-2-type" class="er entityLabel">text</text><rect height="21" width="84.75" y="45" x="35.688690185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,55.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-2-name" class="er entityLabel">flow_slug</text><rect height="21" width="23.79498291015625" y="45" x="120.43869018554688" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.43869018554688,55.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-2-key" class="er entityLabel">FK</text><rect height="21" width="35.688690185546875" y="66" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,76.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-3-type" class="er entityLabel">text</text><rect height="21" width="84.75" y="66" x="35.688690185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,76.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-3-name" class="er entityLabel">status</text><rect height="21" width="23.79498291015625" y="66" x="120.43869018554688" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.43869018554688,76.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-3-key" class="er entityLabel"/><rect height="21" width="35.688690185546875" y="87" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,97.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-4-type" class="er entityLabel">jsonb</text><rect height="21" width="84.75" y="87" x="35.688690185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,97.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-4-name" class="er entityLabel">input</text><rect height="21" width="23.79498291015625" y="87" x="120.43869018554688" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.43869018554688,97.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-4-key" class="er entityLabel"/><rect height="21" width="35.688690185546875" y="108" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,118.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-5-type" class="er entityLabel">jsonb</text><rect height="21" width="84.75" y="108" x="35.688690185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,118.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-5-name" class="er entityLabel">output</text><rect height="21" width="23.79498291015625" y="108" x="120.43869018554688" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.43869018554688,118.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-5-key" class="er entityLabel"/><rect height="21" width="35.688690185546875" y="129" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,139.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-6-type" class="er entityLabel">int</text><rect height="21" width="84.75" y="129" x="35.688690185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,139.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-6-name" class="er entityLabel">remaining_steps</text><rect height="21" width="23.79498291015625" y="129" x="120.43869018554688" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(125.43869018554688,139.5)" y="0" x="0" id="text-entity-runs-75ffb4dd-6be8-5a8d-bc72-ade53caeacdf-attr-6-key" class="er entityLabel"/></g><g transform="translate(275.4497375488281,499 )" id="entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4"><rect height="150" width="153.42575073242188" y="0" x="0" class="er entityBox"/><text style="dominant-baseline: middle; text-anchor: middle; font-size: 12px;" transform="translate(76.71287536621094,12)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4" class="er entityLabel">step_states</text><rect height="21" width="29.594940185546875" y="24" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,34.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-1-type" class="er entityLabel">text</text><rect height="21" width="84.1875" y="24" x="29.594940185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(34.594940185546875,34.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-1-name" class="er entityLabel">flow_slug</text><rect height="21" width="39.643310546875" y="24" x="113.78244018554688" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(118.78244018554688,34.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-1-key" class="er entityLabel">FK</text><rect height="21" width="29.594940185546875" y="45" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,55.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-2-type" class="er entityLabel">uuid</text><rect height="21" width="84.1875" y="45" x="29.594940185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(34.594940185546875,55.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-2-name" class="er entityLabel">run_id</text><rect height="21" width="39.643310546875" y="45" x="113.78244018554688" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(118.78244018554688,55.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-2-key" class="er entityLabel">PK,FK</text><rect height="21" width="29.594940185546875" y="66" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,76.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-3-type" class="er entityLabel">text</text><rect height="21" width="84.1875" y="66" x="29.594940185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(34.594940185546875,76.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-3-name" class="er entityLabel">step_slug</text><rect height="21" width="39.643310546875" y="66" x="113.78244018554688" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(118.78244018554688,76.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-3-key" class="er entityLabel">PK,FK</text><rect height="21" width="29.594940185546875" y="87" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,97.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-4-type" class="er entityLabel">text</text><rect height="21" width="84.1875" y="87" x="29.594940185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(34.594940185546875,97.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-4-name" class="er entityLabel">status</text><rect height="21" width="39.643310546875" y="87" x="113.78244018554688" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(118.78244018554688,97.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-4-key" class="er entityLabel"/><rect height="21" width="29.594940185546875" y="108" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,118.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-5-type" class="er entityLabel">int</text><rect height="21" width="84.1875" y="108" x="29.594940185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(34.594940185546875,118.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-5-name" class="er entityLabel">remaining_tasks</text><rect height="21" width="39.643310546875" y="108" x="113.78244018554688" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(118.78244018554688,118.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-5-key" class="er entityLabel"/><rect height="21" width="29.594940185546875" y="129" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,139.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-6-type" class="er entityLabel">int</text><rect height="21" width="84.1875" y="129" x="29.594940185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(34.594940185546875,139.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-6-name" class="er entityLabel">remaining_deps</text><rect height="21" width="39.643310546875" y="129" x="113.78244018554688" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(118.78244018554688,139.5)" y="0" x="0" id="text-entity-stepstates-d5fb431d-8c65-5bd1-8e0a-6a399ad2c7c4-attr-6-key" class="er entityLabel"/></g><g transform="translate(274.58380126953125,749 )" id="entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8"><rect height="213" width="155.15762329101562" y="0" x="0" class="er entityBox"/><text style="dominant-baseline: middle; text-anchor: middle; font-size: 12px;" transform="translate(77.57881164550781,12)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8" class="er entityLabel">step_tasks</text><rect height="21" width="35.688690185546875" y="24" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,34.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-1-type" class="er entityLabel">text</text><rect height="21" width="79.82562255859375" y="24" x="35.688690185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,34.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-1-name" class="er entityLabel">flow_slug</text><rect height="21" width="39.643310546875" y="24" x="115.51431274414062" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,34.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-1-key" class="er entityLabel">FK</text><rect height="21" width="35.688690185546875" y="45" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,55.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-2-type" class="er entityLabel">uuid</text><rect height="21" width="79.82562255859375" y="45" x="35.688690185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,55.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-2-name" class="er entityLabel">run_id</text><rect height="21" width="39.643310546875" y="45" x="115.51431274414062" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,55.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-2-key" class="er entityLabel">PK,FK</text><rect height="21" width="35.688690185546875" y="66" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,76.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-3-type" class="er entityLabel">text</text><rect height="21" width="79.82562255859375" y="66" x="35.688690185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,76.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-3-name" class="er entityLabel">step_slug</text><rect height="21" width="39.643310546875" y="66" x="115.51431274414062" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,76.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-3-key" class="er entityLabel">PK,FK</text><rect height="21" width="35.688690185546875" y="87" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,97.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-4-type" class="er entityLabel">bigint</text><rect height="21" width="79.82562255859375" y="87" x="35.688690185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,97.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-4-name" class="er entityLabel">message_id</text><rect height="21" width="39.643310546875" y="87" x="115.51431274414062" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,97.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-4-key" class="er entityLabel"/><rect height="21" width="35.688690185546875" y="108" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,118.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-5-type" class="er entityLabel">int</text><rect height="21" width="79.82562255859375" y="108" x="35.688690185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,118.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-5-name" class="er entityLabel">task_index</text><rect height="21" width="39.643310546875" y="108" x="115.51431274414062" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,118.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-5-key" class="er entityLabel">PK</text><rect height="21" width="35.688690185546875" y="129" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,139.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-6-type" class="er entityLabel">text</text><rect height="21" width="79.82562255859375" y="129" x="35.688690185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,139.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-6-name" class="er entityLabel">status</text><rect height="21" width="39.643310546875" y="129" x="115.51431274414062" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,139.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-6-key" class="er entityLabel"/><rect height="21" width="35.688690185546875" y="150" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,160.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-7-type" class="er entityLabel">int</text><rect height="21" width="79.82562255859375" y="150" x="35.688690185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,160.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-7-name" class="er entityLabel">attempts_count</text><rect height="21" width="39.643310546875" y="150" x="115.51431274414062" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,160.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-7-key" class="er entityLabel"/><rect height="21" width="35.688690185546875" y="171" x="0" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,181.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-8-type" class="er entityLabel">text</text><rect height="21" width="79.82562255859375" y="171" x="35.688690185546875" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,181.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-8-name" class="er entityLabel">error_message</text><rect height="21" width="39.643310546875" y="171" x="115.51431274414062" class="er attributeBoxEven"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,181.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-8-key" class="er entityLabel"/><rect height="21" width="35.688690185546875" y="192" x="0" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(5,202.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-9-type" class="er entityLabel">jsonb</text><rect height="21" width="79.82562255859375" y="192" x="35.688690185546875" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(40.688690185546875,202.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-9-name" class="er entityLabel">output</text><rect height="21" width="39.643310546875" y="192" x="115.51431274414062" class="er attributeBoxOdd"/><text style="dominant-baseline: middle; font-size: 10.2px;" transform="translate(120.51431274414062,202.5)" y="0" x="0" id="text-entity-steptasks-1b58e334-b1db-5be4-8d8a-3602898074c8-attr-9-key" class="er entityLabel"/></g><rect height="14" width="19.359375" y="162.96568298339844" x="106.04055786132812" class="er relationshipLabelBox"/><text style="text-anchor: middle; dominant-baseline: middle; font-size: 12px;" y="169.96568298339844" x="115.72024536132812" id="rel1" class="er relationshipLabel">has</text><rect height="14" width="80.734375" y="458.8131103515625" x="20.040935516357422" class="er relationshipLabelBox"/><text style="text-anchor: middle; dominant-baseline: middle; font-size: 12px;" y="465.8131103515625" x="60.40812301635742" id="rel2" class="er relationshipLabel">is_dependency</text><rect height="14" width="66.078125" y="460.0412902832031" x="126.8541259765625" class="er relationshipLabelBox"/><text style="text-anchor: middle; dominant-baseline: middle; font-size: 12px;" y="467.0412902832031" x="159.8931884765625" id="rel3" class="er relationshipLabel">depends_on</text><rect height="14" width="60.703125" y="167.44549560546875" x="308.50225830078125" class="er relationshipLabelBox"/><text style="text-anchor: middle; dominant-baseline: middle; font-size: 12px;" y="174.44549560546875" x="338.85382080078125" id="rel4" class="er relationshipLabel">instantiates</text><rect height="14" width="44.703125" y="436.75" x="329.8114318847656" class="er relationshipLabelBox"/><text style="text-anchor: middle; dominant-baseline: middle; font-size: 12px;" y="443.75" x="352.1629943847656" id="rel5" class="er relationshipLabel">contains</text><rect height="14" width="19.359375" y="692" x="342.4833068847656" class="er relationshipLabelBox"/><text style="text-anchor: middle; dominant-baseline: middle; font-size: 12px;" y="699" x="352.1629943847656" id="rel6" class="er relationshipLabel">has</text></svg>
@@ -0,0 +1,72 @@
1
+ BEGIN {
2
+ # ANSI color codes
3
+ RED="\033[31m";
4
+ GREEN="\033[32m";
5
+ YELLOW="\033[33m";
6
+ GRAY="\033[90m";
7
+ BOLD="\033[1m";
8
+ RESET="\033[0m";
9
+ }
10
+
11
+ /Dubious|Failed|error|exit 1|Result: FAIL/ {
12
+ print RED $0 RESET;
13
+ next;
14
+ }
15
+
16
+ # Match any line containing ERROR: (PostgreSQL error messages)
17
+ /ERROR:/ {
18
+ print RED $0 RESET;
19
+ next;
20
+ }
21
+
22
+ # Match DETAIL: and CONTEXT: lines that are part of PostgreSQL error messages
23
+ /DETAIL:|CONTEXT:/ {
24
+ print RED $0 RESET;
25
+ next;
26
+ }
27
+
28
+ /ok$/ {
29
+ print GREEN $0 RESET;
30
+ next;
31
+ }
32
+
33
+ /\.\.\.+/ {
34
+ test = $1;
35
+ result = $NF;
36
+ if (result == "ok") {
37
+ printf "%s %s %s\n", test, GRAY RESET, GREEN result RESET;
38
+ } else {
39
+ printf "%s %s %s\n", RED test RESET, GRAY RESET, RED result RESET;
40
+ }
41
+ next;
42
+ }
43
+
44
+ /Test Summary Report|-------------------/ {
45
+ print YELLOW BOLD $0 RESET;
46
+ next;
47
+ }
48
+
49
+ /\(Wstat:.*/ {
50
+ sub(/^[[:space:]]+/, "");
51
+ filename = $1;
52
+ print YELLOW " " RED filename RESET YELLOW $2 $3 $4 $5 $6 RESET;
53
+ next;
54
+ }
55
+
56
+ /^Files=|^Result:/ {
57
+ if ($0 ~ /FAIL/) {
58
+ print RED BOLD $0 RESET;
59
+ } else {
60
+ print YELLOW $0 RESET;
61
+ }
62
+ next;
63
+ }
64
+
65
+ /Try rerunning/ {
66
+ print YELLOW $0 RESET;
67
+ next;
68
+ }
69
+
70
+ {
71
+ print;
72
+ }
@@ -0,0 +1,5 @@
1
+ #!/bin/bash
2
+
3
+ # Run the Supabase tests and colorize the output
4
+ pnpm supabase db test "$@" 2>&1 | awk -f ./scripts/colorize-pgtap-output.awk
5
+ exit ${PIPESTATUS[0]}
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+
3
+ # Get all arguments passed to this script
4
+ args="$@"
5
+
6
+ # Watch for changes in SQL files and run the test with the provided arguments
7
+ find -iname '*.sql' | entr -r -c sh -c "scripts/run-test-with-colors $args"
@@ -0,0 +1,85 @@
1
+ import type postgres from 'postgres';
2
+ import type {
3
+ StepTaskRecord,
4
+ IPgflowClient,
5
+ StepTaskKey,
6
+ RunRow,
7
+ } from './types.ts';
8
+ import type { Json } from './types.ts';
9
+ import type { AnyFlow, ExtractFlowInput } from '@pgflow/dsl';
10
+
11
+ /**
12
+ * Implementation of IPgflowClient that uses direct SQL calls to pgflow functions
13
+ */
14
+ export class PgflowSqlClient<TFlow extends AnyFlow>
15
+ implements IPgflowClient<TFlow>
16
+ {
17
+ constructor(private readonly sql: postgres.Sql) {}
18
+
19
+ async pollForTasks(
20
+ queueName: string,
21
+ batchSize = 20,
22
+ visibilityTimeout = 2,
23
+ maxPollSeconds = 5,
24
+ pollIntervalMs = 200
25
+ ): Promise<StepTaskRecord<TFlow>[]> {
26
+ return await this.sql<StepTaskRecord<TFlow>[]>`
27
+ SELECT *
28
+ FROM pgflow.poll_for_tasks(
29
+ queue_name => ${queueName},
30
+ vt => ${visibilityTimeout},
31
+ qty => ${batchSize},
32
+ max_poll_seconds => ${maxPollSeconds},
33
+ poll_interval_ms => ${pollIntervalMs}
34
+ );
35
+ `;
36
+ }
37
+
38
+ async completeTask(stepTask: StepTaskKey, output?: Json): Promise<void> {
39
+ await this.sql`
40
+ SELECT pgflow.complete_task(
41
+ run_id => ${stepTask.run_id}::uuid,
42
+ step_slug => ${stepTask.step_slug}::text,
43
+ task_index => ${0}::int,
44
+ output => ${this.sql.json(output || null)}::jsonb
45
+ );
46
+ `;
47
+ }
48
+
49
+ async failTask(stepTask: StepTaskKey, error: unknown): Promise<void> {
50
+ const errorString =
51
+ typeof error === 'string'
52
+ ? error
53
+ : error instanceof Error
54
+ ? error.message
55
+ : JSON.stringify(error);
56
+
57
+ await this.sql`
58
+ SELECT pgflow.fail_task(
59
+ run_id => ${stepTask.run_id}::uuid,
60
+ step_slug => ${stepTask.step_slug}::text,
61
+ task_index => ${0}::int,
62
+ error_message => ${errorString}::text
63
+ );
64
+ `;
65
+ }
66
+
67
+ async startFlow<TFlow extends AnyFlow>(
68
+ flow: TFlow,
69
+ input: ExtractFlowInput<TFlow>
70
+ ): Promise<RunRow> {
71
+ const results = await this.sql<RunRow[]>`
72
+ SELECT * FROM pgflow.start_flow(${flow.slug}::text, ${this.sql.json(
73
+ input
74
+ )}::jsonb);
75
+ `;
76
+
77
+ if (results.length === 0) {
78
+ throw new Error(`Failed to start flow ${flow.slug}`);
79
+ }
80
+
81
+ const [flowRun] = results;
82
+
83
+ return flowRun;
84
+ }
85
+ }