# `Gust.DSL`

The Gust DSL is how you turn a module into a DAG.  
When you add `use Gust.DSL` to a module in the `dags/` folder, Gust automatically detects it and creates a DAG based on the file name.

You can configure a schedule, define callbacks, and in the `dev` environment the code is automatically reloaded when files change.

After enabling the DSL, use `task` definitions to declare the steps that should be executed.

## Example

    defmodule HelloWorld do
      # `schedule` and `on_finished_callback` are optional.
      # Note: if you change `schedule`, restart the server to update the cron job.
      use Gust.DSL, schedule: "* * * * *", on_finished_callback: :notify_something

      # Gust logs are stored and displayed through GustWeb via Logger.
      require Logger

      # Gust.Flows is used to query Dag, Run, and Task.
      alias Gust.Flows

      def notify_something(status, run) do
        dag = Flows.get_dag!(run.dag_id)
        message = "DAG: #{dag.name}; completed with status: #{status}"
        Logger.info(message)
      end

      def skip_first_task?(%{run_id: run_id}) do
        run = Flows.get_run!(run_id)
        Map.get(run.params, "skip_first_task", false)
      end

      task :first_task, downstream: [:second_task], save: true, skip_if: :skip_first_task? do
        greetings = "Hi from first_task"
        Logger.info(greetings)
        
        # You can get secrets created on the Web UI
        secret = Flows.get_secret_by_name("SUPER_SECRET")
        Logger.warning("I know your secret: #{secret.value}")

        # The return value must be a map when `save` is true.
        %{result: greetings}
      end

      task :second_task, ctx: %{run_id: run_id} do

        # Getting "first_task"'s result
        task = Flows.get_task_by_name_run("first_task", run_id)

        Logger.info(task.result)
      end
    end

## Parameters

  * `schedule` - A valid cron expression string.
  * `on_finished_callback` - The name of the function to be called.

# `task`
*macro* 

Defines a task in the DAG without options or explicit context matching.

## Parameters

  * `name` - The name of the task (atom).
  * `block` - The code block to execute for the task.

## Example

    task :simple_task do
      IO.puts "Hello"
    end

# `task`
*macro* 

Defines a task in the DAG.

## Parameters

  * `name` — The name of the task (atom).
  * `opts_and_ctx` — A keyword list of options and an optional context pattern.
  * `block` — The code block executed when the task runs.

## Task Options

  * `:downstream` — A list of task names (atoms) to run after this task completes.
  * `:save` — When true, the task's return value will be persisted.
      * Note: If enabled, the return value **must be a map**.
  * `:ctx` — A pattern that will be matched against the context passed to the task.
      * Defaults to: `%{run_id: run_id}`.
  * `:skip_if` — The name of a function in the DAG module that receives the task context
    and returns a boolean. When it returns `true`, the task body is not executed and the
    task is marked as `:skipped`. If an upstream task is skipped, dependent tasks are also
    skipped.
  * `:map_over` — The name of an upstream task whose saved list result will be used to
    start one parallel task instance per item. Gust persists the list under the
    `gust_task_items` key, and each item is passed as `ctx.params`. Map items are passed
    unchanged. Other values are wrapped as `%{"item" => value}`.

## Example

    task :my_task, ctx: %{run_id: run_id} do
      IO.inspect(run_id)
    end

    task :first, downstream: [:second] do
      :ok
    end

    task :persist_result, save: true do
      %{result: :ok}
    end

    task :process_item, map_over: :persist_items, ctx: %{params: %{"item" => item}} do
      IO.inspect(item)
    end

    def skip_export?(%{run_id: run_id}) do
      run = Gust.Flows.get_run!(run_id)
      Map.get(run.params, "skip_export", false)
    end

    task :export, skip_if: :skip_export? do
      :ok
    end

When using `save: true`, the return value **must** be a map so it can be merged into the overall DAG results.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
