You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sedona.apache.org by gi...@apache.org on 2025/12/12 16:11:44 UTC

(sedona-db) branch asf-site updated: Deployed ce85315 to latest-snapshot with MkDocs 1.6.1 and mike 2.1.3

This is an automated email from the ASF dual-hosted git repository.

github-bot pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/sedona-db.git


The following commit(s) were added to refs/heads/asf-site by this push:
     new e3793a78 Deployed ce85315 to latest-snapshot with MkDocs 1.6.1 and mike 2.1.3
e3793a78 is described below

commit e3793a7870cb3868687ad08c70d37b9918d0deb4
Author: GitHub Actions <ac...@github.com>
AuthorDate: Fri Dec 12 16:11:39 2025 +0000

    Deployed ce85315 to latest-snapshot with MkDocs 1.6.1 and mike 2.1.3
---
 latest-snapshot/contributors-guide/index.html      |  67 ++++++-
 .../_matplotlib_defaults.cpython-314.pyc           | Bin 0 -> 431 bytes
 .../_extensions/function-listing/_extension.yml}   |  19 +-
 .../function-listing/function-listing.lua          |  43 +++++
 .../_extensions/render-meta-and-examples.lua       | 137 +++++++++++++
 .../functions/_matplotlib_defaults.py}             |  17 +-
 latest-snapshot/reference/functions/_quarto.yml    |  46 +++++
 .../reference/functions/_render_examples.py        | 120 ++++++++++++
 .../reference/functions/_render_listing.py         |  83 ++++++++
 .../reference/functions/_render_meta.py            | 213 +++++++++++++++++++++
 .../functions/index.qmd}                           |  17 +-
 .../reference/functions/st_analyze_agg.qmd         |  49 +++++
 latest-snapshot/reference/functions/st_buffer.qmd  |  81 ++++++++
 .../reference/functions/st_intersection.qmd        |  54 ++++++
 latest-snapshot/requirements.txt                   |   1 +
 latest-snapshot/search/search_index.json           |   2 +-
 16 files changed, 911 insertions(+), 38 deletions(-)

diff --git a/latest-snapshot/contributors-guide/index.html b/latest-snapshot/contributors-guide/index.html
index 7bad34ad..ce822c01 100644
--- a/latest-snapshot/contributors-guide/index.html
+++ b/latest-snapshot/contributors-guide/index.html
@@ -2046,6 +2046,71 @@ cargo<span class="w"> </span>bench
 </li>
 <li>Push your changes and open a pull request.</li>
 </ol>
+<p>SQL function reference is special: because we provide so many functions, we have
+a specialized syntax for documenting them. The minimum required documentation for
+a function is a file <code>docs/reference/functions/function_name.qmd</code>:</p>
+<div class="codehilite"><pre><span></span><code><span class="c1">---</span>
+<span class="nl">title</span><span class="p">:</span><span class="w"> </span><span class="n">ST_FunctionName</span>
+<span class="nl">description</span><span class="p">:</span><span class="w"> </span><span class="n">A</span><span class="w"> </span><span class="n">brief</span><span class="w"> </span><span class="n">one</span><span class="w"> </span><span class="n">sentence</span><span class="w"> </span><span class="n">description</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">what</span><span class="w"> </span><span class="n">the</span><span class="w"> </s [...]
+<span class="nl">kernels</span><span class="p">:</span>
+<span class="w">  </span><span class="o">-</span><span class="w"> </span><span class="k">returns</span><span class="err">:</span><span class="w"> </span><span class="n">geometry</span>
+<span class="w">    </span><span class="nl">args</span><span class="p">:</span><span class="w"> </span><span class="o">[</span><span class="n">geometry</span><span class="o">]</span>
+<span class="c1">---</span>
+
+<span class="err">##</span><span class="w"> </span><span class="n">Examples</span>
+
+<span class="err">```</span><span class="k">sql</span>
+<span class="k">SELECT</span><span class="w"> </span><span class="n">ST_FunctionName</span><span class="p">(</span><span class="n">ST_Point</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">))</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">val</span><span class="p">;</span>
+<span class="err">```</span>
+</code></pre></div>
+
+<p>After writing this file, the <code>.md</code> file may be rendered using <a href="https://quarto.org">Quarto</a>:</p>
+<div class="highlight"><pre><span></span><code><span class="nb">cd</span><span class="w"> </span>docs/reference/functions
+quarto<span class="w"> </span>render
+</code></pre></div>
+<p>This command (1) expands <code>description</code> and <code>kernels</code> to a templated representation,
+(2) checks and renders the result of the SQL examples, and (3) executes any
+<a href="https://quarto.org/docs/computations/python.html">Python code chunks</a>. These may
+be used to render figures that demonstrate visually what a function does or how its
+parameters affect the result.</p>
+<p>The <code>kernels</code> section of the frontmatter allows multiple implementations of a function
+to be documented. For example, many functions include implementations for geometry
+<em>and</em> geography or allow extra arguments to be supplied to customize behaviour. As
+an example, the frontmatter for <code>ST_Buffer()</code> is:</p>
+<div class="codehilite"><pre><span></span><code><span class="o">---</span>
+<span class="nx">title</span><span class="p">:</span><span class="w"> </span><span class="nx">ST_Buffer</span>
+<span class="nx">description</span><span class="p">:</span><span class="w"> </span><span class="p">&gt;</span>
+<span class="w">    </span><span class="nx">Computes</span><span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="nx">geometry</span><span class="w"> </span><span class="nx">that</span><span class="w"> </span><span class="nx">represents</span><span class="w"> </span><span class="nx">all</span><span class="w"> </span><span class="nx">points</span><span class="w"> </span><span class="nx">whose</span><span class="w"> </span><span class="nx">distance</span><spa [...]
+<span class="w">    </span><span class="nx">geometry</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="nx">less</span><span class="w"> </span><span class="nx">than</span><span class="w"> </span><span class="k">or</span><span class="w"> </span><span class="nx">equal</span><span class="w"> </span><span class="nx">to</span><span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="nx">specified</span><span class="w"> </spa [...]
+<span class="nx">kernels</span><span class="p">:</span>
+<span class="w">  </span><span class="o">-</span><span class="w"> </span><span class="nx">returns</span><span class="p">:</span><span class="w"> </span><span class="nx">geometry</span>
+<span class="w">    </span><span class="nx">args</span><span class="p">:</span>
+<span class="w">    </span><span class="o">-</span><span class="w"> </span><span class="nx">geometry</span>
+<span class="w">    </span><span class="o">-</span><span class="w"> </span><span class="nx">name</span><span class="p">:</span><span class="w"> </span><span class="nx">distance</span>
+<span class="w">      </span><span class="k">type</span><span class="p">:</span><span class="w"> </span><span class="nx">float64</span>
+<span class="w">      </span><span class="nx">description</span><span class="p">:</span><span class="w"> </span><span class="nx">Radius</span><span class="w"> </span><span class="nx">of</span><span class="w"> </span><span class="nx">the</span><span class="w"> </span><span class="nx">buffer</span>
+<span class="w">  </span><span class="o">-</span><span class="w"> </span><span class="nx">returns</span><span class="p">:</span><span class="w"> </span><span class="nx">geometry</span>
+<span class="w">    </span><span class="nx">args</span><span class="p">:</span>
+<span class="w">    </span><span class="o">-</span><span class="w"> </span><span class="nx">geometry</span>
+<span class="w">    </span><span class="o">-</span><span class="w"> </span><span class="nx">name</span><span class="p">:</span><span class="w"> </span><span class="nx">distance</span>
+<span class="w">      </span><span class="k">type</span><span class="p">:</span><span class="w"> </span><span class="nx">float64</span>
+<span class="w">    </span><span class="o">-</span><span class="w"> </span><span class="nx">name</span><span class="p">:</span><span class="w"> </span><span class="nx">params</span>
+<span class="w">      </span><span class="k">type</span><span class="p">:</span><span class="w"> </span><span class="nx">utf8</span>
+<span class="w">      </span><span class="nx">description</span><span class="p">:</span><span class="w"> </span><span class="nx">Space</span><span class="o">-</span><span class="nx">separated</span><span class="w"> </span><span class="err">`</span><span class="nx">key</span><span class="p">=</span><span class="nx">value</span><span class="err">`</span><span class="w"> </span><span class="nx">parameters</span><span class="p">.</span>
+<span class="o">---</span>
+</code></pre></div>
+
+<p>This illustrates a few ways in which arguments can be defined:</p>
+<ul>
+<li>By the string <code>geometry</code>, <code>geography</code>, or <code>raster</code>. These are expanded to a full
+  definition by quarto but are so common that we allow abbreviating them to avoid
+  typing <code>description: Input geometry</code> for every single function.</li>
+<li>With a YAML object of <code>name</code> / <code>type</code> / <code>description</code>. The type names are lowercase
+  Arrow type names which should be identical to those printed when executing a query
+  in SedonaDB.</li>
+</ul>
+<p>The build system for function documentation is a work in progress, so be sure to ask
+if you run into problems or have any questions about the syntax!</p>
 
 
 
@@ -2066,7 +2131,7 @@ cargo<span class="w"> </span>bench
     <span class="md-icon" title="Last update">
       <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21 13.1c-.1 0-.3.1-.4.2l-1 1 2.1 2.1 1-1c.2-.2.2-.6 0-.8l-1.3-1.3c-.1-.1-.2-.2-.4-.2m-1.9 1.8-6.1 6V23h2.1l6.1-6.1zM12.5 7v5.2l4 2.4-1 1L11 13V7zM11 21.9c-5.1-.5-9-4.8-9-9.9C2 6.5 6.5 2 12 2c5.3 0 9.6 4.1 10 9.3-.3-.1-.6-.2-1-.2s-.7.1-1 .2C19.6 7.2 16.2 4 12 4c-4.4 0-8 3.6-8 8 0 4.1 3.1 7.5 7.1 7.9l-.1.2z"></path></svg>
     </span>
-    <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-datetime" title="November 9, 2025 03:42:23 UTC">November 9, 2025 03:42:23</span>
+    <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-datetime" title="December 12, 2025 16:07:28 UTC">December 12, 2025 16:07:28</span>
   </span>
 
     
diff --git a/latest-snapshot/reference/functions/__pycache__/_matplotlib_defaults.cpython-314.pyc b/latest-snapshot/reference/functions/__pycache__/_matplotlib_defaults.cpython-314.pyc
new file mode 100644
index 00000000..1cb53d12
Binary files /dev/null and b/latest-snapshot/reference/functions/__pycache__/_matplotlib_defaults.cpython-314.pyc differ
diff --git a/latest-snapshot/requirements.txt b/latest-snapshot/reference/functions/_extensions/function-listing/_extension.yml
similarity index 82%
copy from latest-snapshot/requirements.txt
copy to latest-snapshot/reference/functions/_extensions/function-listing/_extension.yml
index 6bd80c39..a218f5f7 100644
--- a/latest-snapshot/requirements.txt
+++ b/latest-snapshot/reference/functions/_extensions/function-listing/_extension.yml
@@ -15,15 +15,10 @@
 # specific language governing permissions and limitations
 # under the License.
 
-griffe
-mike
-mkdocs
-mkdocs-git-revision-date-localized-plugin
-mkdocs-glightbox
-mkdocs-macros-plugin
-mkdocs-material
-mkdocstrings[python]
-nbconvert
-pyproj
-ruff
-lonboard
+title: Function Listing
+author: SedonaDB
+version: 1.0.0
+quarto-required: ">=1.4.0"
+contributes:
+  shortcodes:
+    - function-listing.lua
diff --git a/latest-snapshot/reference/functions/_extensions/function-listing/function-listing.lua b/latest-snapshot/reference/functions/_extensions/function-listing/function-listing.lua
new file mode 100644
index 00000000..460d1570
--- /dev/null
+++ b/latest-snapshot/reference/functions/_extensions/function-listing/function-listing.lua
@@ -0,0 +1,43 @@
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements.  See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership.  The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License.  You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied.  See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+
+return {
+  ["function-listing"] = function(args, kwargs, meta)
+    -- Get the file pattern from arguments (default to "st_*.qmd")
+    local file_pattern = args[1] or "st_*.qmd"
+
+  -- Execute _render_listing.py with the file pattern
+  local cmd = string.format("python3 _render_listing.py '%s'", file_pattern)
+  local handle = io.popen(cmd, "r")
+
+  if not handle then
+    return pandoc.Para{pandoc.Str("Error: Could not execute _render_listing.py")}
+  end
+
+  local result = handle:read("*all")
+  handle:close()
+
+  -- Parse the markdown result and return as pandoc blocks
+  if result and result ~= "" then
+    local doc_result = pandoc.read(result, "markdown")
+    return doc_result.blocks
+  end
+
+  -- Fallback if no result
+  return pandoc.Para{pandoc.Str("No functions found matching pattern: " .. file_pattern)}
+  end
+}
diff --git a/latest-snapshot/reference/functions/_extensions/render-meta-and-examples.lua b/latest-snapshot/reference/functions/_extensions/render-meta-and-examples.lua
new file mode 100644
index 00000000..51e1781f
--- /dev/null
+++ b/latest-snapshot/reference/functions/_extensions/render-meta-and-examples.lua
@@ -0,0 +1,137 @@
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements.  See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership.  The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License.  You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied.  See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+
+-- auto-description.lua
+-- Automatically adds a Description section based on frontmatter using _render_meta.py
+-- Also processes SQL code blocks using _render_examples.py
+
+local function render_sql_example(sql_code)
+  -- Create a temporary file for the SQL
+  local temp_file = os.tmpname()
+
+  -- Write SQL content to temporary file
+  local temp_handle = io.open(temp_file, "w")
+  if not temp_handle then
+    return {pandoc.CodeBlock(sql_code, pandoc.Attr("", {"sql"}, {}))}
+  end
+
+  temp_handle:write(sql_code)
+  temp_handle:close()
+
+  -- Execute _render_examples.py using stdin (with - argument)
+  local cmd = string.format("python3 _render_examples.py - < '%s'", temp_file)
+  local handle = io.popen(cmd, "r")
+  if not handle then
+    os.remove(temp_file)
+    return {pandoc.CodeBlock(sql_code, pandoc.Attr("", {"sql"}, {}))}
+  end
+
+  local result = handle:read("*all")
+  handle:close()
+  os.remove(temp_file)
+
+  -- Parse the markdown result and return as pandoc blocks
+  if result and result ~= "" then
+    local doc_result = pandoc.read(result, "markdown")
+    return doc_result.blocks
+  end
+
+  -- Fallback to original code block if rendering fails
+  return {pandoc.CodeBlock(sql_code, pandoc.Attr("", {"sql"}, {}))}
+end
+
+local function render_meta_content(doc)
+  -- Use Pandoc's JSON encoding (may not work perfectly)
+  local json_content = pandoc.json.encode(doc.meta)
+
+  -- Create a temporary file for the JSON
+  local temp_file = os.tmpname()
+
+  -- Write JSON content to temporary file
+  local temp_handle = io.open(temp_file, "w")
+  if not temp_handle then
+    return pandoc.Para{pandoc.Str("Error: Could not create temporary file")}
+  end
+
+  temp_handle:write(json_content)
+  temp_handle:close()
+
+  -- Pass JSON directly to _render_meta.py (JSON is valid YAML)
+  local cmd = string.format("python3 _render_meta.py - < '%s'", temp_file)
+
+  local handle = io.popen(cmd, "r")
+  if not handle then
+    os.remove(temp_file)
+    return pandoc.Para{pandoc.Str("Error: Could not execute _render_meta.py")}
+  end
+
+  local result = handle:read("*all")
+  if not result then
+    result = "Error: Could not read output from _render_meta.py"
+  end
+
+  handle:close()
+  os.remove(temp_file)  -- Parse the markdown result and return as pandoc blocks
+  if result and result ~= "" then
+    local doc_result = pandoc.read(result, "markdown")
+    return doc_result.blocks
+  end
+
+  return {}
+end
+
+function Pandoc(doc)
+  local description = doc.meta.description
+
+  if description and description ~= "" then
+    -- First pass: Process all existing SQL code blocks before generating new content
+    local new_blocks = {}
+    for i, block in ipairs(doc.blocks) do
+      if block.t == "CodeBlock" and block.classes and #block.classes > 0 and block.classes[1] == "sql" then
+        local rendered_blocks = render_sql_example(block.text)
+        -- Add all rendered blocks to new_blocks
+        for _, rendered_block in ipairs(rendered_blocks) do
+          table.insert(new_blocks, rendered_block)
+        end
+      else
+        table.insert(new_blocks, block)
+      end
+    end
+    doc.blocks = new_blocks
+
+    -- Second pass: Generate content using _render_meta.py
+    local meta_blocks = render_meta_content(doc)
+
+    if #meta_blocks > 0 then
+      -- Insert after title (first header) if it exists, otherwise at the beginning
+      local insert_pos = 1
+      for i, block in ipairs(doc.blocks) do
+        if block.t == "Header" and block.level == 1 then
+          insert_pos = i + 1
+          break
+        end
+      end
+
+      -- Insert the generated blocks
+      for j, block in ipairs(meta_blocks) do
+        table.insert(doc.blocks, insert_pos + j - 1, block)
+      end
+    end
+  end
+
+  return doc
+end
diff --git a/latest-snapshot/requirements.txt b/latest-snapshot/reference/functions/_matplotlib_defaults.py
similarity index 82%
copy from latest-snapshot/requirements.txt
copy to latest-snapshot/reference/functions/_matplotlib_defaults.py
index 6bd80c39..4baaa176 100644
--- a/latest-snapshot/requirements.txt
+++ b/latest-snapshot/reference/functions/_matplotlib_defaults.py
@@ -15,15 +15,8 @@
 # specific language governing permissions and limitations
 # under the License.
 
-griffe
-mike
-mkdocs
-mkdocs-git-revision-date-localized-plugin
-mkdocs-glightbox
-mkdocs-macros-plugin
-mkdocs-material
-mkdocstrings[python]
-nbconvert
-pyproj
-ruff
-lonboard
+import matplotlib.pyplot as plt
+
+plt.rcParams["axes.labelsize"] = 8
+plt.rcParams["xtick.labelsize"] = 8
+plt.rcParams["ytick.labelsize"] = 8
diff --git a/latest-snapshot/reference/functions/_quarto.yml b/latest-snapshot/reference/functions/_quarto.yml
new file mode 100644
index 00000000..331ca253
--- /dev/null
+++ b/latest-snapshot/reference/functions/_quarto.yml
@@ -0,0 +1,46 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# This quarto project allows `quarto render` from this directory to be
+# used such that it takes care of executing code blocks to create figures
+# and render standardized frontmatter defining function arguments into
+# usage/argument documentation.
+project:
+  title: "Function Reference"
+format:
+  gfm:
+    # Increase the quality of the figures (the default of 72 is not very
+    # appealing)
+    fig-dpi: 300
+
+# Use jupyter to render python code blocks. We could also use knitr, which
+# is more flexible but requires an R install available.
+engine: jupyter
+
+# By default, don't echo the Python code for Python code blocks. We use these
+# blocks primarily to create figures, not to demo Python code and its output.
+# individual code blocks can add `#| echo: true` to override this default.
+execute:
+  echo: false
+
+# These filters take care of rendering ```sql code blocks, rendering the
+# standardized description/usage/arguments based on document frontmatter,
+# and providing the function-listing shortcode used to list all the functions
+# in index.qmd.
+filters:
+  - _extensions/render-meta-and-examples.lua
+  - _extensions/function-listing
diff --git a/latest-snapshot/reference/functions/_render_examples.py b/latest-snapshot/reference/functions/_render_examples.py
new file mode 100644
index 00000000..1bf1f963
--- /dev/null
+++ b/latest-snapshot/reference/functions/_render_examples.py
@@ -0,0 +1,120 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import sedonadb
+
+sd = sedonadb.connect()
+
+
+def render_examples(examples, width=80, ascii=False):
+    """Renders examples to stdout using SedonaDB for Python
+
+    This takes an iterable of example SQL strings and renders the SQL
+    and the result to stdout. All examples are run in the same
+    context.
+
+    Output:
+
+    ````
+
+    ```sql
+    --- examples that don't return a result are accumulated
+    SET some.config = true;
+    --- when a query does return a result, we end the sql code block
+    --- and print the result
+    SELECT one as 1;
+    ```
+
+    ```
+    <output>
+    ```
+
+    ````
+    """
+    try:
+        examples_iter = iter(examples)
+        while True:
+            render_examples_iter_until_result(examples_iter, width=width, ascii=ascii)
+    except StopIteration:
+        pass
+
+
+def render_examples_iter_until_result(examples_iter, width=80, ascii=False):
+    example = next(examples_iter)
+
+    # Open the block where the SQL is printed
+    print("\n```sql")
+    while example is not None:
+        # Execute the example to get a row count. If this is a resultless
+        # statement (no rows, no cols), don't execute it again to print. This
+        # allows SET and CREATE TABLE statements to "set up" examples. We
+        # could also look for a trailing semicolon (e.g., only print results
+        # of statements without a trailing semicolon) if this approach is
+        # problematic.
+
+        # Echo the example
+        print(example.strip())
+
+        # Parse it
+        df = sd.sql(example)
+
+        # Execute and check emptiness
+        if df.execute() == 0 and not df.schema.names:
+            example = next(examples_iter, None)
+            continue
+
+        # Close the ```sql block
+        print("```\n")
+
+        # Print the result block (executes the query again)
+        print("```")
+        df.show(limit=None, width=width, ascii=ascii)
+        print("```")
+        return
+
+    # If we're here, none of the statements had any output, so we need to close
+    # the sql block
+    print("```\n")
+
+
+if __name__ == "__main__":
+    import argparse
+    import sys
+
+    parser = argparse.ArgumentParser(description="Render SedonaDB SQL examples")
+    parser.add_argument(
+        "examples",
+        nargs="+",
+        help=(
+            "SQL strings to be rendered or `-` to read from stdin. "
+            "When reading from stdin, multiple examples may be separated by "
+            "with `----` on its own line."
+        ),
+    )
+    parser.add_argument("--width", type=int, default=80)
+    parser.add_argument("--ascii", default=False, action="store_true")
+
+    args = parser.parse_args(sys.argv[1:])
+    if args.examples == ["-"]:
+        args.examples = sys.stdin.read().split("\n----\n")
+
+    try:
+        render_examples(args.examples, width=args.width, ascii=args.ascii)
+    except Exception as e:
+        raise ValueError(
+            f"Failed to render examples:\n{'\n----\n'.join(args.examples)}"
+        ) from e
diff --git a/latest-snapshot/reference/functions/_render_listing.py b/latest-snapshot/reference/functions/_render_listing.py
new file mode 100644
index 00000000..464e0d01
--- /dev/null
+++ b/latest-snapshot/reference/functions/_render_listing.py
@@ -0,0 +1,83 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import io
+from pathlib import Path
+import yaml
+
+from _render_meta import render_meta
+
+
+def render_listing(paths):
+    """Lists meta information for zero or more filenames to function .qmd files
+
+    Output:
+
+    ```
+    ## [ST_Name](st_name.md)
+
+    <description>
+
+    ## Usage
+
+    return_type ST_Name(arg_name: arg_type)
+    ```
+    """
+    for file in paths:
+        raw_meta = read_frontmatter(file)
+        link_href = file.name.replace(".qmd", ".md")
+        print(f"\n## [{raw_meta['title']}]({link_href})\n\n")
+
+        render_meta(raw_meta, level=2, arguments=False)
+
+
+def read_frontmatter(path):
+    frontmatter = io.StringIO()
+    with open(path) as f:
+        for line in f:
+            if line.strip() == "---":
+                break
+        for line in f:
+            if line.strip() == "---":
+                break
+            frontmatter.write(line)
+    frontmatter.seek(0)
+    return yaml.safe_load(frontmatter)
+
+
+def collect_files(file_glob):
+    return list(sorted(Path(__file__).parent.rglob(file_glob)))
+
+
+if __name__ == "__main__":
+    import argparse
+    import sys
+    import yaml
+
+    parser = argparse.ArgumentParser(description="Render SedonaDB SQL function listing")
+    parser.add_argument(
+        "files",
+        nargs="+",
+        help="Files or globs of files whose frontmatter should be included in the listing",
+    )
+    args = parser.parse_args(sys.argv[1:])
+
+    in_files: list[Path] = []
+    for file_or_glob in args.files:
+        in_files.extend(collect_files(file_or_glob))
+
+    render_listing(in_files)
diff --git a/latest-snapshot/reference/functions/_render_meta.py b/latest-snapshot/reference/functions/_render_meta.py
new file mode 100644
index 00000000..e3465a70
--- /dev/null
+++ b/latest-snapshot/reference/functions/_render_meta.py
@@ -0,0 +1,213 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import io
+
+
+def render_meta(raw_meta, level=1, usage=True, arguments=True):
+    """Render parsed YAML frontmatter into a standardized template
+
+    Output:
+
+    ```
+    <description>
+
+    ## Usage
+
+    return_type ST_Name(arg_name: arg_type)
+
+    ## Arguments
+
+    - **arg_name** (arg_type): Arg description
+    ```
+
+    """
+    if "description" in raw_meta:
+        render_description(raw_meta["description"])
+
+    if "kernels" in raw_meta:
+        for kernel in raw_meta["kernels"]:
+            kernel["args"] = expand_args(kernel["args"])
+
+        if usage:
+            render_usage(raw_meta["title"], raw_meta["kernels"], level)
+
+        if arguments:
+            render_args(raw_meta["kernels"], level=level)
+
+
+def render_description(description):
+    print(to_str(description).strip())
+
+
+def render_usage(name, kernels, level):
+    print(f"\n{heading(level + 1)} Usage\n")
+    print("\n```sql")
+    for kernel in kernels:
+        args = ", ".join(render_usage_arg(arg) for arg in kernel["args"])
+        print(f"{to_str(kernel['returns'])} {to_str(name)}({args})")
+    print("```")
+
+
+def render_usage_arg(arg):
+    if arg["default"] is not None:
+        return f"{arg['name']}: {arg['type']} = {arg['default']}"
+    else:
+        return f"{arg['name']}: {arg['type']}"
+
+
+def render_args(kernels, level):
+    try:
+        expanded_args = {}
+        for kernel in reversed(kernels):
+            args_dict = {arg["name"]: arg for arg in kernel["args"]}
+            expanded_args.update({k: v for k, v in args_dict.items() if v is not None})
+    except Exception as e:
+        raise ValueError(
+            f"Failed to consolidate argument documentation from kernels:\n{kernels}"
+        ) from e
+
+    print(f"\n{heading(level + 1)} Arguments\n")
+    for arg in expanded_args.values():
+        print(
+            f"- **{to_str(arg['name'])}** ({to_str(arg['type'])}): {to_str(arg['description'])}"
+        )
+
+
+def expand_args(args):
+    """Normalizes frontmatter-specified arguments
+
+    This enables shorthand argument definitions like "geometry" to coexist
+    with more verbosely defined argument definitions.
+    """
+    args = [expand_arg(arg) for arg in args]
+    return deduplicate_common_arg_combinations(args)
+
+
+def deduplicate_common_arg_combinations(expanded_args):
+    """Transform argument names for binary functions with multiple geometry inputs
+
+    Functions like ST_Intersects() that accept two geometries or two geographies
+    will both have auto-generated function names [geom, geom]. This function
+    renames them to [geomA, geomB].
+    """
+    all_names = [arg["name"] for arg in expanded_args]
+    if all_names[:2] == ["geom", "geom"]:
+        all_names[:2] = ["geomA", "geomB"]
+    elif all_names[:2] == ["geog", "geog"]:
+        all_names[:2] = ["geogA", "geogB"]
+
+    return [
+        {
+            "name": new_name,
+            "type": arg["type"],
+            "description": arg["description"],
+            "default": arg["default"],
+        }
+        for arg, new_name in zip(expanded_args, all_names)
+    ]
+
+
+def expand_arg(arg):
+    """Ensure each arg definition is a dict with keys type, name, description,
+    and default
+    """
+    if isinstance(arg, dict):
+        arg = {k: to_str(v) for k, v in arg.items()}
+    else:
+        arg = to_str(arg)
+        arg = {
+            "type": arg,
+            "name": DEFAULT_ARG_NAMES[arg],
+            "description": DEFAULT_ARG_DESCRIPTIONS.get(arg, None),
+        }
+
+    if "default" not in arg:
+        arg["default"] = None
+    if "description" not in arg:
+        arg["description"] = None
+
+    return arg
+
+
+# Define some default argument names/descriptions so that we can abbreviate
+# the ubiquitous "geometry" input type argument without repeating the string
+# "geom: Input geometry" for every single function.
+DEFAULT_ARG_NAMES = {
+    "geometry": "geom",
+    "geography": "geog",
+    "raster": "rast",
+}
+
+DEFAULT_ARG_DESCRIPTIONS = {
+    "geometry": "Input geometry",
+    "geography": "Input geography",
+    "raster": "Input raster",
+}
+
+
+def heading(level):
+    return "#" * level + " "
+
+
+def to_str(v):
+    """Convert a value to a string
+
+    Because we call this from within a Quarto filter and use pandoc's built-in
+    JSON output, we might get a pandoc JSONified AST here. Parsing the AST here
+    is slightly easier than getting the Quarto filter to recreate the initial
+    YAML frontmatter.
+    """
+    if isinstance(v, str):
+        return v
+
+    if isinstance(v, dict):
+        if v["t"] == "Str":
+            return v["c"]
+        if v["t"] == "Code":
+            return f"`{v['c'][1]}`"
+        elif v["t"] == "Space":
+            return " "
+        elif v["t"] == "Para":
+            return "".join(to_str(item) for item in v["c"])
+        else:
+            raise ValueError(f"Unhandled type in Pandoc ast convert: {v}")
+    else:
+        return "".join(to_str(item) for item in v)
+
+
+if __name__ == "__main__":
+    import argparse
+    import sys
+    import yaml
+
+    parser = argparse.ArgumentParser(description="Render SedonaDB SQL function header")
+    parser.add_argument(
+        "meta",
+        help=(
+            "Function yaml metadata (e.g., frontmatter for a function doc page). "
+            "Use `-` to read stdin."
+        ),
+    )
+
+    args = parser.parse_args(sys.argv[1:])
+    if args.meta == "-":
+        args.meta = sys.stdin.read()
+
+    with io.StringIO(args.meta) as f:
+        raw_meta = yaml.safe_load(f)
+        render_meta(raw_meta)
diff --git a/latest-snapshot/requirements.txt b/latest-snapshot/reference/functions/index.qmd
similarity index 82%
copy from latest-snapshot/requirements.txt
copy to latest-snapshot/reference/functions/index.qmd
index 6bd80c39..7c2ea8c6 100644
--- a/latest-snapshot/requirements.txt
+++ b/latest-snapshot/reference/functions/index.qmd
@@ -1,3 +1,4 @@
+---
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -15,15 +16,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
-griffe
-mike
-mkdocs
-mkdocs-git-revision-date-localized-plugin
-mkdocs-glightbox
-mkdocs-macros-plugin
-mkdocs-material
-mkdocstrings[python]
-nbconvert
-pyproj
-ruff
-lonboard
+title: "SQL Function Reference"
+---
+
+{{< function-listing st_*.qmd >}}
diff --git a/latest-snapshot/reference/functions/st_analyze_agg.qmd b/latest-snapshot/reference/functions/st_analyze_agg.qmd
new file mode 100644
index 00000000..e9b1de6a
--- /dev/null
+++ b/latest-snapshot/reference/functions/st_analyze_agg.qmd
@@ -0,0 +1,49 @@
+---
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+title: ST_Analyze_Agg
+description: Compute the statistics of geometries for the input geometry.
+kernels:
+  - returns: struct
+    args: [geometry]
+---
+
+## Description
+
+`ST_Analyze_Agg()` provides a high-level summary of its input geometries. The fields of
+its struct return type are:
+
+- `count`: Number of input geometries
+- `minx`, `miny`, `maxx`, `maxy`: Minimum bounding rectangle (envelope)
+- `mean_size_in_bytes`
+- `mean_points_per_geometry`
+- `puntal_count`: Number of point or multipoint geometries
+- `lineal_count`: Number of line or multilinestring geometries
+- `polygonal_count`: Number of polygon or multipolygon geometries
+- `geometrycollection_count`: Number of geometrycollection geometries
+- `mean_envelope_width`
+- `mean_envelope_height`
+- `mean_envelope_area`
+
+## Examples
+
+```sql
+SELECT ST_Analyze_Agg(
+    ST_GeomFromText('MULTIPOINT(1.1 101.1,2.1 102.1,3.1 103.1,4.1 104.1,5.1 105.1,6.1 106.1,7.1 107.1,8.1 108.1,9.1 109.1,10.1 110.1)')
+  ) AS analyze
+```
diff --git a/latest-snapshot/reference/functions/st_buffer.qmd b/latest-snapshot/reference/functions/st_buffer.qmd
new file mode 100644
index 00000000..64f807c8
--- /dev/null
+++ b/latest-snapshot/reference/functions/st_buffer.qmd
@@ -0,0 +1,81 @@
+---
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+title: ST_Buffer
+description: >
+    Computes a geometry that represents all points whose distance from the input
+    geometry is less than or equal to a specified distance.
+kernels:
+  - returns: geometry
+    args:
+    - geometry
+    - name: distance
+      type: float64
+      description: Radius of the buffer
+  - returns: geometry
+    args:
+    - geometry
+    - name: distance
+      type: float64
+    - name: params
+      type: utf8
+      description: >
+        Space-separated `key=value` parameters. Supported parameters include `quad_segs`,
+        `endcap`, `join`, `mitre_limit`, and `side`. These parameters are identical to
+        the PostGIS buffer parameter strings.
+---
+
+## Examples
+
+```sql
+SELECT ST_Buffer(
+  ST_GeomFromText('POLYGON ((10 10, 11 10, 10 11, 10 10))'),
+  1.0
+) AS geom;
+```
+
+```{python}
+import _matplotlib_defaults
+import sedonadb
+
+sd = sedonadb.connect()
+
+sd.sql("""
+SELECT ST_GeomFromText('POLYGON ((10 10, 11 10, 10 11, 10 10))') as geom
+""").to_view("input")
+
+df = sd.sql("SELECT *, ST_Buffer(geom, 1.0) AS result FROM input").to_pandas()
+
+ax = df.geom.plot(alpha=0.5)
+df.result.plot(ax=ax, facecolor='none', edgecolor='red')
+```
+
+```sql
+SELECT ST_Buffer(
+  ST_GeomFromText('POLYGON ((10 10, 11 10, 10 11, 10 10))'),
+  1.0,
+  'quad_segs=2'
+) AS geom;
+```
+
+```{python}
+df = sd.sql("SELECT *, ST_Buffer(geom, 1.0, 'quad_segs=2') AS result FROM input").to_pandas()
+
+ax = df.geom.plot(alpha=0.5)
+df.result.plot(ax=ax, facecolor='none', edgecolor='red')
+```
diff --git a/latest-snapshot/reference/functions/st_intersection.qmd b/latest-snapshot/reference/functions/st_intersection.qmd
new file mode 100644
index 00000000..2bdc47be
--- /dev/null
+++ b/latest-snapshot/reference/functions/st_intersection.qmd
@@ -0,0 +1,54 @@
+---
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+title: ST_Intersection
+description: Compute the intersection of two geometries or geographies.
+kernels:
+  - returns: geometry
+    args: [geometry, geometry]
+  - returns: geography
+    args: [geography, geography]
+---
+
+## Examples
+
+```sql
+SELECT ST_Intersection(
+    ST_GeomFromText('POLYGON ((1 1, 11 1, 11 11, 1 11, 1 1))'),
+    ST_GeomFromText('POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))')
+) AS val;
+```
+
+```{python}
+import _matplotlib_defaults
+import sedonadb
+
+sd = sedonadb.connect()
+
+sd.sql("""
+SELECT
+    ST_GeomFromText('POLYGON ((1 1, 11 1, 11 11, 1 11, 1 1))') as geom_a,
+    ST_GeomFromText('POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))') as geom_b
+""").to_view("input")
+
+df = sd.sql("SELECT *, ST_Intersection(geom_a, geom_b) as result FROM input").to_pandas()
+
+ax = df.geom_a.plot(alpha=0.5)
+df.geom_b.plot(ax=ax, alpha=0.5)
+df.result.plot(ax=ax, facecolor='none', edgecolor='red')
+```
diff --git a/latest-snapshot/requirements.txt b/latest-snapshot/requirements.txt
index 6bd80c39..53f6716c 100644
--- a/latest-snapshot/requirements.txt
+++ b/latest-snapshot/requirements.txt
@@ -16,6 +16,7 @@
 # under the License.
 
 griffe
+ipykernel
 mike
 mkdocs
 mkdocs-git-revision-date-localized-plugin
diff --git a/latest-snapshot/search/search_index.json b/latest-snapshot/search/search_index.json
index 104f8e32..ebe40416 100644
--- a/latest-snapshot/search/search_index.json
+++ b/latest-snapshot/search/search_index.json
@@ -1 +1 @@
-{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Introducing SedonaDB","text":"<p>SedonaDB is an open-source single-node analytical database engine with geospatial as a first-class citizen. It aims to deliver the fastest spatial analytics query speed and the most comprehensive function coverage available.</p> <p>SedonaDB is perfect for process [...]
\ No newline at end of file
+{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Introducing SedonaDB","text":"<p>SedonaDB is an open-source single-node analytical database engine with geospatial as a first-class citizen. It aims to deliver the fastest spatial analytics query speed and the most comprehensive function coverage available.</p> <p>SedonaDB is perfect for process [...]
\ No newline at end of file