Current section
Files
Jump to
Current section
Files
lib/mq/query.ex
defmodule Mq.Query do
@moduledoc """
Programmatic query builder for constructing mq queries.
Queries are built by starting with a **selector** (e.g. `h2/0`, `code/0`) and
chaining operations via the `|>` pipe operator. The resulting struct can be
passed directly to `Mq.run/3` or converted to its string form with
`to_string/1` / `Kernel.to_string/1`.
## Basic usage
iex> Mq.Query.h2() |> to_string()
".h2"
iex> Mq.Query.h2() |> Mq.Query.to_text() |> to_string()
".h2 | to_text()"
## Filters
Use `Mq.Filter` to build filter expressions for `select/2` and `map/2`:
iex> alias Mq.{Query, Filter}
iex> Query.h2() |> Query.select(Filter.contains("Feature")) |> to_string()
".h2 | select(contains(\\"Feature\\"))"
## Combined filters
iex> alias Mq.{Query, Filter}
iex> query = Query.h2()
...> |> Query.select(
...> Filter.contains("API")
...> |> Filter.and_filter(Filter.negate(Filter.contains("Internal")))
...> )
...> |> Query.to_text()
...> |> Query.downcase()
iex> to_string(query)
".h2 | select(contains(\\"API\\") and not(contains(\\"Internal\\"))) | to_text() | downcase()"
## Using with `Mq.run/3`
iex> {:ok, result} = Mq.run(Mq.Query.h2(), "# Hello\\n## World")
iex> result.values
["## World"]
"""
@type t :: %__MODULE__{expr: String.t()}
defstruct [:expr]
defp new(expr), do: %__MODULE__{expr: expr}
defp pipe_expr(%__MODULE__{expr: ""}, next), do: new(next)
defp pipe_expr(%__MODULE__{expr: expr}, next), do: new("#{expr} | #{next}")
# Heading selectors
for n <- 1..6 do
@doc "Select all h#{n} headings."
def unquote(:"h#{n}")(), do: new(unquote(".h#{n}"))
end
@doc "Select all headings (any level)."
def heading, do: new(".heading")
# Block element selectors
@doc "Select all code blocks."
def code, do: new(".code")
@doc "Select all paragraphs."
def paragraph, do: new(".p")
@doc "Select all blockquotes."
def blockquote, do: new(".blockquote")
@doc "Select all horizontal rules."
def hr, do: new(".hr")
@doc "Select all images."
def image, do: new(".image")
@doc "Select all links."
def link, do: new(".link")
@doc "Select all text nodes."
def text, do: new(".text")
@doc "Select all strong (bold) nodes."
def strong, do: new(".strong")
@doc "Select all emphasis (italic) nodes."
def emphasis, do: new(".emphasis")
@doc "Select all strikethrough (delete) nodes."
def delete, do: new(".delete")
@doc "Select all math blocks."
def math, do: new(".math")
@doc "Select all tables."
def table, do: new(".table")
@doc "Select all table alignment nodes."
def table_align, do: new(".table_align")
@doc "Select all raw HTML nodes."
def html, do: new(".html")
@doc "Select all link definition nodes."
def definition, do: new(".definition")
@doc "Select all footnote definition nodes."
def footnote, do: new(".footnote")
@doc "Select all TOML front matter nodes."
def toml, do: new(".toml")
@doc "Select all YAML front matter nodes."
def yaml, do: new(".yaml")
# Inline element selectors
@doc "Select all inline code spans."
def code_inline, do: new(".code_inline")
@doc "Select all inline math spans."
def math_inline, do: new(".math_inline")
@doc "Select all link reference nodes."
def link_ref, do: new(".link_ref")
@doc "Select all image reference nodes."
def image_ref, do: new(".image_ref")
@doc "Select all footnote reference nodes."
def footnote_ref, do: new(".footnote_ref")
@doc "Select all line break nodes."
def line_break, do: new(".break")
# Task list selectors
@doc "Select all task list items."
def task, do: new(".task")
@doc "Select all unchecked task list items."
def todo, do: new(".todo")
@doc "Select all checked task list items."
def done, do: new(".done")
# List and table selectors
@doc "Select all list items."
def list, do: new(".[]")
@doc "Select the list item at index `n`."
def list_at(n), do: new(".[#{n}]")
@doc "Select all cells in table row `n`."
def table_row(n), do: new(".[#{n}][]")
@doc "Select all cells in table column `n`."
def table_col(n), do: new(".[][#{n}]")
@doc "Select the table cell at row `r`, column `c`."
def table_cell(r, c), do: new(".[#{r}][#{c}]")
# MDX selectors
@doc "Select all MDX JSX flow elements."
def mdx_jsx_flow_element, do: new(".mdx_jsx_flow_element")
@doc "Select all MDX text expression nodes."
def mdx_text_expression, do: new(".mdx_text_expression")
@doc "Select all MDX JSX text elements."
def mdx_jsx_text_element, do: new(".mdx_jsx_text_element")
@doc "Select all MDX flow expression nodes."
def mdx_flow_expression, do: new(".mdx_flow_expression")
@doc "Select all MDX JS/ESM import/export nodes."
def mdx_js_esm, do: new(".mdx_js_esm")
# Recursive (deep) selector
@doc "Recursive / deep selector — descend into all children."
def recursive, do: new("..")
# Standalone attribute selectors (0-arity)
# These also exist as 1-arity chain operations below.
@doc "Standalone `.value` attribute selector."
def value, do: new(".value")
@doc "Standalone `.values` attribute selector."
def node_values, do: new(".values")
@doc "Standalone `.lang` attribute selector."
def lang, do: new(".lang")
@doc "Standalone `.meta` attribute selector."
def meta, do: new(".meta")
@doc "Standalone `.fence` attribute selector."
def fence, do: new(".fence")
@doc "Standalone `.url` attribute selector."
def url, do: new(".url")
@doc "Standalone `.alt` attribute selector."
def alt, do: new(".alt")
@doc "Standalone `.depth` attribute selector."
def depth, do: new(".depth")
@doc "Standalone `.level` attribute selector."
def level, do: new(".level")
@doc "Standalone `.ordered` attribute selector."
def ordered, do: new(".ordered")
@doc "Standalone `.checked` attribute selector."
def checked, do: new(".checked")
@doc "Standalone `.column` attribute selector."
def column, do: new(".column")
@doc "Standalone `.row` attribute selector."
def row, do: new(".row")
@doc "Standalone `.align` attribute selector."
def align, do: new(".align")
@doc "Standalone dict property selector: `.\"key\"`."
def property(key), do: new(".\"#{key}\"")
# Standalone select (no leading selector)
@doc """
Standalone `select(filter)` — no leading selector.
Query.select(Filter.mdx?())
# => "select(is_mdx())"
"""
def select(%Mq.Filter{expr: expr}), do: new("select(#{expr})")
def select(filter) when is_binary(filter), do: new("select(#{filter})")
# Chained operations
@doc "Append a `select(filter)` step."
def select(%__MODULE__{} = q, %Mq.Filter{expr: expr}), do: pipe_expr(q, "select(#{expr})")
def select(%__MODULE__{} = q, filter) when is_binary(filter),
do: pipe_expr(q, "select(#{filter})")
@doc "Append a `map(filter)` step."
def map(%__MODULE__{} = q, %Mq.Filter{expr: expr}), do: pipe_expr(q, "map(#{expr})")
def map(%__MODULE__{} = q, filter) when is_binary(filter), do: pipe_expr(q, "map(#{filter})")
# Output format conversions
@doc "Convert to plain text."
def to_text(%__MODULE__{} = q), do: pipe_expr(q, "to_text()")
@doc "Convert to Markdown."
def to_markdown(%__MODULE__{} = q), do: pipe_expr(q, "to_markdown()")
@doc "Convert to MDX."
def to_mdx(%__MODULE__{} = q), do: pipe_expr(q, "to_mdx()")
@doc "Convert to HTML."
def to_html(%__MODULE__{} = q), do: pipe_expr(q, "to_html()")
@doc "Convert to a string value (mq `to_string()` function)."
def stringify(%__MODULE__{} = q), do: pipe_expr(q, "to_string()")
@doc "Convert to a number value."
def to_number(%__MODULE__{} = q), do: pipe_expr(q, "to_number()")
@doc "Convert to an array value."
def to_array(%__MODULE__{} = q), do: pipe_expr(q, "to_array()")
@doc "Convert to bytes."
def to_bytes(%__MODULE__{} = q), do: pipe_expr(q, "to_bytes()")
@doc "Convert to a Markdown string (serialized)."
def to_markdown_string(%__MODULE__{} = q), do: pipe_expr(q, "to_markdown_string()")
# Collection operations
@doc "Return the length of the current value."
def length(%__MODULE__{} = q), do: pipe_expr(q, "length")
@doc "Return the byte length of the current value."
def len(%__MODULE__{} = q), do: pipe_expr(q, "len()")
@doc "Return the UTF-8 byte length of the current value."
def utf8bytelen(%__MODULE__{} = q), do: pipe_expr(q, "utf8bytelen()")
@doc "Add/concatenate the current value."
def add(%__MODULE__{} = q), do: pipe_expr(q, "add")
@doc "Return the first element."
def first(%__MODULE__{} = q), do: pipe_expr(q, "first")
@doc "Return the last element."
def last(%__MODULE__{} = q), do: pipe_expr(q, "last")
@doc "Emit nothing (empty result)."
def empty(%__MODULE__{} = q), do: pipe_expr(q, "empty")
@doc "Reverse the current value."
def reverse(%__MODULE__{} = q), do: pipe_expr(q, "reverse")
@doc "Sort the current value."
def sort(%__MODULE__{} = q), do: pipe_expr(q, "sort")
@doc "Remove nil/null entries."
def compact(%__MODULE__{} = q), do: pipe_expr(q, "compact")
@doc "Remove duplicate entries."
def uniq(%__MODULE__{} = q), do: pipe_expr(q, "uniq")
@doc "Flatten nested arrays."
def flatten(%__MODULE__{} = q), do: pipe_expr(q, "flatten")
@doc "Return the keys of a dict."
def keys(%__MODULE__{} = q), do: pipe_expr(q, "keys")
@doc "Return the values of a dict."
def values(%__MODULE__{} = q), do: pipe_expr(q, "values")
@doc "Return the key-value entries of a dict."
def entries(%__MODULE__{} = q), do: pipe_expr(q, "entries")
@doc "Descend into children."
def children(%__MODULE__{} = q), do: pipe_expr(q, ".children")
@doc "Split the current value by `sep`."
def split(%__MODULE__{} = q, sep), do: pipe_expr(q, "split(#{inspect(sep)})")
@doc "Join elements with `sep`."
def join(%__MODULE__{} = q, sep), do: pipe_expr(q, "join(#{inspect(sep)})")
@doc "Select the nth element (0-based)."
def nth(%__MODULE__{} = q, n), do: pipe_expr(q, "nth(#{n})")
@doc "Limit output to `n` elements."
def limit(%__MODULE__{} = q, n), do: pipe_expr(q, "limit(#{n})")
@doc "Take a range of `n` elements."
def range(%__MODULE__{} = q, n), do: pipe_expr(q, "range(#{n})")
@doc "Slice elements from `start` to `stop`."
def slice(%__MODULE__{} = q, start, stop), do: pipe_expr(q, "slice(#{start}, #{stop})")
@doc "Find the first index of `value`."
def index(%__MODULE__{} = q, value), do: pipe_expr(q, "index(#{inspect(value)})")
@doc "Find the last index of `value`."
def rindex(%__MODULE__{} = q, value), do: pipe_expr(q, "rindex(#{inspect(value)})")
@doc "Delete the element `value`."
def del(%__MODULE__{} = q, value), do: pipe_expr(q, "del(#{inspect(value)})")
@doc "Insert `val` at index `idx`."
def insert(%__MODULE__{} = q, idx, val), do: pipe_expr(q, "insert(#{idx}, #{inspect(val)})")
@doc "Repeat the current value `n` times."
def repeat(%__MODULE__{} = q, n), do: pipe_expr(q, "repeat(#{n})")
# String operations
@doc "Trim leading and trailing whitespace."
def trim(%__MODULE__{} = q), do: pipe_expr(q, "trim()")
@doc "Trim leading whitespace."
def ltrim(%__MODULE__{} = q), do: pipe_expr(q, "ltrim()")
@doc "Trim trailing whitespace."
def rtrim(%__MODULE__{} = q), do: pipe_expr(q, "rtrim()")
@doc "Convert to lowercase (Unicode-aware)."
def downcase(%__MODULE__{} = q), do: pipe_expr(q, "downcase()")
@doc "Convert to uppercase (Unicode-aware)."
def upcase(%__MODULE__{} = q), do: pipe_expr(q, "upcase()")
@doc "Convert to lowercase (ASCII only)."
def ascii_downcase(%__MODULE__{} = q), do: pipe_expr(q, "ascii_downcase()")
@doc "Convert to uppercase (ASCII only)."
def ascii_upcase(%__MODULE__{} = q), do: pipe_expr(q, "ascii_upcase()")
@doc "Explode a string into codepoints."
def explode(%__MODULE__{} = q), do: pipe_expr(q, "explode()")
@doc "Implode codepoints back into a string."
def implode(%__MODULE__{} = q), do: pipe_expr(q, "implode()")
@doc "URL-encode the current value."
def url_encode(%__MODULE__{} = q), do: pipe_expr(q, "url_encode()")
@doc "Intern the current string."
def intern(%__MODULE__{} = q), do: pipe_expr(q, "intern()")
@doc "Replace all occurrences of `pattern` with `replacement` (regex)."
def gsub(%__MODULE__{} = q, pattern, replacement),
do: pipe_expr(q, "gsub(#{inspect(pattern)}, #{inspect(replacement)})")
@doc "Replace the first occurrence of `from` with `to`."
def replace(%__MODULE__{} = q, from, to),
do: pipe_expr(q, "replace(#{inspect(from)}, #{inspect(to)})")
@doc "Test whether the current value matches `pattern` (regex)."
def test(%__MODULE__{} = q, pattern), do: pipe_expr(q, "test(#{inspect(pattern)})")
@doc "Capture groups from `pattern` (regex)."
def capture(%__MODULE__{} = q, pattern), do: pipe_expr(q, "capture(#{inspect(pattern)})")
# Math operations
@doc "Absolute value."
def abs(%__MODULE__{} = q), do: pipe_expr(q, "abs()")
@doc "Ceiling."
def ceil(%__MODULE__{} = q), do: pipe_expr(q, "ceil()")
@doc "Floor."
def floor(%__MODULE__{} = q), do: pipe_expr(q, "floor()")
@doc "Round."
def round(%__MODULE__{} = q), do: pipe_expr(q, "round()")
@doc "Truncate."
def trunc(%__MODULE__{} = q), do: pipe_expr(q, "trunc()")
@doc "Square root."
def sqrt(%__MODULE__{} = q), do: pipe_expr(q, "sqrt()")
@doc "Natural logarithm."
def ln(%__MODULE__{} = q), do: pipe_expr(q, "ln()")
@doc "Base-10 logarithm."
def log10(%__MODULE__{} = q), do: pipe_expr(q, "log10()")
@doc "Exponential (e^x)."
def exp(%__MODULE__{} = q), do: pipe_expr(q, "exp()")
@doc "Negate the current numeric value."
def negate(%__MODULE__{} = q), do: pipe_expr(q, "negate()")
@doc "Check whether the current value is NaN."
def nan?(%__MODULE__{} = q), do: pipe_expr(q, "is_nan()")
@doc "Raise the current value to the power of `n`."
def pow(%__MODULE__{} = q, n), do: pipe_expr(q, "pow(#{n})")
@doc "Return the smaller of the current value and `other`."
def min(%__MODULE__{} = q, other), do: pipe_expr(q, "min(#{other})")
@doc "Return the larger of the current value and `other`."
def max(%__MODULE__{} = q, other), do: pipe_expr(q, "max(#{other})")
# Type / logic
@doc "Return the type of the current value."
def type(%__MODULE__{} = q), do: pipe_expr(q, "type")
@doc "Emit debug information for the current value."
def debug(%__MODULE__{} = q), do: pipe_expr(q, "debug")
@doc "Return `default` when the current value is none/null."
def coalesce(%__MODULE__{} = q, default), do: pipe_expr(q, "coalesce(#{inspect(default)})")
# Encoding
@doc "Base64-encode."
def base64(%__MODULE__{} = q), do: pipe_expr(q, "base64()")
@doc "Base64-decode."
def base64d(%__MODULE__{} = q), do: pipe_expr(q, "base64d()")
@doc "Base64url-encode."
def base64url(%__MODULE__{} = q), do: pipe_expr(q, "base64url()")
@doc "Base64url-decode."
def base64urld(%__MODULE__{} = q), do: pipe_expr(q, "base64urld()")
@doc "MD5 hash."
def md5(%__MODULE__{} = q), do: pipe_expr(q, "md5()")
@doc "SHA-256 hash."
def sha256(%__MODULE__{} = q), do: pipe_expr(q, "sha256()")
@doc "SHA-512 hash."
def sha512(%__MODULE__{} = q), do: pipe_expr(q, "sha512()")
@doc "Decode from hex."
def from_hex(%__MODULE__{} = q), do: pipe_expr(q, "from_hex()")
@doc "Encode to hex."
def to_hex(%__MODULE__{} = q), do: pipe_expr(q, "to_hex()")
# Path operations
@doc "Return the basename of a path."
def basename(%__MODULE__{} = q), do: pipe_expr(q, "basename()")
@doc "Return the directory part of a path."
def dirname(%__MODULE__{} = q), do: pipe_expr(q, "dirname()")
@doc "Return the file extension."
def extname(%__MODULE__{} = q), do: pipe_expr(q, "extname()")
@doc "Return the filename stem (basename without extension)."
def stem(%__MODULE__{} = q), do: pipe_expr(q, "stem()")
@doc "Join the current path with `other`."
def path_join(%__MODULE__{} = q, other), do: pipe_expr(q, "path_join(#{inspect(other)})")
# Dict operations
@doc "Get the value at dict key `key`."
def get(%__MODULE__{} = q, key), do: pipe_expr(q, "get(#{inspect(key)})")
@doc "Set dict key `key` to `val`."
def set(%__MODULE__{} = q, key, val), do: pipe_expr(q, "set(#{inspect(key)}, #{inspect(val)})")
# Chained attribute selectors (1-arity, dual with standalone 0-arity)
@doc "Access the `.value` attribute of the selected node."
def value(%__MODULE__{} = q), do: pipe_expr(q, ".value")
@doc "Access the `.lang` attribute (e.g. code block language)."
def lang(%__MODULE__{} = q), do: pipe_expr(q, ".lang")
@doc "Access the `.meta` attribute."
def meta(%__MODULE__{} = q), do: pipe_expr(q, ".meta")
@doc "Access the `.fence` attribute."
def fence(%__MODULE__{} = q), do: pipe_expr(q, ".fence")
@doc "Access the `.url` attribute."
def url(%__MODULE__{} = q), do: pipe_expr(q, ".url")
@doc "Access the `.alt` attribute."
def alt(%__MODULE__{} = q), do: pipe_expr(q, ".alt")
@doc "Access the `.title` attribute."
def title(%__MODULE__{} = q), do: pipe_expr(q, ".title")
@doc "Access the `.ident` attribute."
def ident(%__MODULE__{} = q), do: pipe_expr(q, ".ident")
@doc "Access the `.label` attribute."
def label(%__MODULE__{} = q), do: pipe_expr(q, ".label")
@doc "Access the `.depth` attribute."
def depth(%__MODULE__{} = q), do: pipe_expr(q, ".depth")
@doc "Access the `.level` attribute."
def level(%__MODULE__{} = q), do: pipe_expr(q, ".level")
@doc "Access the `.index` attribute (item index in a list)."
def item_index(%__MODULE__{} = q), do: pipe_expr(q, ".index")
@doc "Access the `.ordered` attribute."
def ordered(%__MODULE__{} = q), do: pipe_expr(q, ".ordered")
@doc "Access the `.checked` attribute (task list)."
def checked(%__MODULE__{} = q), do: pipe_expr(q, ".checked")
@doc "Access the `.column` attribute."
def column(%__MODULE__{} = q), do: pipe_expr(q, ".column")
@doc "Access the `.row` attribute."
def row(%__MODULE__{} = q), do: pipe_expr(q, ".row")
@doc "Access the `.align` attribute."
def align(%__MODULE__{} = q), do: pipe_expr(q, ".align")
@doc "Access the `.name` attribute (MDX element name)."
def mdx_name(%__MODULE__{} = q), do: pipe_expr(q, ".name")
@doc "Access a dict property by key (generates `.\"key\"`)."
def property(%__MODULE__{} = q, key), do: pipe_expr(q, ".\"#{key}\"")
# Markdown attribute mutation
@doc "Update the node content to `content`."
def update(%__MODULE__{} = q, content), do: pipe_expr(q, "update(#{inspect(content)})")
@doc "Get the attribute named `name`."
def attr(%__MODULE__{} = q, name), do: pipe_expr(q, "attr(#{inspect(name)})")
@doc "Set the attribute named `name` to `val`."
def set_attr(%__MODULE__{} = q, name, val),
do: pipe_expr(q, "set_attr(#{inspect(name)}, #{inspect(val)})")
@doc "Get the title of a link or image."
def get_title(%__MODULE__{} = q), do: pipe_expr(q, "get_title")
@doc "Get the URL of a link or image."
def get_url(%__MODULE__{} = q), do: pipe_expr(q, "get_url")
@doc "Set the checked state of a task list item."
def set_check(%__MODULE__{} = q, val), do: pipe_expr(q, "set_check(#{val})")
@doc "Set the reference identifier of a link ref or image ref."
def set_ref(%__MODULE__{} = q, ref), do: pipe_expr(q, "set_ref(#{inspect(ref)})")
@doc "Set the language of a code block."
def set_code_block_lang(%__MODULE__{} = q, lang),
do: pipe_expr(q, "set_code_block_lang(#{inspect(lang)})")
@doc "Set whether a list is ordered."
def set_list_ordered(%__MODULE__{} = q, val), do: pipe_expr(q, "set_list_ordered(#{val})")
# Markdown construction
@doc """
Convert to a fenced code block.
- `to_code(q)` — no language (`null`)
- `to_code(q, "elixir")` — with language
"""
def to_code(%__MODULE__{} = q, lang \\ nil) do
pipe_expr(q, if(lang, do: "to_code(#{inspect(lang)})", else: "to_code(null)"))
end
@doc "Convert to an inline code span."
def to_code_inline(%__MODULE__{} = q), do: pipe_expr(q, "to_code_inline()")
@doc "Convert to a heading of the given `depth` (1–6)."
def to_h(%__MODULE__{} = q, depth), do: pipe_expr(q, "to_h(#{depth})")
@doc "Convert to a horizontal rule."
def to_hr(%__MODULE__{} = q), do: pipe_expr(q, "to_hr()")
@doc """
Convert to a link node.
- `to_link(q, url)` — current value becomes the link text
- `to_link(q, url, text)` — explicit text, empty title
- `to_link(q, url, text, title)` — explicit text and title
"""
def to_link(%__MODULE__{} = q, url) do
pipe_expr(q, "to_link(#{inspect(url)}, \"\")")
end
def to_link(%__MODULE__{} = q, url, text) do
pipe_expr(q, "to_link(#{inspect(url)}, #{inspect(text)}, \"\")")
end
def to_link(%__MODULE__{} = q, url, text, link_title) do
pipe_expr(q, "to_link(#{inspect(url)}, #{inspect(text)}, #{inspect(link_title)})")
end
@doc """
Convert to an image node.
- `to_image(q, url)` — current value becomes the alt text
- `to_image(q, url, alt)` — explicit alt, empty title
- `to_image(q, url, alt, title)` — explicit alt and title
"""
def to_image(%__MODULE__{} = q, url) do
pipe_expr(q, "to_image(#{inspect(url)}, \"\")")
end
def to_image(%__MODULE__{} = q, url, img_alt) do
pipe_expr(q, "to_image(#{inspect(url)}, #{inspect(img_alt)}, \"\")")
end
def to_image(%__MODULE__{} = q, url, img_alt, img_title) do
pipe_expr(q, "to_image(#{inspect(url)}, #{inspect(img_alt)}, #{inspect(img_title)})")
end
@doc "Convert to a math block."
def to_math(%__MODULE__{} = q), do: pipe_expr(q, "to_math()")
@doc "Convert to an inline math span."
def to_math_inline(%__MODULE__{} = q), do: pipe_expr(q, "to_math_inline()")
@doc "Convert to a strong (bold) node."
def to_strong(%__MODULE__{} = q), do: pipe_expr(q, "to_strong()")
@doc "Convert to an emphasis (italic) node."
def to_em(%__MODULE__{} = q), do: pipe_expr(q, "to_em()")
@doc "Convert to a plain Markdown text node."
def to_md_text(%__MODULE__{} = q), do: pipe_expr(q, "to_md_text()")
@doc "Convert to a list item at nesting `list_level`."
def to_md_list(%__MODULE__{} = q, list_level), do: pipe_expr(q, "to_md_list(#{list_level})")
@doc "Convert to a Markdown element with the given node `node_name`."
def to_md_name(%__MODULE__{} = q, node_name),
do: pipe_expr(q, "to_md_name(#{inspect(node_name)})")
@doc "Build a table row from the given `cells` list."
def to_md_table_row(%__MODULE__{} = q, cells) when is_list(cells) do
cell_str = Enum.map_join(cells, ", ", &inspect/1)
pipe_expr(q, "to_md_table_row(#{cell_str})")
end
@doc "Build a table cell with `content` at row `r`, column `c`."
def to_md_table_cell(%__MODULE__{} = q, content, r, c),
do: pipe_expr(q, "to_md_table_cell(#{inspect(content)}, #{r}, #{c})")
# Pipe two Query structs
@doc """
Pipe two queries together.
Query.h2() |> Query.pipe(Query.to_text())
# => ".h2 | to_text()"
"""
def pipe(%__MODULE__{} = q1, %__MODULE__{expr: expr2}), do: pipe_expr(q1, expr2)
# Conversion
@doc "Return the raw mq query string."
def to_query_string(%__MODULE__{expr: expr}), do: expr
end
defimpl String.Chars, for: Mq.Query do
def to_string(%Mq.Query{expr: expr}), do: expr
end
defimpl Inspect, for: Mq.Query do
def inspect(%Mq.Query{expr: expr}, _opts), do: "#Mq.Query<#{expr}>"
end