diff --git a/Cargo.lock b/Cargo.lock index 29f8c42a..57b681de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3602,6 +3602,7 @@ dependencies = [ "blake3", "bytes", "chrono", + "chrono-tz", "fast-float2", "fs4", "futures", @@ -3640,6 +3641,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dd2126daebf58da564fc5840cd55eb8eb2479d24dfced0a1aea2178a9b33b12" dependencies = [ "chrono", + "chrono-tz", "fallible-streaming-iterator", "hashbrown 0.16.1", "indexmap", diff --git a/doc/syntax/scale/aesthetic/generate_examples.R b/doc/syntax/scale/aesthetic/generate_examples.R index 4498ad90..9ab782b8 100644 --- a/doc/syntax/scale/aesthetic/generate_examples.R +++ b/doc/syntax/scale/aesthetic/generate_examples.R @@ -9,25 +9,84 @@ CONTINUOUS_PALETTES <- c( # ggsql default "sequential", # Crameri Sequential - "navia", "batlow", "batlowk", "batloww", "hawaii", "lajolla", "tokyo", - "turku", "acton", "bamako", "bilbao", "buda", "davos", "devon", "glasgow", - "grayc", "imola", "lapaz", "lipari", "nuuk", "oslo", + "navia", + "batlow", + "batlowk", + "batloww", + "hawaii", + "lajolla", + "tokyo", + "turku", + "acton", + "bamako", + "bilbao", + "buda", + "davos", + "devon", + "glasgow", + "grayc", + "imola", + "lapaz", + "lipari", + "nuuk", + "oslo", # Crameri Multi-Sequential - "bukavu", "fes", "oleron", + "bukavu", + "fes", + "oleron", # Crameri Diverging - "vik", "berlin", "roma", "bam", "broc", "cork", "lisbon", "managua", - "tofino", "vanimo", + "vik", + "berlin", + "roma", + "bam", + "broc", + "cork", + "lisbon", + "managua", + "tofino", + "vanimo", # Crameri Cyclic - "romao", "bamo", "broco", "corko", "viko", + "romao", + "bamo", + "broco", + "corko", + "viko", # ColorBrewer Single-hue - "blues", "greens", "oranges", "reds", "purples", "greys", + "blues", + "greens", + "oranges", + "reds", + "purples", + "greys", # ColorBrewer Multi-hue - "ylorbr", "ylorrd", "ylgn", "ylgnbu", "gnbu", "bugn", "bupu", "pubu", - "pubugn", "purd", "rdpu", "orrd", + "ylorbr", + "ylorrd", + "ylgn", + "ylgnbu", + "gnbu", + "bugn", + "bupu", + "pubu", + "pubugn", + "purd", + "rdpu", + "orrd", # ColorBrewer Diverging - "rdbu", "rdylbu", "rdylgn", "spectral", "brbg", "prgn", "piyg", "rdgy", "puor", + "rdbu", + "rdylbu", + "rdylgn", + "spectral", + "brbg", + "prgn", + "piyg", + "rdgy", + "puor", # Matplotlib - "viridis", "plasma", "magma", "inferno", "cividis" + "viridis", + "plasma", + "magma", + "inferno", + "cividis" ) # Discrete palettes referenced in color_disc.qmd @@ -39,8 +98,11 @@ DISCRETE_PALETTES <- c( # D3 "category10", # ColorBrewer qualitative - "set1", "set2", "set3", - "pastel1", "pastel2", + "set1", + "set2", + "set3", + "pastel1", + "pastel2", "dark2", "paired", "accent", @@ -52,18 +114,27 @@ DISCRETE_PALETTES <- c( # Format: name = c(dash, gap, dash, gap, ...) # Empty vector means solid line NAMED_LINETYPES <- list( - solid = c(), - dashed = c(6, 4), - dotted = c(1, 2), - dotdash = c(1, 2, 6, 2), + solid = c(), + dashed = c(6, 4), + dotted = c(1, 2), + dotdash = c(1, 2, 6, 2), longdash = c(10, 4), - twodash = c(6, 2, 2, 2) + twodash = c(6, 2, 2, 2) ) # Shape definitions # Closed shapes (filled) -SHAPES_CLOSED <- c("circle", "square", "diamond", "triangle-up", "triangle-down", - "star", "square-cross", "circle-plus", "square-plus") +SHAPES_CLOSED <- c( + "circle", + "square", + "diamond", + "triangle-up", + "triangle-down", + "star", + "square-cross", + "circle-plus", + "square-plus" +) # Open shapes (stroke only) SHAPES_OPEN <- c("cross", "plus", "asterisk", "bowtie", "hline", "vline") # All shapes @@ -78,7 +149,6 @@ parse_palettes <- function(rust_file) { palettes <- list() - # Pattern to match: pub const NAME: &[&str] = &[ ... ]; # We need to find each palette definition pattern <- 'pub const ([A-Z_0-9]+): &\\[&str\\] = &\\[([^;]+)\\];' @@ -89,14 +159,23 @@ parse_palettes <- function(rust_file) { for (match in all_matches) { # Extract name - name_match <- regmatches(match, regexec('pub const ([A-Z_0-9]+):', match, perl = TRUE))[[1]] - if (length(name_match) < 2) next + name_match <- regmatches( + match, + regexec('pub const ([A-Z_0-9]+):', match, perl = TRUE) + )[[1]] + if (length(name_match) < 2) { + next + } name <- tolower(name_match[2]) # Extract colors colors_section <- sub('.*&\\[', '', match) colors_section <- sub('\\];.*', '', colors_section) - color_matches <- gregexpr('"(#[0-9A-Fa-f]{6})"', colors_section, perl = TRUE) + color_matches <- gregexpr( + '"(#[0-9A-Fa-f]{6})"', + colors_section, + perl = TRUE + ) colors <- regmatches(colors_section, color_matches)[[1]] colors <- gsub('"', '', colors) @@ -124,15 +203,23 @@ generate_gradient_svg <- function(colors, width = 600, height = 60) { } # Build gradient stops - stops <- vapply(seq_along(sampled), function(i) { - offset <- (i - 1) / (length(sampled) - 1) * 100 - sprintf(' ', offset, sampled[i]) - }, character(1)) + stops <- vapply( + seq_along(sampled), + function(i) { + offset <- (i - 1) / (length(sampled) - 1) * 100 + sprintf( + ' ', + offset, + sampled[i] + ) + }, + character(1) + ) stops_str <- paste(stops, collapse = "\n") svg <- sprintf( -' + ' %s @@ -140,7 +227,11 @@ generate_gradient_svg <- function(colors, width = 600, height = 60) { ', - width, height, stops_str, width, height + width, + height, + stops_str, + width, + height ) svg @@ -152,24 +243,40 @@ generate_gradient_svg <- function(colors, width = 600, height = 60) { #' @param swatch_height Height of each swatch in pixels #' @param gap Gap between swatches in pixels #' @return SVG content as string -generate_swatch_svg <- function(colors, swatch_width = 40, swatch_height = 60, gap = 2) { +generate_swatch_svg <- function( + colors, + swatch_width = 40, + swatch_height = 60, + gap = 2 +) { n <- length(colors) total_width <- n * swatch_width + (n - 1) * gap # Build rectangles for each color - rects <- vapply(seq_along(colors), function(i) { - x <- (i - 1) * (swatch_width + gap) - sprintf(' ', - x, swatch_width, swatch_height, colors[i]) - }, character(1)) + rects <- vapply( + seq_along(colors), + function(i) { + x <- (i - 1) * (swatch_width + gap) + sprintf( + ' ', + x, + swatch_width, + swatch_height, + colors[i] + ) + }, + character(1) + ) rects_str <- paste(rects, collapse = "\n") svg <- sprintf( -' + ' %s ', - total_width, swatch_height, rects_str + total_width, + swatch_height, + rects_str ) svg @@ -182,7 +289,13 @@ generate_swatch_svg <- function(colors, swatch_width = 40, swatch_height = 60, g #' @param height SVG height in pixels #' @param stroke_width Width of the line #' @return SVG content as string -generate_linetype_svg <- function(name, dasharray, width = 200, height = 40, stroke_width = 3) { +generate_linetype_svg <- function( + name, + dasharray, + width = 200, + height = 40, + stroke_width = 3 +) { y <- height / 2 if (length(dasharray) == 0) { @@ -190,14 +303,23 @@ generate_linetype_svg <- function(name, dasharray, width = 200, height = 40, str } else { # Scale dasharray values by stroke width (ggplot2 convention) scaled_dash <- dasharray * stroke_width - dash_attr <- sprintf(' stroke-dasharray="%s"', paste(scaled_dash, collapse=" ")) + dash_attr <- sprintf( + ' stroke-dasharray="%s"', + paste(scaled_dash, collapse = " ") + ) } svg <- sprintf( -' + ' ', - width, height, y, width - 10, y, stroke_width, dash_attr + width, + height, + y, + width - 10, + y, + stroke_width, + dash_attr ) svg @@ -214,7 +336,8 @@ get_shape_path <- function(name, size = 12, cx = 20, cy = 20) { # Reference: circle with radius 1.0 has area π # All shapes scaled to have approximately equal visual area - path <- switch(name, + path <- switch( + name, "circle" = { # Circle as SVG circle element (handled separately) NULL @@ -222,27 +345,59 @@ get_shape_path <- function(name, size = 12, cx = 20, cy = 20) { "square" = { # Half-side 0.71/0.8 = 0.89 of base size for equal area s <- size * 0.89 - sprintf("M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", - cx - s, cy - s, cx + s, cy - s, cx + s, cy + s, cx - s, cy + s) + sprintf( + "M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", + cx - s, + cy - s, + cx + s, + cy - s, + cx + s, + cy + s, + cx - s, + cy + s + ) }, "diamond" = { # Half-diagonal 0.89/0.8 = 1.11 of base size for equal area d <- size * 1.11 - sprintf("M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", - cx, cy - d, cx + d, cy, cx, cy + d, cx - d, cy) + sprintf( + "M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", + cx, + cy - d, + cx + d, + cy, + cx, + cy + d, + cx - d, + cy + ) }, "triangle-up" = { # Scaled up by 0.92/0.8 = 1.15 for equal area r <- size * 1.15 h <- r * 0.75 - sprintf("M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", - cx, cy - r, cx + r, cy + h, cx - r, cy + h) + sprintf( + "M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", + cx, + cy - r, + cx + r, + cy + h, + cx - r, + cy + h + ) }, "triangle-down" = { r <- size * 1.15 h <- r * 0.75 - sprintf("M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", - cx - r, cy - h, cx + r, cy - h, cx, cy + r) + sprintf( + "M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", + cx - r, + cy - h, + cx + r, + cy - h, + cx, + cy + r + ) }, "star" = { # Outer radius 0.95/0.8 = 1.19 of base size for equal area @@ -261,14 +416,32 @@ get_shape_path <- function(name, size = 12, cx = 20, cy = 20) { "cross" = { # X shape - scaled by 1/√2 so diagonal length matches plus's axis-aligned length s <- size / sqrt(2) - sprintf("M%.1f,%.1f L%.1f,%.1f M%.1f,%.1f L%.1f,%.1f", - cx - s, cy - s, cx + s, cy + s, cx + s, cy - s, cx - s, cy + s) + sprintf( + "M%.1f,%.1f L%.1f,%.1f M%.1f,%.1f L%.1f,%.1f", + cx - s, + cy - s, + cx + s, + cy + s, + cx + s, + cy - s, + cx - s, + cy + s + ) }, "plus" = { # + shape s <- size - sprintf("M%.1f,%.1f L%.1f,%.1f M%.1f,%.1f L%.1f,%.1f", - cx - s, cy, cx + s, cy, cx, cy - s, cx, cy + s) + sprintf( + "M%.1f,%.1f L%.1f,%.1f M%.1f,%.1f L%.1f,%.1f", + cx - s, + cy, + cx + s, + cy, + cx, + cy - s, + cx, + cy + s + ) }, "hline" = { # Horizontal line @@ -297,9 +470,21 @@ get_shape_path <- function(name, size = 12, cx = 20, cy = 20) { "bowtie" = { # Two triangles pointing inward s <- size - sprintf("M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", - cx - s, cy - s * 0.7, cx, cy, cx - s, cy + s * 0.7, - cx + s, cy - s * 0.7, cx, cy, cx + s, cy + s * 0.7) + sprintf( + "M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", + cx - s, + cy - s * 0.7, + cx, + cy, + cx - s, + cy + s * 0.7, + cx + s, + cy - s * 0.7, + cx, + cy, + cx + s, + cy + s * 0.7 + ) }, "square-cross" = { # Square with X-shaped cutout (handled specially in generate_shape_svg) @@ -332,10 +517,14 @@ generate_shape_svg <- function(name, size = 40, is_closed = TRUE) { # Special handling for circle if (name == "circle") { svg <- sprintf( -' + ' ', - size, size, cx, cy, shape_size, + size, + size, + cx, + cy, + shape_size, if (is_closed) "#333333" else "none" ) return(svg) @@ -344,34 +533,36 @@ generate_shape_svg <- function(name, size = 40, is_closed = TRUE) { # Special handling for circle-plus (circle divided into 4 quarters with constant-width gap) if (name == "circle-plus") { r <- shape_size - g <- shape_size * 0.15 / sqrt(2) # gap half-width, scaled to match X visually - n <- 8 # points per quarter arc + g <- shape_size * 0.15 / sqrt(2) # gap half-width, scaled to match X visually + n <- 8 # points per quarter arc # Where circle intersects gap edge edge <- sqrt(r^2 - g^2) # Start angle for arc (where y = g on circle) start_angle <- asin(g / r) - end_angle <- pi/2 - start_angle + end_angle <- pi / 2 - start_angle paths <- character(4) for (q in 0:3) { base_angle <- q * pi / 2 # Inner corner point - corner <- switch(q + 1, - c(cx + g, cy + g), # q=0: top-right - c(cx - g, cy + g), # q=1: top-left - c(cx - g, cy - g), # q=2: bottom-left - c(cx + g, cy - g) # q=3: bottom-right + corner <- switch( + q + 1, + c(cx + g, cy + g), # q=0: top-right + c(cx - g, cy + g), # q=1: top-left + c(cx - g, cy - g), # q=2: bottom-left + c(cx + g, cy - g) # q=3: bottom-right ) # Point where gap meets circle (start of arc) - gap_start <- switch(q + 1, - c(cx + edge, cy + g), # right edge of horizontal gap - c(cx - g, cy + edge), # top edge of vertical gap - c(cx - edge, cy - g), # left edge of horizontal gap - c(cx + g, cy - edge) # bottom edge of vertical gap + gap_start <- switch( + q + 1, + c(cx + edge, cy + g), # right edge of horizontal gap + c(cx - g, cy + edge), # top edge of vertical gap + c(cx - edge, cy - g), # left edge of horizontal gap + c(cx + g, cy - edge) # bottom edge of vertical gap ) # Arc points @@ -384,27 +575,34 @@ generate_shape_svg <- function(name, size = 40, is_closed = TRUE) { }) # Point where arc meets gap (end of arc) - gap_end <- switch(q + 1, - c(cx + g, cy + edge), # top edge of vertical gap - c(cx - edge, cy + g), # left edge of horizontal gap - c(cx - g, cy - edge), # bottom edge of vertical gap - c(cx + edge, cy - g) # right edge of horizontal gap + gap_end <- switch( + q + 1, + c(cx + g, cy + edge), # top edge of vertical gap + c(cx - edge, cy + g), # left edge of horizontal gap + c(cx - g, cy - edge), # bottom edge of vertical gap + c(cx + edge, cy - g) # right edge of horizontal gap ) # Build path: corner -> gap_start -> arc -> gap_end -> close - paths[q + 1] <- sprintf("M%.1f,%.1f L%.1f,%.1f L%s L%.1f,%.1f Z", - corner[1], corner[2], - gap_start[1], gap_start[2], + paths[q + 1] <- sprintf( + "M%.1f,%.1f L%.1f,%.1f L%s L%.1f,%.1f Z", + corner[1], + corner[2], + gap_start[1], + gap_start[2], paste(arc_pts, collapse = " L"), - gap_end[1], gap_end[2] + gap_end[1], + gap_end[2] ) } combined_path <- paste(paths, collapse = " ") svg <- sprintf( -' + ' ', - size, size, combined_path + size, + size, + combined_path ) return(svg) } @@ -412,25 +610,55 @@ generate_shape_svg <- function(name, size = 40, is_closed = TRUE) { # Special handling for square-cross (square divided into 4 triangles by X) if (name == "square-cross") { s <- shape_size * 0.89 - g <- shape_size * 0.15 # gap half-width + g <- shape_size * 0.15 # gap half-width # 4 triangles (top, right, bottom, left) paths <- c( - sprintf("M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", - cx - s + g, cy - s, cx + s - g, cy - s, cx, cy - g), # top - sprintf("M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", - cx + s, cy - s + g, cx + s, cy + s - g, cx + g, cy), # right - sprintf("M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", - cx + s - g, cy + s, cx - s + g, cy + s, cx, cy + g), # bottom - sprintf("M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", - cx - s, cy + s - g, cx - s, cy - s + g, cx - g, cy) # left + sprintf( + "M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", + cx - s + g, + cy - s, + cx + s - g, + cy - s, + cx, + cy - g + ), # top + sprintf( + "M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", + cx + s, + cy - s + g, + cx + s, + cy + s - g, + cx + g, + cy + ), # right + sprintf( + "M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", + cx + s - g, + cy + s, + cx - s + g, + cy + s, + cx, + cy + g + ), # bottom + sprintf( + "M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", + cx - s, + cy + s - g, + cx - s, + cy - s + g, + cx - g, + cy + ) # left ) combined_path <- paste(paths, collapse = " ") svg <- sprintf( -' + ' ', - size, size, combined_path + size, + size, + combined_path ) return(svg) } @@ -438,47 +666,91 @@ generate_shape_svg <- function(name, size = 40, is_closed = TRUE) { # Special handling for square-plus (square divided into 4 smaller squares by +) if (name == "square-plus") { s <- shape_size * 0.89 - g <- shape_size * 0.15 / sqrt(2) # gap half-width, scaled to match X visually + g <- shape_size * 0.15 / sqrt(2) # gap half-width, scaled to match X visually # 4 smaller squares in corners paths <- c( - sprintf("M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", - cx - s, cy - s, cx - g, cy - s, cx - g, cy - g, cx - s, cy - g), # top-left - sprintf("M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", - cx + g, cy - s, cx + s, cy - s, cx + s, cy - g, cx + g, cy - g), # top-right - sprintf("M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", - cx + g, cy + g, cx + s, cy + g, cx + s, cy + s, cx + g, cy + s), # bottom-right - sprintf("M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", - cx - s, cy + g, cx - g, cy + g, cx - g, cy + s, cx - s, cy + s) # bottom-left + sprintf( + "M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", + cx - s, + cy - s, + cx - g, + cy - s, + cx - g, + cy - g, + cx - s, + cy - g + ), # top-left + sprintf( + "M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", + cx + g, + cy - s, + cx + s, + cy - s, + cx + s, + cy - g, + cx + g, + cy - g + ), # top-right + sprintf( + "M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", + cx + g, + cy + g, + cx + s, + cy + g, + cx + s, + cy + s, + cx + g, + cy + s + ), # bottom-right + sprintf( + "M%.1f,%.1f L%.1f,%.1f L%.1f,%.1f L%.1f,%.1f Z", + cx - s, + cy + g, + cx - g, + cy + g, + cx - g, + cy + s, + cx - s, + cy + s + ) # bottom-left ) combined_path <- paste(paths, collapse = " ") svg <- sprintf( -' + ' ', - size, size, combined_path + size, + size, + combined_path ) return(svg) } path <- get_shape_path(name, shape_size, cx, cy) - if (is.null(path)) return(NULL) + if (is.null(path)) { + return(NULL) + } if (is_closed) { # Closed shapes: fill only, no stroke svg <- sprintf( -' + ' ', - size, size, path + size, + size, + path ) } else { # Open shapes: stroke only, no fill svg <- sprintf( -' + ' ', - size, size, path + size, + size, + path ) } @@ -489,8 +761,12 @@ generate_shape_svg <- function(name, size = 40, is_closed = TRUE) { #' @param count Number of linetypes to generate #' @return List with names and dasharray values generate_sequential_linetypes <- function(count) { - if (count <= 0) return(list()) - if (count == 1) return(list(solid = c())) + if (count <= 0) { + return(list()) + } + if (count == 1) { + return(list(solid = c())) + } # Generate linetypes from sparse to solid @@ -503,8 +779,8 @@ generate_sequential_linetypes <- function(count) { result[[paste0("seq_", i)]] <- c() } else { # Calculate ink ratio (evenly spaced from min to max) - min_ink <- 1/16 - max_ink <- 15/16 + min_ink <- 1 / 16 + max_ink <- 15 / 16 ink_ratio <- min_ink + (i - 1) * (max_ink - min_ink) / (count - 1) # Convert to on/off pattern (cycle of 16 units) @@ -525,24 +801,39 @@ main <- function() { script_dir <- if (interactive()) { getwd() } else { - dirname(commandArgs(trailingOnly = FALSE)[grep("--file=", commandArgs(trailingOnly = FALSE))]) - script_dir <- sub("--file=", "", commandArgs(trailingOnly = FALSE)[grep("--file=", commandArgs(trailingOnly = FALSE))]) + dirname(commandArgs(trailingOnly = FALSE)[grep( + "--file=", + commandArgs(trailingOnly = FALSE) + )]) + script_dir <- sub( + "--file=", + "", + commandArgs(trailingOnly = FALSE)[grep( + "--file=", + commandArgs(trailingOnly = FALSE) + )] + ) dirname(script_dir) } # Try to find the repo root # Navigate up from doc/syntax/scale/palette to repo root - repo_root <- normalizePath(file.path(script_dir, "..", "..", "..", ".."), mustWork = FALSE) + repo_root <- normalizePath( + file.path(script_dir, "..", "..", "..", ".."), + mustWork = FALSE + ) palettes_file <- file.path(repo_root, "src", "plot", "scale", "palettes.rs") - # If that doesn't work, try relative to current working directory + # If that doesn't work, try relative to current working directory if (!file.exists(palettes_file)) { # Try from repo root directly palettes_file <- "src/plot/scale/palettes.rs" } if (!file.exists(palettes_file)) { - stop("Error: Could not find palettes.rs. Run from repo root or palette directory.") + stop( + "Error: Could not find palettes.rs. Run from repo root or palette directory." + ) } # Output directory (subfolder called "examples") @@ -582,7 +873,11 @@ main <- function() { output_file <- file.path(output_dir, sprintf("gradient_%s.svg", name)) writeLines(svg_content, output_file) generated <- generated + 1 - message(sprintf("Generated: gradient_%s.svg (%d colors)", name, length(colors))) + message(sprintf( + "Generated: gradient_%s.svg (%d colors)", + name, + length(colors) + )) } # Generate swatch SVGs for discrete palettes @@ -598,7 +893,11 @@ main <- function() { output_file <- file.path(output_dir, sprintf("swatch_%s.svg", name)) writeLines(svg_content, output_file) generated <- generated + 1 - message(sprintf("Generated: swatch_%s.svg (%d colors)", name, length(colors))) + message(sprintf( + "Generated: swatch_%s.svg (%d colors)", + name, + length(colors) + )) } # Generate linetype SVGs for named linetypes @@ -630,7 +929,10 @@ main <- function() { for (name in SHAPES_CLOSED) { svg_content <- generate_shape_svg(name, size = 40, is_closed = TRUE) if (!is.null(svg_content)) { - output_file <- file.path(output_dir, sprintf("shape_%s.svg", gsub("-", "_", name))) + output_file <- file.path( + output_dir, + sprintf("shape_%s.svg", gsub("-", "_", name)) + ) writeLines(svg_content, output_file) generated <- generated + 1 message(sprintf("Generated: shape_%s.svg", gsub("-", "_", name))) @@ -642,7 +944,10 @@ main <- function() { for (name in SHAPES_OPEN) { svg_content <- generate_shape_svg(name, size = 40, is_closed = FALSE) if (!is.null(svg_content)) { - output_file <- file.path(output_dir, sprintf("shape_%s.svg", gsub("-", "_", name))) + output_file <- file.path( + output_dir, + sprintf("shape_%s.svg", gsub("-", "_", name)) + ) writeLines(svg_content, output_file) generated <- generated + 1 message(sprintf("Generated: shape_%s.svg", gsub("-", "_", name))) @@ -652,7 +957,10 @@ main <- function() { message(sprintf("\nGenerated %d SVG files total", generated)) if (length(missing) > 0) { - message(sprintf("\nWarning: %d palettes not found in source:", length(missing))) + message(sprintf( + "\nWarning: %d palettes not found in source:", + length(missing) + )) for (name in missing) { message(sprintf(" - %s", name)) } diff --git a/ggsql-R/.Rbuildignore b/ggsql-R/.Rbuildignore index fc296354..879ee66c 100644 --- a/ggsql-R/.Rbuildignore +++ b/ggsql-R/.Rbuildignore @@ -1,3 +1,11 @@ ^ggsql\.Rproj$ ^\.Rproj\.user$ ^LICENSE\.md$ +^\.vscode$ +^src/\.cargo$ +^src/rust/vendor$ +^src/rust/target$ +^src/Makevars$ +^src/Makevars\.win$ +^README\.Rmd$ +^air\.toml$ diff --git a/ggsql-R/.gitignore b/ggsql-R/.gitignore index cd67eac6..516d7073 100644 --- a/ggsql-R/.gitignore +++ b/ggsql-R/.gitignore @@ -1 +1,10 @@ .Rproj.user +src/rust/vendor +src/rust/target +src/Makevars +src/Makevars.win +src/*.o +src/*.so +src/*.dll +src/rust/test_files +inst/doc diff --git a/ggsql-R/.vscode/extensions.json b/ggsql-R/.vscode/extensions.json new file mode 100644 index 00000000..344f76eb --- /dev/null +++ b/ggsql-R/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "Posit.air-vscode" + ] +} diff --git a/ggsql-R/.vscode/settings.json b/ggsql-R/.vscode/settings.json new file mode 100644 index 00000000..ff53f442 --- /dev/null +++ b/ggsql-R/.vscode/settings.json @@ -0,0 +1,21 @@ +{ + "rust-analyzer.linkedProjects": [ + "${workspaceFolder}/src/rust/Cargo.toml" + ], + "files.associations": { + "Makevars.in": "makefile", + "Makevars.win": "makefile", + "configure": "shellscript", + "configure.win": "shellscript", + "cleanup": "shellscript", + "cleanup.win": "shellscript" + }, + "[r]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "Posit.air-vscode" + }, + "[quarto]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "quarto.quarto" + } +} diff --git a/ggsql-R/DESCRIPTION b/ggsql-R/DESCRIPTION index 6bfd64c3..80eae4a3 100644 --- a/ggsql-R/DESCRIPTION +++ b/ggsql-R/DESCRIPTION @@ -1,6 +1,6 @@ Package: ggsql Title: A SQL extension for declarative data visualization based on the Grammar of Graphics -Version: 0.0.0.9000 +Version: 0.1.9 Authors@R: c( person("George", "Stagg", , "george.stagg@posit.co", role = c("aut", "cre"), comment = c(ORCID = "0009-0006-3173-9846")), @@ -15,17 +15,29 @@ Description: ggsql allows you to write queries that combine SQL data retrieval with visualization specifications in a single, composable syntax. License: MIT + file LICENSE Encoding: UTF-8 -SystemRequirements: ggsql +SystemRequirements: Cargo (Rust's package manager), rustc Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.3 Imports: + cli, + htmltools, + jsonlite, knitr, + nanoarrow, + R6, rlang, - vegawidget + yaml Suggests: - png, + gapminder, + quarto, + reticulate, + rmarkdown, rsvg, testthat (>= 3.0.0), V8, withr Config/testthat/edition: 3 +Config/rextendr/version: 0.4.2.9000 +Depends: + R (>= 4.2) +VignetteBuilder: quarto diff --git a/ggsql-R/NAMESPACE b/ggsql-R/NAMESPACE index cfe11849..2c4573c2 100644 --- a/ggsql-R/NAMESPACE +++ b/ggsql-R/NAMESPACE @@ -1,4 +1,42 @@ # Generated by roxygen2: do not edit by hand -importFrom(rlang,on_load) -importFrom(rlang,run_on_load) +S3method("$",GgsqlReader) +S3method("$",GgsqlSpec) +S3method("$",GgsqlWriter) +S3method("$",ggsql_tables) +S3method("[[",GgsqlReader) +S3method("[[",GgsqlSpec) +S3method("[[",GgsqlWriter) +S3method("[[",ggsql_tables) +S3method(knit_print,Spec) +S3method(names,ggsql_tables) +S3method(print,ggsql_tables) +S3method(print,ggsql_validated) +S3method(str,Spec) +export(duckdb_reader) +export(ggsql_execute) +export(ggsql_execute_sql) +export(ggsql_has_visual) +export(ggsql_is_valid) +export(ggsql_layer_count) +export(ggsql_layer_data) +export(ggsql_layer_sql) +export(ggsql_metadata) +export(ggsql_register) +export(ggsql_render) +export(ggsql_save) +export(ggsql_sql) +export(ggsql_stat_data) +export(ggsql_stat_sql) +export(ggsql_table) +export(ggsql_table_names) +export(ggsql_unregister) +export(ggsql_validate) +export(ggsql_visual) +export(ggsql_warnings) +export(vegalite_writer) +import(rlang) +importFrom(R6,R6Class) +importFrom(knitr,knit_print) +importFrom(utils,str) +useDynLib(ggsql, .registration = TRUE) diff --git a/ggsql-R/R/convert.R b/ggsql-R/R/convert.R new file mode 100644 index 00000000..2c6b62d8 --- /dev/null +++ b/ggsql-R/R/convert.R @@ -0,0 +1,27 @@ +#' Convert a data.frame to Arrow IPC stream bytes +#' @param df A data.frame. +#' @return Raw vector of Arrow IPC stream bytes. +#' @noRd +df_to_ipc <- function(df) { + # Convert factors to character — nanoarrow doesn't support dictionary IPC encoding + factor_cols <- vapply(df, is.factor, logical(1)) + if (any(factor_cols)) { + df[factor_cols] <- lapply(df[factor_cols], as.character) + } + stream <- nanoarrow::as_nanoarrow_array_stream(df) + con <- rawConnection(raw(0), "wb") + on.exit(close(con)) + nanoarrow::write_nanoarrow(stream, con) + rawConnectionValue(con) +} + +#' Convert Arrow IPC stream bytes to a data.frame +#' @param ipc_bytes Raw vector of Arrow IPC stream bytes. +#' @return A data.frame. +#' @noRd +ipc_to_df <- function(ipc_bytes) { + con <- rawConnection(ipc_bytes, "rb") + on.exit(close(con)) + stream <- nanoarrow::read_nanoarrow(con) + as.data.frame(stream) +} diff --git a/ggsql-R/R/engine.R b/ggsql-R/R/engine.R index 15b4aa40..8e166fdb 100644 --- a/ggsql-R/R/engine.R +++ b/ggsql-R/R/engine.R @@ -1,58 +1,459 @@ +# Package-level environment for persistent reader across knitr chunks +ggsql_env <- new.env(parent = emptyenv()) -ggsql_engine <- function(options) { - # Write a temporary file with the query - tmp <- basename(tempfile("ggsql", ".", paste0(".", "gsql"))) - on.exit(unlink(tmp)) - writeLines(options$code, tmp) +get_engine_reader <- function(connection = NULL) { + if (is.null(connection)) { + # Default in-memory DuckDB reader + if (is.null(ggsql_env$reader)) { + ggsql_env$reader <- duckdb_reader() + # Inject the sql proxy into the knit environment for cross-chunk access + proxy <- new_ggsql_tables() + assign("sql", proxy, envir = knitr::knit_global()) + # Also inject into Python if reticulate is available, so Python chunks + # can use sql.tablename directly (without the r. prefix) + if ( + requireNamespace("reticulate", quietly = TRUE) && + reticulate::py_available(initialize = FALSE) + ) { + reticulate::py_run_string("pass") # ensure Python is initialized + py <- reticulate::py + py[["sql"]] <- proxy + } + } + return(ggsql_env$reader) + } + + # Custom connection: cache by connection string + if (is.null(ggsql_env$readers)) { + ggsql_env$readers <- list() + } + if (is.null(ggsql_env$readers[[connection]])) { + ggsql_env$readers[[connection]] <- parse_connection(connection) + } + ggsql_env$readers[[connection]] +} + +register_syntax_highlighting <- function() { + syntax_file <- system.file("ggsql.xml", package = "ggsql") + if (!nzchar(syntax_file)) { + return() + } + + # For rmarkdown: add --syntax-definition to Pandoc args + current <- knitr::opts_knit$get("rmarkdown.pandoc.args") + if (!syntax_file %in% current) { + knitr::opts_knit$set( + rmarkdown.pandoc.args = c(current, "--syntax-definition", syntax_file) + ) + } +} + +# --------------------------------------------------------------------------- +# Connection string parsing +# --------------------------------------------------------------------------- + +parse_connection <- function(connection) { + check_string(connection) + + if (!grepl("://", connection, fixed = TRUE)) { + cli::cli_abort( + "Invalid connection string {.val {connection}}. Expected format: {.code scheme://...} (e.g., {.code duckdb://memory})." + ) + } + + scheme <- sub("://.*", "", connection) + + switch( + tolower(scheme), + duckdb = Reader$new(connection), + cli::cli_abort( + "Unsupported connection scheme {.val {scheme}}. Supported schemes: {.val duckdb}." + ) + ) +} + +# --------------------------------------------------------------------------- +# sql proxy: live access to tables in the ggsql DuckDB reader +# --------------------------------------------------------------------------- + +new_ggsql_tables <- function() { + structure(list(), class = "ggsql_tables") +} + +#' @export +`$.ggsql_tables` <- function(x, name) { + safe_name <- gsub('"', '""', name, fixed = TRUE) + ggsql_execute_sql(get_engine_reader(), paste0('SELECT * FROM "', safe_name, '"')) +} + +#' @export +`[[.ggsql_tables` <- function(x, name, ...) { + safe_name <- gsub('"', '""', name, fixed = TRUE) + ggsql_execute_sql(get_engine_reader(), paste0('SELECT * FROM "', safe_name, '"')) +} + +#' @export +print.ggsql_tables <- function(x, ...) { + reader <- get_engine_reader() + tables <- try_fetch( + ggsql_execute_sql(reader, "SHOW TABLES"), + error = function(cnd) data.frame(name = character()) + ) + cli::cli_text("") + if (nrow(tables) > 0) { + cli::cli_bullets(stats::setNames(tables[[1]], rep("*", nrow(tables)))) + } else { + cli::cli_text("(no tables)") + } + invisible(x) +} + +#' @export +names.ggsql_tables <- function(x) { + reader <- get_engine_reader() + tables <- try_fetch( + ggsql_execute_sql(reader, "SHOW TABLES"), + error = function(cnd) data.frame(name = character()) + ) + if (nrow(tables) > 0) tables[[1]] else character() +} + +# --------------------------------------------------------------------------- +# Data reference resolution (r: and py: prefixes) +# --------------------------------------------------------------------------- + +resolve_data_refs <- function(query, reader) { + refs <- gregexpr( + "(?:r|py):[a-zA-Z_][a-zA-Z0-9_.]*", + query, + ignore.case = TRUE, + perl = TRUE + ) + matches <- regmatches(query, refs)[[1]] + + if (length(matches) == 0) { + return(query) + } + + for (ref in unique(matches)) { + parts <- strsplit(ref, ":", fixed = TRUE)[[1]] + prefix <- parts[1] + name <- parts[2] + + df <- switch( + tolower(prefix), + r = try_fetch( + get(name, envir = knitr::knit_global()), + error = function(cnd) { + cli::cli_abort( + "Column reference {.code {ref}}: object {.val {name}} not found in R environment." + ) + } + ), + py = { + rlang::check_installed( + "reticulate", + reason = "to use py: data references." + ) + obj <- reticulate::py[[name]] + if (is.null(obj)) { + cli::cli_abort( + "Column reference {.code {ref}}: object {.val {name}} not found in Python environment." + ) + } + obj + } + ) + + if (!is.data.frame(df)) { + cli::cli_abort("{.code {ref}} does not refer to a data frame.") + } + + internal_name <- paste0("__", prefix, "_", name, "__") + ggsql_register(reader, df, internal_name, replace = TRUE) + query <- gsub(ref, internal_name, query, fixed = TRUE) + } + + query +} + +# --------------------------------------------------------------------------- +# Vega-Lite HTML rendering +# --------------------------------------------------------------------------- + +vegalite_html <- function( + spec_json, + width = NULL, + height = NULL, + caption = NULL, + align = "center" +) { + ggsql_env$vis_counter <- (ggsql_env$vis_counter %||% 0L) + 1L + vis_id <- paste0("ggsql-vis-", ggsql_env$vis_counter) + + # Convert fig.width/fig.height (inches) to pixels at 96 dpi, + # or use defaults if not specified + css_width <- if (!is.null(width)) { + if (is.numeric(width)) paste0(round(width * 96), "px") else width + } else { + "100%" + } + css_height <- if (!is.null(height)) { + if (is.numeric(height)) paste0(round(height * 96), "px") else height + } else { + "400px" + } + + margin_style <- switch( + align %||% "center", + center = "margin-left: auto; margin-right: auto;", + right = "margin-left: auto;", + "" + ) - out <- '' + html <- sprintf( + '
+
+
- # Format and evaluate system command - if (options$eval) { - cmd <- sprintf("ggsql run %s", paste(tmp, options$engine.opts)) - out <- system(cmd, intern=TRUE) +', + vis_id, + css_width, + margin_style, + vis_id, + css_height, + spec_json, + vis_id + ) - out <- rlang::try_fetch( - utils::read.csv(text = out), - error = function(cnd) out + if (!is.null(caption) && nzchar(caption)) { + html <- sprintf( + '
\n%s\n
%s
\n
', + html, + htmltools::htmlEscape(caption) ) - # Excludes dummy table when creating new table in chunk - is_proper_dataframe <- is.data.frame(out) && - !(identical(colnames(out), "Count") && nrow(out) == 1) - if (is_proper_dataframe) { - out <- knitr::kable(out) - options$results <- "asis" + } + + html +} + +# --------------------------------------------------------------------------- +# Inline chunk options (--| and #| prefix support) +# --------------------------------------------------------------------------- + +parse_chunk_options <- function(options) { + code <- options$code + if (length(code) == 0) { + return(options) + } + + # Extract leading lines with --| or #| prefix + option_pattern <- "^\\s*(?:--|#)\\|\\s?" + is_option <- grepl(option_pattern, code, perl = TRUE) + + # Only consider contiguous leading option lines + n_options <- 0L + for (i in seq_along(is_option)) { + if (!is_option[i]) { + break } + n_options <- i + } + + if (n_options == 0L) { + return(options) + } + + # Extract option text (strip the prefix) + option_lines <- sub(option_pattern, "", code[seq_len(n_options)], perl = TRUE) + options$code <- code[-seq_len(n_options)] + + # Parse as YAML + yaml_text <- paste(option_lines, collapse = "\n") + parsed <- tryCatch( + yaml::yaml.load(yaml_text), + error = function(cnd) NULL + ) + + if (is.null(parsed) || !is.list(parsed)) { + return(options) + } + + # Merge into options (inline options override chunk header options) + for (nm in names(parsed)) { + # Convert Quarto-style kebab-case to knitr-style dot-case + knitr_nm <- gsub("-", ".", nm, fixed = TRUE) + options[[knitr_nm]] <- parsed[[nm]] + } + + options +} + +# --------------------------------------------------------------------------- +# knitr engine +# --------------------------------------------------------------------------- + +ggsql_engine <- function(options) { + # Parse inline chunk options (--| or #| prefixed lines) + options <- parse_chunk_options(options) + + # Use SQL syntax highlighting for the source code block. + # ggsql-specific highlighting requires adding ggsql.xml to the Quarto/Pandoc + # config (see inst/ggsql.xml). SQL covers the base keywords well. + options$class.source <- options$class.source %||% "sql" + + # Always register syntax highlighting, even for custom connections + register_syntax_highlighting() + + if (!options$eval) { + return(knitr::engine_output(options, options$code, "")) + } + + query <- paste(options$code, collapse = "\n") + + result <- try_fetch( + { + reader <- get_engine_reader(options$connection) + ggsql_engine_eval(query, reader, options) + }, + error = function(cnd) { + knitr::engine_output(options, options$code, conditionMessage(cnd)) + } + ) + + result +} + +ggsql_engine_eval <- function(query, reader, options) { + query <- resolve_data_refs(query, reader) + validated <- ggsql_validate(query) + + if (!validated$has_visual) { + # Plain SQL: execute and render as table + df <- ggsql_execute_sql(reader, query) + + # If output.var is set, assign to knit environment instead of rendering + if (!is.null(options$output.var)) { + assign(options$output.var, df, envir = knitr::knit_global()) + return(knitr::engine_output(options, options$code, "")) + } + + # Suppress output for DDL/DML statements that return metadata rows + # (e.g., COPY TO returns a "Count" column) + is_result <- nrow(df) > 0 && ncol(df) > 0 && !identical(names(df), "Count") + if (!is_result) { + return(knitr::engine_output(options, options$code, "")) + } + out <- knitr::kable(df) + options$results <- "asis" return(knitr::engine_output(options, options$code, out)) } - # Interpret output as-is, i.e. raw html/pandoc + # Visualization query: execute and render + spec <- ggsql_execute(reader, query) + writer_type <- options$writer %||% "vegalite" + + # If output.var is set, always capture the Vega-Lite JSON + if (!is.null(options$output.var)) { + writer <- vegalite_writer() + json <- ggsql_render(writer, spec) + assign(options$output.var, json, envir = knitr::knit_global()) + return(knitr::engine_output(options, options$code, "")) + } + options$results <- "asis" - # Render the spec as html chunk to include - widget <- vegawidget::as_vegaspec(paste0(out, collapse = "\n")) - out <- knitr::knit_print(widget, options = options) + switch( + writer_type, + vegalite = { + # Embed Vega-Lite spec directly with vega-embed from CDN. + # This avoids vegawidget version constraints (ggsql uses Vega-Lite v6). + writer <- vegalite_writer() + json <- ggsql_render(writer, spec) + out <- vegalite_html( + json, + width = options$fig.width, + height = options$fig.height, + caption = options$fig.cap, + align = options$fig.align + ) + knitr::engine_output(options, options$code, out = out) + }, + vegalite_svg = render_static_figure(spec, "svg", options), + vegalite_png = render_static_figure(spec, "png", options), + cli::cli_abort( + c( + "Unsupported writer {.val {writer_type}}.", + i = "Supported writers: {.val vegalite}, {.val vegalite_svg}, {.val vegalite_png}." + ) + ) + ) +} + +write_static_figure <- function(spec, format, options) { + options$label <- options$label %||% "ggsql-chunk" + ext <- paste0(".", format) + fig <- knitr::fig_path(ext, options, number = 1L) + dir.create(dirname(fig), recursive = TRUE, showWarnings = FALSE) - # When we cannot include widgets, we are handed a screenshot that we - # must include as a png file. - # This happens in static formats, like PDF - if (inherits(out, "html_screenshot")) { - file_path <- knitr::sew(out, options = options) - return(knitr::engine_output(options, out = list(file_path))) - } + switch( + format, + svg = writeLines(ggsql_to_svg(spec), fig), + png = writeBin(ggsql_to_png(spec), fig) + ) - # Add metadata manually, since we're not using the usual hooks. - # This ensures the dependencies ( + +The only thing you need to remember is to load ggsql into R in your +Rmarkdown/Quarto document so the knitr engine is registered. diff --git a/ggsql-R/air.toml b/ggsql-R/air.toml new file mode 100644 index 00000000..e69de29b diff --git a/ggsql-R/configure b/ggsql-R/configure new file mode 100755 index 00000000..c6ba17a2 --- /dev/null +++ b/ggsql-R/configure @@ -0,0 +1,3 @@ +#!/usr/bin/env sh +: "${R_HOME=`R RHOME`}" +"${R_HOME}/bin/Rscript" tools/config.R diff --git a/ggsql-R/configure.win b/ggsql-R/configure.win new file mode 100644 index 00000000..57eb2555 --- /dev/null +++ b/ggsql-R/configure.win @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +"${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" tools/config.R diff --git a/ggsql-R/inst/ggsql.xml b/ggsql-R/inst/ggsql.xml new file mode 100644 index 00000000..39437676 --- /dev/null +++ b/ggsql-R/inst/ggsql.xml @@ -0,0 +1,832 @@ + + + + + + + SELECT + FROM + WHERE + GROUP + ORDER + BY + HAVING + LIMIT + OFFSET + DISTINCT + ALL + JOIN + LEFT + RIGHT + INNER + OUTER + CROSS + FULL + NATURAL + LATERAL + ON + WITH + RECURSIVE + AS + INSERT + UPDATE + DELETE + CREATE + DROP + ALTER + TRUNCATE + INTO + VALUES + SET + TABLE + VIEW + INDEX + DATABASE + SCHEMA + TEMP + TEMPORARY + CASE + WHEN + THEN + ELSE + END + OVER + PARTITION + ROWS + RANGE + UNBOUNDED + PRECEDING + FOLLOWING + CURRENT + ROW + NULLS + FIRST + LAST + UNION + INTERSECT + EXCEPT + AND + OR + NOT + IN + BETWEEN + LIKE + ILIKE + EXISTS + IS + ANY + ASC + DESC + + + + + DRAW + PLACE + SCALE + PROJECT + FACET + LABEL + THEME + VISUALISE + VISUALIZE + + + + + MAPPING + REMAPPING + SETTING + FILTER + ORDER + PARTITION + RENAMING + TO + VIA + + + + + CONTINUOUS + DISCRETE + BINNED + ORDINAL + IDENTITY + + + + + point + line + path + bar + col + area + rect + polygon + ribbon + histogram + density + smooth + boxplot + violin + text + label + segment + arrow + rule + linear + errorbar + + + + + x + y + xmin + xmax + ymin + ymax + xend + yend + weight + color + colour + fill + stroke + opacity + size + shape + linetype + linewidth + width + height + typeface + fontweight + italic + hjust + vjust + + + + + linear + log + log10 + log2 + sqrt + reverse + categorical + ordinal + date + datetime + time + viridis + plasma + magma + inferno + cividis + diverging + sequential + identity + manual + + + + + cartesian + polar + flip + fixed + trans + map + quickmap + + + + + minimal + classic + gray + grey + bw + dark + light + void + + + + + type + limits + breaks + labels + expand + direction + na_value + palette + domain + range + + + + + xlim + ylim + ratio + angle + clip + + + + + title + subtitle + caption + tag + + + + + background + panel_background + panel_grid + panel_grid_major + panel_grid_minor + text_size + text_family + title_size + axis_text_size + axis_line + axis_line_width + panel_border + plot_margin + panel_spacing + legend_background + legend_position + legend_direction + + + + + count + sum + avg + min + max + stddev + variance + array_agg + string_agg + group_concat + row_number + rank + dense_rank + ntile + lag + lead + first_value + last_value + nth_value + cume_dist + percent_rank + date_trunc + date_part + datepart + datename + dateadd + datediff + extract + now + current_date + current_time + current_timestamp + getdate + getutcdate + strftime + strptime + make_date + make_time + make_timestamp + concat + substring + substr + length + len + char_length + lower + upper + trim + ltrim + rtrim + replace + lpad + rpad + split_part + string_split + format + printf + abs + ceil + ceiling + floor + round + trunc + truncate + mod + power + exp + ln + sign + sin + cos + tan + asin + acos + atan + atan2 + pi + degrees + radians + random + rand + cast + convert + coalesce + nullif + ifnull + isnull + nvl + try_cast + typeof + greatest + least + decode + json + json_extract + json_value + json_query + json_object + json_array + to_json + from_json + unnest + generate_series + + + + + NULL + TRUE + FALSE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ggsql-R/man/duckdb_reader.Rd b/ggsql-R/man/duckdb_reader.Rd new file mode 100644 index 00000000..c6588edd --- /dev/null +++ b/ggsql-R/man/duckdb_reader.Rd @@ -0,0 +1,27 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/reader.R +\name{duckdb_reader} +\alias{duckdb_reader} +\title{Create a DuckDB reader} +\usage{ +duckdb_reader(database = NULL) +} +\arguments{ +\item{database}{Path to a DuckDB database file, or \code{NULL} (the default) +for an in-memory database.} +} +\value{ +A \code{Reader} object. +} +\description{ +Creates a DuckDB database connection that can execute SQL queries and +register data frames as queryable tables. The default creates an empty +in-memory database but you can also pass the path to a DuckDB database to +directly interact with that. +} +\examples{ +reader <- duckdb_reader() +ggsql_register(reader, mtcars, "cars") +df <- ggsql_execute_sql(reader, "SELECT mpg, disp FROM cars LIMIT 5") + +} diff --git a/ggsql-R/man/figures/README-unnamed-chunk-2-1.png b/ggsql-R/man/figures/README-unnamed-chunk-2-1.png new file mode 100644 index 00000000..421109e7 Binary files /dev/null and b/ggsql-R/man/figures/README-unnamed-chunk-2-1.png differ diff --git a/ggsql-R/man/figures/README-unnamed-chunk-2-1.svg b/ggsql-R/man/figures/README-unnamed-chunk-2-1.svg new file mode 100644 index 00000000..d52a4a30 --- /dev/null +++ b/ggsql-R/man/figures/README-unnamed-chunk-2-1.svg @@ -0,0 +1 @@ +101520253035mpg100200300400disp diff --git a/ggsql-R/man/figures/README-unnamed-chunk-3-1.png b/ggsql-R/man/figures/README-unnamed-chunk-3-1.png new file mode 100644 index 00000000..4519b8df Binary files /dev/null and b/ggsql-R/man/figures/README-unnamed-chunk-3-1.png differ diff --git a/ggsql-R/man/figures/README-unnamed-chunk-3-1.svg b/ggsql-R/man/figures/README-unnamed-chunk-3-1.svg new file mode 100644 index 00000000..e63aa281 --- /dev/null +++ b/ggsql-R/man/figures/README-unnamed-chunk-3-1.svg @@ -0,0 +1 @@ +101520253035mpg100200300400dispThat data came from R 🤯 diff --git a/ggsql-R/man/figures/logo.png b/ggsql-R/man/figures/logo.png new file mode 100644 index 00000000..946b47a7 Binary files /dev/null and b/ggsql-R/man/figures/logo.png differ diff --git a/ggsql-R/man/ggsql-package.Rd b/ggsql-R/man/ggsql-package.Rd index fc325e28..2673a103 100644 --- a/ggsql-R/man/ggsql-package.Rd +++ b/ggsql-R/man/ggsql-package.Rd @@ -6,6 +6,8 @@ \alias{ggsql-package} \title{ggsql: A SQL extension for declarative data visualization based on the Grammar of Graphics} \description{ +\if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} + ggsql allows you to write queries that combine SQL data retrieval with visualization specifications in a single, composable syntax. } \author{ diff --git a/ggsql-R/man/ggsql_execute.Rd b/ggsql-R/man/ggsql_execute.Rd new file mode 100644 index 00000000..c3320c2e --- /dev/null +++ b/ggsql-R/man/ggsql_execute.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/reader.R +\name{ggsql_execute} +\alias{ggsql_execute} +\alias{ggsql_execute_sql} +\title{Execute a ggsql query} +\usage{ +ggsql_execute(reader, query) + +ggsql_execute_sql(reader, query) +} +\arguments{ +\item{reader}{A \code{Reader} object created by \code{\link[=duckdb_reader]{duckdb_reader()}}.} + +\item{query}{A ggsql query string (SQL + VISUALISE clause).} +} +\value{ +A \code{Spec} object. +} +\description{ +Parses the query, and execute it against the reader's database. Returns +either a visualization specification ready for rendering (\code{ggsql_execute}) or +a data frame with the query result (\code{ggsql_execute_sql}). +} +\examples{ +reader <- duckdb_reader() +ggsql_register(reader, mtcars, "cars") +spec <- ggsql_execute(reader, + "SELECT * FROM cars VISUALISE mpg AS x, disp AS y DRAW point" +) + +} diff --git a/ggsql-R/man/ggsql_register.Rd b/ggsql-R/man/ggsql_register.Rd new file mode 100644 index 00000000..dff8fb4e --- /dev/null +++ b/ggsql-R/man/ggsql_register.Rd @@ -0,0 +1,51 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/reader.R +\name{ggsql_register} +\alias{ggsql_register} +\alias{ggsql_unregister} +\alias{ggsql_table} +\alias{ggsql_table_names} +\title{Register and unregisters a data frame as a queryable table} +\usage{ +ggsql_register(reader, df, name, replace = FALSE) + +ggsql_unregister(reader, name) + +ggsql_table(reader, name) + +ggsql_table_names(reader) +} +\arguments{ +\item{reader}{A \code{Reader} object created by e.g. \code{\link[=duckdb_reader]{duckdb_reader()}}.} + +\item{df}{A data frame to register.} + +\item{name}{The name of the table.} + +\item{replace}{If \code{TRUE}, replace an existing table with the same name. +Defaults to \code{FALSE}.} +} +\value{ +\code{reader} for \code{ggsql_register()} and \code{ggsql_unregister()}. +\code{ggsql_table} returns a data.frame if the table exists and \code{NULL} if not. +\code{ggsql_table_names} return a character vector. +} +\description{ +After registration, the data frame can be queried by name in SQL statements. +You can use \code{ggsql_table} to extract tables from the reader (both registered +ones and those native to the backend) and \code{ggsql_table_names} to get a vector +of all the tables in reader. +} +\examples{ +reader <- duckdb_reader() +ggsql_register(reader, mtcars, "cars") + +ggsql_table_names(reader) + +ggsql_table(reader, "cars") + +ggsql_unregister(reader, "cars") + +ggsql_table_names(reader) + +} diff --git a/ggsql-R/man/ggsql_render.Rd b/ggsql-R/man/ggsql_render.Rd new file mode 100644 index 00000000..a600f742 --- /dev/null +++ b/ggsql-R/man/ggsql_render.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/writer.R +\name{ggsql_render} +\alias{ggsql_render} +\title{Render a spec with a writer} +\usage{ +ggsql_render(writer, spec) +} +\arguments{ +\item{writer}{A \code{Writer} object created by e.g. \code{\link[=vegalite_writer]{vegalite_writer()}}.} + +\item{spec}{A \code{Spec} object returned by \code{\link[=ggsql_execute]{ggsql_execute()}}.} +} +\value{ +Writer dependent: +\itemize{ +\item \code{vegalite_writer}: A string holding the vegalite JSON representation of the +visualization +} +} +\description{ +This function takes a \code{Spec} object as returned by \code{\link[=ggsql_execute]{ggsql_execute()}} and +renders it with the provided writer. +} +\examples{ +reader <- duckdb_reader() +ggsql_register(reader, mtcars, "cars") +spec <- ggsql_execute(reader, + "SELECT * FROM cars VISUALISE mpg AS x DRAW histogram" +) + +ggsql_render(vegalite_writer(), spec) + +} diff --git a/ggsql-R/man/ggsql_save.Rd b/ggsql-R/man/ggsql_save.Rd new file mode 100644 index 00000000..f837ed07 --- /dev/null +++ b/ggsql-R/man/ggsql_save.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/render.R +\name{ggsql_save} +\alias{ggsql_save} +\title{Save a ggsql spec to a file} +\usage{ +ggsql_save(spec, file, width = 600, height = 400) +} +\arguments{ +\item{spec}{A \code{Spec} object returned by \code{\link[=ggsql_execute]{ggsql_execute()}}.} + +\item{file}{Output file path. Extension determines format: \code{.svg}, \code{.png}, or +\code{.json}.} + +\item{width}{Width in pixels.} + +\item{height}{Height in pixels.} +} +\value{ +\code{file}, invisibly. +} +\description{ +This function renders a specification and returns it either as a Vegalite +json string, an SVG or a PNG. For the latter two, the Vegalite JSON is +rendered to SVG using the V8 package and, potentially, converted to PNG using +the rsvg package. +} +\examples{ +reader <- duckdb_reader() +ggsql_register(reader, mtcars, "cars") +spec <- ggsql_execute(reader, + "SELECT * FROM cars VISUALISE mpg AS x, disp AS y DRAW point" +) +svg_file <- tempfile(fileext = ".svg") +ggsql_save(spec, svg_file) + +} diff --git a/ggsql-R/man/ggsql_validate.Rd b/ggsql-R/man/ggsql_validate.Rd new file mode 100644 index 00000000..56755992 --- /dev/null +++ b/ggsql-R/man/ggsql_validate.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/validate.R +\name{ggsql_validate} +\alias{ggsql_validate} +\alias{ggsql_has_visual} +\alias{ggsql_is_valid} +\title{Validate a ggsql query} +\usage{ +ggsql_validate(query) + +ggsql_has_visual(x) + +ggsql_is_valid(x) +} +\arguments{ +\item{query}{A ggsql query string.} + +\item{x}{A \code{ggsql_validated} object} +} +\value{ +A \code{ggsql_validated} object for \code{ggsql_validate()}. A boolean for +\code{ggsql_has_visual()} and \code{ggsql_is_valid()} +} +\description{ +Checks query syntax and semantics without executing SQL. Returns a +validation result that can be inspected for errors and warnings. +} +\examples{ +result <- ggsql_validate("SELECT 1 AS x, 2 AS y VISUALISE x, y DRAW point") +result + +} diff --git a/ggsql-R/man/spec_utility.Rd b/ggsql-R/man/spec_utility.Rd new file mode 100644 index 00000000..a94a3c84 --- /dev/null +++ b/ggsql-R/man/spec_utility.Rd @@ -0,0 +1,72 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/spec.R +\name{spec_utility} +\alias{spec_utility} +\alias{ggsql_metadata} +\alias{ggsql_sql} +\alias{ggsql_visual} +\alias{ggsql_layer_count} +\alias{ggsql_layer_data} +\alias{ggsql_stat_data} +\alias{ggsql_layer_sql} +\alias{ggsql_stat_sql} +\alias{ggsql_warnings} +\title{Utility functions for visualization specifications} +\usage{ +ggsql_metadata(spec) + +ggsql_sql(spec) + +ggsql_visual(spec) + +ggsql_layer_count(spec) + +ggsql_layer_data(spec, index = 1L) + +ggsql_stat_data(spec, index = 1L) + +ggsql_layer_sql(spec, index = 1L) + +ggsql_stat_sql(spec, index = 1L) + +ggsql_warnings(spec) +} +\arguments{ +\item{spec}{A \code{Spec} object as returned by \code{\link[=ggsql_execute]{ggsql_execute()}}} + +\item{index}{Layer index} +} +\value{ +\itemize{ +\item \code{ggsql_metadata}: A list with elements \code{rows}, \code{columns}, and \code{layer_count} +\item \code{ggsql_sql}: A character string with the SQL portion of the query +\item \code{ggsql_visual}: A character string with the visual portion of the query +\item \code{ggsql_layer_count}: An integer giving the number of layers +\item \code{ggsql_layer_data}: A data frame, or \code{NULL} if no data is available for +this layer +\item \code{ggsql_stat_data}: A data frame, or \code{NULL} if the layer doesn't use a stat +transform +\item \code{ggsql_layer_sql}: A character string with the SQL query used by the layer +to fetch its data, or \code{NULL} if the layer doesn't have any data. +\item \code{ggsql_stat_sql}: A character string with the SQL query used by the layers +stat transform, or \code{NULL} if the layer doesn't have a stat transform. +\item \code{ggsql_warnings}: A data.frame with columns \code{message}, \code{line}, and \code{column} +giving the validation warnings for the spec +} +} +\description{ +These functions allow you to extract various information from a \code{Spec} object +returned by \code{\link[=ggsql_execute]{ggsql_execute()}}. +} +\examples{ +reader <- duckdb_reader() +ggsql_register(reader, mtcars, "cars") +spec <- ggsql_execute(reader, + "SELECT * FROM cars VISUALISE mpg AS x DRAW histogram" +) + +ggsql_metadata(spec) + +ggsql_visual(spec) + +} diff --git a/ggsql-R/man/vegalite_writer.Rd b/ggsql-R/man/vegalite_writer.Rd new file mode 100644 index 00000000..ee2f5b3a --- /dev/null +++ b/ggsql-R/man/vegalite_writer.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/writer.R +\name{vegalite_writer} +\alias{vegalite_writer} +\title{Create a Vega-Lite writer} +\usage{ +vegalite_writer() +} +\value{ +A \code{Writer} object. +} +\description{ +This function creates a vegalite writer which is currently the only writer +type for ggsql +} +\examples{ +vegalite_writer() + +} diff --git a/ggsql-R/src/.gitignore b/ggsql-R/src/.gitignore new file mode 100644 index 00000000..24e51fc6 --- /dev/null +++ b/ggsql-R/src/.gitignore @@ -0,0 +1,8 @@ +*.o +*.so +*.dll +target +.cargo +rust/vendor +Makevars +Makevars.win diff --git a/ggsql-R/src/Makevars.in b/ggsql-R/src/Makevars.in new file mode 100644 index 00000000..776981ff --- /dev/null +++ b/ggsql-R/src/Makevars.in @@ -0,0 +1,48 @@ +TARGET_DIR = ./rust/target +LIBDIR = $(TARGET_DIR)/@LIBDIR@ +STATLIB = $(LIBDIR)/libggsql.a +PKG_LIBS = -L$(LIBDIR) -lggsql + +all: $(SHLIB) rust_clean + +.PHONY: $(STATLIB) + +$(SHLIB): $(STATLIB) + +CARGOTMP = $(CURDIR)/.cargo +VENDOR_DIR = $(CURDIR)/vendor + + +# RUSTFLAGS appends --print=native-static-libs to ensure that +# the correct linkers are used. Use this for debugging if need. +# +# CRAN note: Cargo and Rustc versions are reported during +# configure via tools/msrv.R. +# +# If a vendor directory exists, it is used for offline compilation. Otherwise if +# vendor.tar.xz exists, it is unzipped and used for offline compilation. +$(STATLIB): + + if [ -d ./vendor ]; then \ + echo "=== Using offline vendor directory ==="; \ + mkdir -p $(CARGOTMP) && \ + cp rust/vendor-config.toml $(CARGOTMP)/config.toml; \ + elif [ -f ./rust/vendor.tar.xz ]; then \ + echo "=== Using offline vendor tarball ==="; \ + tar xf rust/vendor.tar.xz && \ + mkdir -p $(CARGOTMP) && \ + cp rust/vendor-config.toml $(CARGOTMP)/config.toml; \ + fi + + export CARGO_HOME=$(CARGOTMP) && \ + export PATH="$(PATH):$(HOME)/.cargo/bin" && \ + @PANIC_EXPORTS@RUSTFLAGS="$(RUSTFLAGS) --print=native-static-libs" cargo build @CRAN_FLAGS@ --lib @PROFILE@ --manifest-path=./rust/Cargo.toml --target-dir $(TARGET_DIR) @TARGET@ + + # Always clean up CARGOTMP + rm -Rf $(CARGOTMP); + +rust_clean: $(SHLIB) + rm -Rf $(CARGOTMP) $(VENDOR_DIR) @CLEAN_TARGET@ + +clean: + rm -Rf $(SHLIB) $(STATLIB) $(OBJECTS) $(TARGET_DIR) $(VENDOR_DIR) diff --git a/ggsql-R/src/Makevars.win.in b/ggsql-R/src/Makevars.win.in new file mode 100644 index 00000000..40dc2cb4 --- /dev/null +++ b/ggsql-R/src/Makevars.win.in @@ -0,0 +1,46 @@ +TARGET = $(subst 64,x86_64,$(subst 32,i686,$(WIN)))-pc-windows-gnu + +TARGET_DIR = ./rust/target +LIBDIR = $(TARGET_DIR)/$(TARGET)/@LIBDIR@ +STATLIB = $(LIBDIR)/libggsql.a +PKG_LIBS = -L$(LIBDIR) -lggsql -lws2_32 -ladvapi32 -luserenv -lbcrypt -lntdll + +all: $(SHLIB) rust_clean + +.PHONY: $(STATLIB) + +$(SHLIB): $(STATLIB) + +CARGOTMP = $(CURDIR)/.cargo +VENDOR_DIR = vendor + +$(STATLIB): + mkdir -p $(TARGET_DIR)/libgcc_mock + touch $(TARGET_DIR)/libgcc_mock/libgcc_eh.a + + # If a vendor directory exists, it is used for offline compilation. Otherwise if + # vendor.tar.xz exists, it is unzipped and used for offline compilation. + if [ -d ./vendor ]; then \ + echo "=== Using offline vendor directory ==="; \ + mkdir -p $(CARGOTMP) && \ + cp rust/vendor-config.toml $(CARGOTMP)/config.toml; \ + elif [ -f ./rust/vendor.tar.xz ]; then \ + echo "=== Using offline vendor tarball ==="; \ + tar xf rust/vendor.tar.xz && \ + mkdir -p $(CARGOTMP) && \ + cp rust/vendor-config.toml $(CARGOTMP)/config.toml; \ + fi + + # Build the project using Cargo with additional flags + export CARGO_HOME=$(CARGOTMP) && \ + export LIBRARY_PATH="$(LIBRARY_PATH);$(CURDIR)/$(TARGET_DIR)/libgcc_mock" && \ + RUSTFLAGS="$(RUSTFLAGS) --print=native-static-libs" cargo build @CRAN_FLAGS@ --target=$(TARGET) --lib @PROFILE@ --manifest-path=rust/Cargo.toml --target-dir=$(TARGET_DIR) + + # Always clean up CARGOTMP + rm -Rf $(CARGOTMP); + +rust_clean: $(SHLIB) + rm -Rf $(CARGOTMP) $(VENDOR_DIR) @CLEAN_TARGET@ + +clean: + rm -Rf $(SHLIB) $(STATLIB) $(OBJECTS) $(TARGET_DIR) $(VENDOR_DIR) diff --git a/ggsql-R/src/cleanup b/ggsql-R/src/cleanup new file mode 100644 index 00000000..e346d71d --- /dev/null +++ b/ggsql-R/src/cleanup @@ -0,0 +1 @@ +rm -f src/Makevars diff --git a/ggsql-R/src/cleanup.win b/ggsql-R/src/cleanup.win new file mode 100644 index 00000000..a1821746 --- /dev/null +++ b/ggsql-R/src/cleanup.win @@ -0,0 +1 @@ +rm -f src/Makevars.win diff --git a/ggsql-R/src/entrypoint.c b/ggsql-R/src/entrypoint.c new file mode 100644 index 00000000..611c11ed --- /dev/null +++ b/ggsql-R/src/entrypoint.c @@ -0,0 +1,8 @@ +// We need to forward routine registration from C to Rust +// to avoid the linker removing the static library. + +void R_init_ggsql_extendr(void *dll); + +void R_init_ggsql(void *dll) { + R_init_ggsql_extendr(dll); +} diff --git a/ggsql-R/src/ggsql-win.def b/ggsql-R/src/ggsql-win.def new file mode 100644 index 00000000..f1b3d279 --- /dev/null +++ b/ggsql-R/src/ggsql-win.def @@ -0,0 +1,2 @@ +EXPORTS +R_init_ggsql diff --git a/ggsql-R/src/rust/Cargo.lock b/ggsql-R/src/rust/Cargo.lock new file mode 100644 index 00000000..b2279c4a --- /dev/null +++ b/ggsql-R/src/rust/Cargo.lock @@ -0,0 +1,4884 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "const-random", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ar_archive_writer" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b" +dependencies = [ + "object", +] + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "argminmax" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f13d10a41ac8d2ec79ee34178d61e6f47a29c2edfe7ef1721c7383b0359e65" +dependencies = [ + "num-traits", +] + +[[package]] +name = "array-init-cursor" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed51fe0f224d1d4ea768be38c51f9f831dee9d05c163c11fba0b8c44387b1fc3" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "arrow" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e833808ff2d94ed40d9379848a950d995043c7fb3e81a30b383f4c6033821cc" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-ipc", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "arrow-string", +] + +[[package]] +name = "arrow-arith" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad08897b81588f60ba983e3ca39bda2b179bdd84dced378e7df81a5313802ef8" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "num", +] + +[[package]] +name = "arrow-array" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8548ca7c070d8db9ce7aa43f37393e4bfcf3f2d3681df278490772fd1673d08d" +dependencies = [ + "ahash 0.8.12", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "hashbrown 0.16.1", + "num", +] + +[[package]] +name = "arrow-buffer" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e003216336f70446457e280807a73899dd822feaf02087d31febca1363e2fccc" +dependencies = [ + "bytes", + "half", + "num", +] + +[[package]] +name = "arrow-cast" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919418a0681298d3a77d1a315f625916cb5678ad0d74b9c60108eb15fd083023" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "atoi", + "base64", + "chrono", + "comfy-table", + "half", + "lexical-core", + "num", + "ryu", +] + +[[package]] +name = "arrow-data" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5c64fff1d142f833d78897a772f2e5b55b36cb3e6320376f0961ab0db7bd6d0" +dependencies = [ + "arrow-buffer", + "arrow-schema", + "half", + "num", +] + +[[package]] +name = "arrow-ipc" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3594dcddccc7f20fd069bc8e9828ce37220372680ff638c5e00dea427d88f5" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "flatbuffers", +] + +[[package]] +name = "arrow-ord" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8f82583eb4f8d84d4ee55fd1cb306720cddead7596edce95b50ee418edf66f" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", +] + +[[package]] +name = "arrow-row" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d07ba24522229d9085031df6b94605e0f4b26e099fb7cdeec37abd941a73753" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "half", +] + +[[package]] +name = "arrow-schema" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3aa9e59c611ebc291c28582077ef25c97f1975383f1479b12f3b9ffee2ffabe" +dependencies = [ + "bitflags", +] + +[[package]] +name = "arrow-select" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c41dbbd1e97bfcaee4fcb30e29105fb2c75e4d82ae4de70b792a5d3f66b2e7a" +dependencies = [ + "ahash 0.8.12", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "num", +] + +[[package]] +name = "arrow-string" +version = "56.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53f5183c150fbc619eede22b861ea7c0eebed8eaac0333eaa7f6da5205fd504d" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "memchr", + "num", + "regex", + "regex-syntax", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atoi_simd" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a49e05797ca52e312a0c658938b7d00693ef037799ef7187678f212d7684cf" +dependencies = [ + "debug_unsafe", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "bincode_derive", + "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +dependencies = [ + "serde_core", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake3" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +dependencies = [ + "borsh-derive", + "bytes", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "boxcar" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f64beae40a84da1b4b26ff2761a5b895c12adc41dc25aaee1c4f2bbfe97a6e" + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "by_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +dependencies = [ + "serde", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + +[[package]] +name = "cc" +version = "1.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "chrono-tz" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" +dependencies = [ + "chrono", + "phf 0.12.1", +] + +[[package]] +name = "clap" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "comfy-table" +version = "7.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0d05af1e006a2407bedef5af410552494ce5be9090444dbbcb57258c1af3d56" +dependencies = [ + "strum 0.26.3", + "strum_macros 0.26.4", + "unicode-width", +] + +[[package]] +name = "compact_str" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "serde", + "static_assertions", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "const_format" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "csscolorparser" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "199f851bd3cb5004c09474252c7f74e7c047441ed0979bf3688a7106a13da952" +dependencies = [ + "num-traits", + "phf 0.13.1", + "serde", + "uncased", +] + +[[package]] +name = "debug_unsafe" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eed2c4702fa172d1ce21078faa7c5203e69f5394d48cc436d25928394a867a2" + +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "duckdb" +version = "1.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8685352ce688883098b61a361e86e87df66fc8c444f4a2411e884c16d5243a65" +dependencies = [ + "arrow", + "cast", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libduckdb-sys", + "num", + "num-integer", + "rust_decimal", + "strum 0.27.2", +] + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "ethnum" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca81e6b4777c89fd810c25a4be2b1bd93ea034fbe58e6a75216a34c6b82c539b" + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "extendr-api" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea54977c6e37236839ffcbc20b5dcea58aa32ae43fbef54a81e1011dc6b19061" +dependencies = [ + "extendr-ffi", + "extendr-macros", + "once_cell", + "paste", +] + +[[package]] +name = "extendr-ffi" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c76777174a82bdb3e66872f580687d3d0143eed1df9b9cd72b321b9596a23ca7" + +[[package]] +name = "extendr-macros" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "661cc4ae29de9c4dafe16cfcbda1dbb9f31bd2568f96ebad232cc1f9bcc8b04d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "fast-float2" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8eb564c5c7423d25c886fb561d1e4ee69f72354d16918afa32c08811f6b6a55" + +[[package]] +name = "fast-srgb8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "filetime" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" +dependencies = [ + "cfg-if", + "libc", + "libredox", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flatbuffers" +version = "25.12.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35f6839d7b3b98adde531effaf34f0c2badc6f4735d26fe74709d8e513a96ef3" +dependencies = [ + "bitflags", + "rustc_version", +] + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", + "zlib-rs", +] + +[[package]] +name = "float-cmp" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs4" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8640e34b88f7652208ce9e88b1a37a2ae95227d84abec377ccd3c5cfeb141ed4" +dependencies = [ + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + +[[package]] +name = "ggsql" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a578a8835f195bfca766eb064a3f7827d7ca5c03b8af3d3c361a735dde1ba101" +dependencies = [ + "anyhow", + "arrow", + "chrono", + "clap", + "const_format", + "csscolorparser", + "duckdb", + "palette", + "polars", + "polars-ops", + "rand 0.8.5", + "regex", + "serde", + "serde_json", + "sprintf", + "thiserror 1.0.69", + "tree-sitter", + "tree-sitter-ggsql", + "uuid", +] + +[[package]] +name = "ggsql-r" +version = "0.1.9" +dependencies = [ + "extendr-api", + "ggsql", + "polars", + "serde_json", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "h2" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", + "zerocopy", +] + +[[package]] +name = "halfbrown" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7ed2f2edad8a14c8186b847909a41fbb9c3eafa44f88bd891114ed5019da09" +dependencies = [ + "hashbrown 0.16.1", + "serde", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", + "rayon", + "serde", + "serde_core", +] + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "humantime" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" + +[[package]] +name = "hyper" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "iri-string" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e7418f59cc01c88316161279a7f665217ae316b388e58a0d10e29f54f1e5eb" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4c90f45aa2e6eacbe8645f77fdea542ac97a494bcd117a67df9ff4d611f995" +dependencies = [ + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "lexical-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8d125a277f807e55a77304455eb7b1cb52f2b18c143b60e766c120bd64a594" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a9f232fbd6f550bc0137dcb5f99ab674071ac2d690ac69704593cb4abbea56" +dependencies = [ + "lexical-parse-integer", + "lexical-util", +] + +[[package]] +name = "lexical-parse-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7a039f8fb9c19c996cd7b2fcce303c1b2874fe1aca544edc85c4a5f8489b34" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "lexical-util" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2604dd126bb14f13fb5d1bd6a66155079cb9fa655b37f875b3a742c705dbed17" + +[[package]] +name = "lexical-write-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c438c87c013188d415fbabbb1dceb44249ab81664efbd31b14ae55dabb6361" +dependencies = [ + "lexical-util", + "lexical-write-integer", +] + +[[package]] +name = "lexical-write-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "409851a618475d2d5796377cad353802345cba92c867d9fbcde9cf4eac4e14df" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "libduckdb-sys" +version = "1.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78bacb8933586cee3b550c39b610d314f9b7a48701ac7a914a046165a4ad8da" +dependencies = [ + "cc", + "flate2", + "pkg-config", + "reqwest", + "serde", + "serde_json", + "tar", + "vcpkg", + "zip", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" +dependencies = [ + "bitflags", + "libc", + "plain", + "redox_syscall 0.7.3", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "lz4" +version = "1.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a20b523e860d03443e98350ceaac5e71c6ba89aea7d960769ec3ce37f4de5af4" +dependencies = [ + "lz4-sys", +] + +[[package]] +name = "lz4-sys" +version = "1.11.1+lz4-1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "now" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d89e9874397a1f0a52fc1f197a8effd9735223cb2390e9dcc83ac6cd02923d0" +dependencies = [ + "chrono", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "object_store" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbfbfff40aeccab00ec8a910b57ca8ecf4319b335c542f2edcd19dd25a1e2a00" +dependencies = [ + "async-trait", + "base64", + "bytes", + "chrono", + "form_urlencoded", + "futures", + "http", + "http-body-util", + "humantime", + "hyper", + "itertools", + "parking_lot", + "percent-encoding", + "quick-xml", + "rand 0.9.2", + "reqwest", + "ring", + "serde", + "serde_json", + "serde_urlencoded", + "thiserror 2.0.18", + "tokio", + "tracing", + "url", + "walkdir", + "wasm-bindgen-futures", + "web-time", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "palette" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +dependencies = [ + "approx", + "fast-srgb8", + "palette_derive", + "phf 0.11.3", +] + +[[package]] +name = "palette_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +dependencies = [ + "by_address", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros 0.11.3", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" +dependencies = [ + "phf_shared 0.12.1", +] + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros 0.13.1", + "phf_shared 0.13.1", + "serde", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared 0.11.3", + "rand 0.8.5", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared 0.13.1", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator 0.13.1", + "phf_shared 0.13.1", + "proc-macro2", + "quote", + "syn 2.0.117", + "uncased", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", + "uncased", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "planus" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3daf8e3d4b712abe1d690838f6e29fb76b76ea19589c4afa39ec30e12f62af71" +dependencies = [ + "array-init-cursor", + "hashbrown 0.15.5", +] + +[[package]] +name = "polars" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bc9ea901050c1bb8747ee411bc7fbb390f3b399931e7484719512965132a248" +dependencies = [ + "getrandom 0.2.17", + "getrandom 0.3.4", + "polars-arrow", + "polars-compute", + "polars-core", + "polars-error", + "polars-io", + "polars-lazy", + "polars-ops", + "polars-plan", + "polars-sql", + "polars-time", + "polars-utils", + "version_check", +] + +[[package]] +name = "polars-arrow" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d3fe43f8702cf7899ff3d516c2e5f7dc84ee6f6a3007e1a831a0ff87940704" +dependencies = [ + "atoi_simd", + "bitflags", + "bytemuck", + "chrono", + "chrono-tz", + "dyn-clone", + "either", + "ethnum", + "getrandom 0.2.17", + "getrandom 0.3.4", + "hashbrown 0.16.1", + "itoa", + "lz4", + "num-traits", + "polars-arrow-format", + "polars-error", + "polars-schema", + "polars-utils", + "serde", + "simdutf8", + "streaming-iterator", + "strum_macros 0.27.2", + "version_check", + "zstd", +] + +[[package]] +name = "polars-arrow-format" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a556ac0ee744e61e167f34c1eb0013ce740e0ee6cd8c158b2ec0b518f10e6675" +dependencies = [ + "planus", + "serde", +] + +[[package]] +name = "polars-compute" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29cc7497378dee3a002f117e0b4e16b7cbe6c8ed3da16a0229c89294af7c3bf" +dependencies = [ + "atoi_simd", + "bytemuck", + "chrono", + "either", + "fast-float2", + "hashbrown 0.16.1", + "itoa", + "num-traits", + "polars-arrow", + "polars-error", + "polars-utils", + "rand 0.9.2", + "ryu", + "serde", + "strength_reduce", + "strum_macros 0.27.2", + "version_check", +] + +[[package]] +name = "polars-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48409b7440cb1a4aa84953fe3a4189dfbfb300a3298266a92a37363476641e40" +dependencies = [ + "bitflags", + "boxcar", + "bytemuck", + "chrono", + "chrono-tz", + "either", + "hashbrown 0.16.1", + "indexmap", + "itoa", + "num-traits", + "polars-arrow", + "polars-compute", + "polars-dtype", + "polars-error", + "polars-row", + "polars-schema", + "polars-utils", + "rand 0.9.2", + "rand_distr", + "rayon", + "regex", + "serde", + "serde_json", + "strum_macros 0.27.2", + "uuid", + "version_check", + "xxhash-rust", +] + +[[package]] +name = "polars-dtype" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7007e9e8b7b657cbd339b65246af7e87f5756ee9a860119b9424ddffd2aaf133" +dependencies = [ + "boxcar", + "hashbrown 0.16.1", + "polars-arrow", + "polars-error", + "polars-utils", + "serde", + "uuid", +] + +[[package]] +name = "polars-error" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a6be22566c89f6405f553bfdb7c8a6cb20ec51b35f3172de9a25fa3e252d85" +dependencies = [ + "object_store", + "parking_lot", + "polars-arrow-format", + "regex", + "signal-hook", + "simdutf8", +] + +[[package]] +name = "polars-expr" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6199a50d3e1afd0674fb009e340cbfb0010682b2387187a36328c00f3f2ca87b" +dependencies = [ + "bitflags", + "hashbrown 0.16.1", + "num-traits", + "polars-arrow", + "polars-compute", + "polars-core", + "polars-io", + "polars-ops", + "polars-plan", + "polars-row", + "polars-time", + "polars-utils", + "rand 0.9.2", + "rayon", + "recursive", + "regex", + "version_check", +] + +[[package]] +name = "polars-io" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be3714acdff87170141880a07f5d9233490d3bd5531c41898f6969d440feee11" +dependencies = [ + "async-trait", + "atoi_simd", + "blake3", + "bytes", + "chrono", + "chrono-tz", + "fast-float2", + "fs4", + "futures", + "glob", + "hashbrown 0.16.1", + "home", + "itoa", + "memchr", + "memmap2", + "num-traits", + "object_store", + "percent-encoding", + "polars-arrow", + "polars-compute", + "polars-core", + "polars-error", + "polars-json", + "polars-parquet", + "polars-schema", + "polars-time", + "polars-utils", + "rayon", + "regex", + "reqwest", + "ryu", + "serde", + "serde_json", + "simdutf8", + "tokio", +] + +[[package]] +name = "polars-json" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dd2126daebf58da564fc5840cd55eb8eb2479d24dfced0a1aea2178a9b33b12" +dependencies = [ + "chrono", + "chrono-tz", + "fallible-streaming-iterator", + "hashbrown 0.16.1", + "indexmap", + "itoa", + "num-traits", + "polars-arrow", + "polars-compute", + "polars-error", + "polars-utils", + "ryu", + "simd-json", + "streaming-iterator", +] + +[[package]] +name = "polars-lazy" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea136c360d03aafe56e0233495e30044ce43639b8b0360a4a38e840233f048a1" +dependencies = [ + "bitflags", + "chrono", + "either", + "memchr", + "polars-arrow", + "polars-compute", + "polars-core", + "polars-expr", + "polars-io", + "polars-mem-engine", + "polars-ops", + "polars-plan", + "polars-stream", + "polars-time", + "polars-utils", + "rayon", + "version_check", +] + +[[package]] +name = "polars-mem-engine" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f6e455ceb6e5aee7ed7d5c8944104e66992173e03a9c42f9670226318672249" +dependencies = [ + "memmap2", + "polars-arrow", + "polars-core", + "polars-error", + "polars-expr", + "polars-io", + "polars-ops", + "polars-plan", + "polars-time", + "polars-utils", + "rayon", + "recursive", +] + +[[package]] +name = "polars-ops" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b59c80a019ef0e6f09b4416d2647076a52839305c9eb11919e8298ec667f853" +dependencies = [ + "argminmax", + "base64", + "bytemuck", + "chrono", + "chrono-tz", + "either", + "hashbrown 0.16.1", + "hex", + "indexmap", + "libm", + "memchr", + "num-traits", + "polars-arrow", + "polars-compute", + "polars-core", + "polars-error", + "polars-schema", + "polars-utils", + "rayon", + "regex", + "regex-syntax", + "strum_macros 0.27.2", + "unicode-normalization", + "unicode-reverse", + "version_check", +] + +[[package]] +name = "polars-parquet" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93c2439d127c59e6bfc9d698419bdb45210068a6f501d44e6096429ad72c2eaa" +dependencies = [ + "async-stream", + "base64", + "bytemuck", + "ethnum", + "futures", + "hashbrown 0.16.1", + "num-traits", + "polars-arrow", + "polars-compute", + "polars-error", + "polars-parquet-format", + "polars-utils", + "serde", + "simdutf8", + "streaming-decompression", +] + +[[package]] +name = "polars-parquet-format" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c025243dcfe8dbc57e94d9f82eb3bef10b565ab180d5b99bed87fd8aea319ce1" +dependencies = [ + "async-trait", + "futures", +] + +[[package]] +name = "polars-plan" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65b4619f5c7e9b91f18611c9ed82ebeee4b10052160825c1316ecf4dbd4d97e6" +dependencies = [ + "bitflags", + "bytemuck", + "bytes", + "chrono", + "chrono-tz", + "either", + "hashbrown 0.16.1", + "memmap2", + "num-traits", + "percent-encoding", + "polars-arrow", + "polars-compute", + "polars-core", + "polars-error", + "polars-io", + "polars-ops", + "polars-time", + "polars-utils", + "rayon", + "recursive", + "regex", + "sha2", + "slotmap", + "strum_macros 0.27.2", + "version_check", +] + +[[package]] +name = "polars-row" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18d232f25b83032e280a279a1f40beb8a6f8fc43907b13dc07b1c56f3b11eea" +dependencies = [ + "bitflags", + "bytemuck", + "polars-arrow", + "polars-compute", + "polars-dtype", + "polars-error", + "polars-utils", +] + +[[package]] +name = "polars-schema" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73e21d429ae1c23f442b0220ccfe773a9734a44e997b5062a741842909d9441" +dependencies = [ + "indexmap", + "polars-error", + "polars-utils", + "serde", + "version_check", +] + +[[package]] +name = "polars-sql" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e67ac1cbb0c972a57af3be12f19aa9803898863fe95c33cdd39df05f5738a75" +dependencies = [ + "bitflags", + "hex", + "polars-core", + "polars-error", + "polars-lazy", + "polars-ops", + "polars-plan", + "polars-time", + "polars-utils", + "rand 0.9.2", + "regex", + "serde", + "sqlparser", +] + +[[package]] +name = "polars-stream" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ff19612074640a9d65e5928b7223db76ffee63e55b276f1e466d06719eb7362" +dependencies = [ + "async-channel", + "async-trait", + "atomic-waker", + "bitflags", + "chrono-tz", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-queue", + "crossbeam-utils", + "futures", + "memmap2", + "parking_lot", + "percent-encoding", + "pin-project-lite", + "polars-arrow", + "polars-compute", + "polars-core", + "polars-error", + "polars-expr", + "polars-io", + "polars-mem-engine", + "polars-ops", + "polars-parquet", + "polars-plan", + "polars-time", + "polars-utils", + "rand 0.9.2", + "rayon", + "recursive", + "slotmap", + "tokio", + "version_check", +] + +[[package]] +name = "polars-time" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddce7a9f81d5f47d981bcee4a8db004f9596bb51f0f4d9d93667a1a00d88166c" +dependencies = [ + "atoi_simd", + "bytemuck", + "chrono", + "chrono-tz", + "now", + "num-traits", + "polars-arrow", + "polars-compute", + "polars-core", + "polars-error", + "polars-ops", + "polars-utils", + "rayon", + "regex", + "strum_macros 0.27.2", +] + +[[package]] +name = "polars-utils" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "667c1bc2d2313f934d711f6e3b58d8d9f80351d14ea60af936a26b7dfb06e309" +dependencies = [ + "bincode", + "bytemuck", + "bytes", + "compact_str", + "either", + "flate2", + "foldhash 0.2.0", + "hashbrown 0.16.1", + "indexmap", + "libc", + "memmap2", + "num-traits", + "polars-error", + "rand 0.9.2", + "raw-cpuid", + "rayon", + "regex", + "rmp-serde", + "serde", + "serde_json", + "serde_stacker", + "slotmap", + "stacker", + "uuid", + "version_check", +] + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3852766467df634d74f0b2d7819bf8dc483a0eb2e3b0f50f756f9cfe8b0d18d8" +dependencies = [ + "ar_archive_writer", + "cc", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quick-xml" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.60.2", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_distr" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" +dependencies = [ + "num-traits", + "rand 0.9.2", +] + +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "recursive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0786a43debb760f491b1bc0269fe5e84155353c67482b9e60d0cfb596054b43e" +dependencies = [ + "recursive-proc-macro-impl", + "stacker", +] + +[[package]] +name = "recursive-proc-macro-impl" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76009fbe0614077fc1a2ce255e3a1881a2e3a3527097d5dc6d8212c585e7e38b" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rkyv" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rmp" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "rmp-serde" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155" +dependencies = [ + "rmp", + "serde", +] + +[[package]] +name = "rust_decimal" +version = "1.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ce901f9a19d251159075a4c37af514c3b8ef99c22e02dd8c19161cf397ee94a" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", + "wasm-bindgen", +] + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "indexmap", + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_stacker" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4936375d50c4be7eff22293a9344f8e46f323ed2b3c243e52f89138d9bb0f4a" +dependencies = [ + "serde", + "serde_core", + "stacker", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "simd-json" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4255126f310d2ba20048db6321c81ab376f6a6735608bf11f0785c41f01f64e3" +dependencies = [ + "ahash 0.8.12", + "halfbrown", + "once_cell", + "ref-cast", + "serde", + "serde_json", + "simdutf8", + "value-trait", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "sprintf" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0e59842c3aac5c7901ea11bbb02e60e5d67263b43d4361dec9303cca8e764eb" +dependencies = [ + "thiserror 2.0.18", +] + +[[package]] +name = "sqlparser" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05a528114c392209b3264855ad491fcce534b94a38771b0a0b97a79379275ce8" +dependencies = [ + "log", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stacker" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d74a23609d509411d10e2176dc2a4346e3b4aea2e7b1869f19fdedbc71c013" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.59.0", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "streaming-decompression" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf6cc3b19bfb128a8ad11026086e31d3ce9ad23f8ea37354b31383a187c44cf3" +dependencies = [ + "fallible-streaming-iterator", +] + +[[package]] +name = "streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520" + +[[package]] +name = "strength_reduce" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros 0.27.2", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.117", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tar" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml_datetime" +version = "1.1.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.8+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16bff38f1d86c47f9ff0647e6838d7bb362522bdf44006c7068c2b1e606f1f3c" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" +dependencies = [ + "winnow", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tree-sitter" +version = "0.26.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a6592b1aec0109df37b6bafea77eb4e61466e37b0a5a98bef4f89bfb81b7a2" +dependencies = [ + "cc", + "regex", + "regex-syntax", + "serde_json", + "streaming-iterator", + "tree-sitter-language", +] + +[[package]] +name = "tree-sitter-ggsql" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120201f125d130513f353fac561e162437f612ff96f5e9f29dd8646af43baa64" +dependencies = [ + "cc", + "tree-sitter", +] + +[[package]] +name = "tree-sitter-language" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "009994f150cc0cd50ff54917d5bc8bffe8cad10ca10d81c34da2ec421ae61782" + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "uncased" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-reverse" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6f4888ebc23094adfb574fdca9fdc891826287a6397d2cd28802ffd6f20c76" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "unicode-segmentation" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" +dependencies = [ + "getrandom 0.4.2", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "value-trait" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e80f0c733af0720a501b3905d22e2f97662d8eacfe082a75ed7ffb5ab08cb59" +dependencies = [ + "float-cmp", + "halfbrown", + "itoa", + "ryu", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6523d69017b7633e396a89c5efab138161ed5aafcbc8d3e5c5a42ae38f50495a" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "serde", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d1faf851e778dfa54db7cd438b70758eba9755cb47403f3496edd7c8fc212f0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e3a6c758eb2f701ed3d052ff5737f5bfe6614326ea7f3bbac7156192dc32e67" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "921de2737904886b52bcbb237301552d05969a6f9c40d261eb0533c8b055fedf" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a93e946af942b58934c604527337bad9ae33ba1d5c6900bbb41c2c07c2364a93" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84cde8507f4d7cfcb1185b8cb5890c494ffea65edbe1ba82cfd63661c805ed94" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "xxhash-rust" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zip" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2a05c7c36fde6c09b08576c9f7fb4cda705990f73b58fe011abf7dfb24168b" +dependencies = [ + "arbitrary", + "crc32fast", + "flate2", + "indexmap", + "memchr", + "zopfli", +] + +[[package]] +name = "zlib-rs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/ggsql-R/src/rust/Cargo.toml b/ggsql-R/src/rust/Cargo.toml new file mode 100644 index 00000000..0824fb59 --- /dev/null +++ b/ggsql-R/src/rust/Cargo.toml @@ -0,0 +1,22 @@ +[workspace] + +[package] +name = 'ggsql-r' +publish = false +version = '0.1.9' +edition = '2021' +rust-version = '1.65' + +[lib] +crate-type = ['staticlib'] +name = 'ggsql' + +[dependencies] +extendr-api = '0.8.1' +ggsql = { version = "0.1.9", default-features = false, features = ["duckdb", "vegalite", "builtin-data"] } +polars = { version = "0.52", default-features = false, features = ["ipc_streaming", "dtype-full", "timezones", "cum_agg"] } +serde_json = "1.0" + +[profile.release] +lto = true +codegen-units = 1 diff --git a/ggsql-R/src/rust/figure/-1.png b/ggsql-R/src/rust/figure/-1.png new file mode 100644 index 00000000..5c7a60bd Binary files /dev/null and b/ggsql-R/src/rust/figure/-1.png differ diff --git a/ggsql-R/src/rust/src/lib.rs b/ggsql-R/src/rust/src/lib.rs new file mode 100644 index 00000000..c10c88b5 --- /dev/null +++ b/ggsql-R/src/rust/src/lib.rs @@ -0,0 +1,250 @@ +use extendr_api::prelude::*; + +use ggsql::reader::{DuckDBReader as RustDuckDBReader, Reader, Spec}; +use ggsql::validate::validate as rust_validate; +use ggsql::writer::{VegaLiteWriter as RustVegaLiteWriter, Writer}; +use polars::prelude::{DataFrame, IpcStreamReader, IpcStreamWriter, SerReader, SerWriter}; +use std::io::Cursor; + +// ============================================================================ +// IPC Conversion Helpers +// ============================================================================ + +fn ipc_stream_to_polars(bytes: &[u8]) -> std::result::Result { + let cursor = Cursor::new(bytes); + IpcStreamReader::new(cursor) + .finish() + .map_err(|e| format!("Failed to read Arrow IPC stream: {e}")) +} + +fn polars_to_ipc_stream(df: &DataFrame) -> std::result::Result, String> { + let mut buffer = Vec::new(); + IpcStreamWriter::new(&mut buffer) + .finish(&mut df.clone()) + .map_err(|e| format!("Failed to write Arrow IPC stream: {e}"))?; + Ok(buffer) +} + +// ============================================================================ +// GgsqlReader — wraps ggsql::reader::DuckDBReader +// ============================================================================ + +#[extendr] +pub struct GgsqlReader { + inner: RustDuckDBReader, +} + +#[extendr] +impl GgsqlReader { + fn new(connection: &str) -> Self { + let inner = RustDuckDBReader::from_connection_string(connection) + .expect("Failed to create DuckDB reader"); + Self { inner } + } + + fn register_ipc(&self, name: &str, ipc_bytes: Raw, replace: bool) { + let df = + ipc_stream_to_polars(ipc_bytes.as_slice()).expect("Failed to deserialize IPC data"); + self.inner + .register(name, df, replace) + .expect("Failed to register table"); + } + + fn unregister(&self, name: &str) { + self.inner + .unregister(name) + .expect("Failed to unregister table"); + } + + fn execute_sql_ipc(&self, sql: &str) -> Robj { + let df = self.inner.execute_sql(sql).expect("SQL execution failed"); + let bytes = polars_to_ipc_stream(&df).expect("Failed to serialize DataFrame"); + Raw::from_bytes(&bytes).into_robj() + } + + fn execute(&self, query: &str) -> GgsqlSpec { + let spec = self + .inner + .execute(query) + .expect("Query execution failed"); + GgsqlSpec { inner: spec } + } +} + +// ============================================================================ +// GgsqlSpec — wraps ggsql::reader::Spec +// ============================================================================ + +#[extendr] +pub struct GgsqlSpec { + inner: Spec, +} + +#[extendr] +impl GgsqlSpec { + fn metadata_rows(&self) -> i32 { + self.inner.metadata().rows as i32 + } + + fn metadata_columns(&self) -> Vec { + self.inner.metadata().columns.clone() + } + + fn metadata_layer_count(&self) -> i32 { + self.inner.metadata().layer_count as i32 + } + + fn get_sql(&self) -> &str { + self.inner.sql() + } + + fn get_visual(&self) -> &str { + self.inner.visual() + } + + fn layer_count(&self) -> i32 { + self.inner.layer_count() as i32 + } + + fn layer_data_ipc(&self, index: i32) -> Nullable { + match self.inner.layer_data(index as usize) { + Some(df) => { + let bytes = polars_to_ipc_stream(df).expect("Failed to serialize layer data"); + Nullable::NotNull(Raw::from_bytes(&bytes).into_robj()) + } + None => Nullable::Null, + } + } + + fn stat_data_ipc(&self, index: i32) -> Nullable { + match self.inner.stat_data(index as usize) { + Some(df) => { + let bytes = polars_to_ipc_stream(df).expect("Failed to serialize stat data"); + Nullable::NotNull(Raw::from_bytes(&bytes).into_robj()) + } + None => Nullable::Null, + } + } + + fn get_layer_sql(&self, index: i32) -> Nullable { + match self.inner.layer_sql(index as usize) { + Some(s) => Nullable::NotNull(s.to_string()), + None => Nullable::Null, + } + } + + fn get_stat_sql(&self, index: i32) -> Nullable { + match self.inner.stat_sql(index as usize) { + Some(s) => Nullable::NotNull(s.to_string()), + None => Nullable::Null, + } + } + + fn warnings_json(&self) -> String { + let warnings: Vec = self + .inner + .warnings() + .iter() + .map(|w| { + serde_json::json!({ + "message": w.message, + "location": w.location.as_ref().map(|l| { + serde_json::json!({"line": l.line, "column": l.column}) + }) + }) + }) + .collect(); + serde_json::to_string(&warnings).unwrap_or_else(|_| "[]".to_string()) + } +} + +// ============================================================================ +// GgsqlWriter — wraps ggsql::writer::VegaLiteWriter +// ============================================================================ + +#[extendr] +pub struct GgsqlWriter { + inner: RustVegaLiteWriter, +} + +#[extendr] +impl GgsqlWriter { + fn new() -> Self { + Self { + inner: RustVegaLiteWriter::new(), + } + } + + fn render(&self, spec: &GgsqlSpec) -> String { + self.inner + .render(&spec.inner) + .expect("Render failed") + } +} + +// ============================================================================ +// Module Functions +// ============================================================================ + +#[extendr] +fn ggsql_validate_impl(query: &str) -> List { + let v = match rust_validate(query) { + Ok(v) => v, + Err(e) => panic!("Validation failed: {e}"), + }; + + let errors_json = serde_json::to_string( + &v.errors() + .iter() + .map(|e| { + serde_json::json!({ + "message": e.message, + "line": e.location.as_ref().map(|l| l.line), + "column": e.location.as_ref().map(|l| l.column) + }) + }) + .collect::>(), + ) + .unwrap_or_else(|_| "[]".to_string()); + + let warnings_json = serde_json::to_string( + &v.warnings() + .iter() + .map(|w| { + serde_json::json!({ + "message": w.message, + "line": w.location.as_ref().map(|l| l.line), + "column": w.location.as_ref().map(|l| l.column) + }) + }) + .collect::>(), + ) + .unwrap_or_else(|_| "[]".to_string()); + + list!( + sql = v.sql().to_string(), + visual = v.visual().to_string(), + has_visual = v.has_visual(), + valid = v.valid(), + errors_json = errors_json, + warnings_json = warnings_json + ) +} + +#[extendr] +fn ggsql_version_impl() -> &'static str { + ggsql::VERSION +} + +// ============================================================================ +// Module Registration +// ============================================================================ + +extendr_module! { + mod ggsql; + impl GgsqlReader; + impl GgsqlSpec; + impl GgsqlWriter; + fn ggsql_validate_impl; + fn ggsql_version_impl; +} diff --git a/ggsql-R/tests/testthat/_snaps/engine.md b/ggsql-R/tests/testthat/_snaps/engine.md index a7202335..f76cfc42 100644 --- a/ggsql-R/tests/testthat/_snaps/engine.md +++ b/ggsql-R/tests/testthat/_snaps/engine.md @@ -50,5 +50,50 @@ (8.7, 22.3) ) AS t(x, y) ) TO 'data.csv' (HEADER, DELIMITER ',') - ## 2 + +# r: prefix resolves R objects + + Code + cat(out) + Output + SELECT mpg, disp FROM r:test_df + | mpg| disp| + |----:|----:| + | 21.0| 160| + | 21.0| 160| + | 22.8| 108| + | 21.4| 258| + | 18.7| 360| + +# multiple r: refs in one query work + + Code + cat(out) + Output + SELECT a.id, a.x, b.y FROM r:df_a a JOIN r:df_b b ON a.id = b.id + | id| x| y| + |--:|--:|--:| + | 1| 10| 20| + | 2| 11| 21| + | 3| 12| 22| + +# connection option creates a DuckDB reader + + Code + cat(out) + Output + SELECT 1 AS x, 2 AS y + | x| y| + |--:|--:| + | 1| 2| + +# writer option is ignored for plain SQL + + Code + cat(out) + Output + SELECT 1 AS x, 2 AS y + | x| y| + |--:|--:| + | 1| 2| diff --git a/ggsql-R/tests/testthat/_snaps/engine/test_chunks.md b/ggsql-R/tests/testthat/_snaps/engine/test_chunks.md deleted file mode 100644 index 74e4ef5b..00000000 --- a/ggsql-R/tests/testthat/_snaps/engine/test_chunks.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: "Test chunks" -author: "Test author" -format: html ---- - - -``` r -library(ggsql) -test_file <- "test.csv" -write.csv(mtcars, test_file) -``` - -![plot of chunk unnamed-chunk-2](figure/unnamed-chunk-2-1.png) - - -``` r -unlink(test_file) -``` diff --git a/ggsql-R/tests/testthat/figure/-1.png b/ggsql-R/tests/testthat/figure/-1.png new file mode 100644 index 00000000..30146935 Binary files /dev/null and b/ggsql-R/tests/testthat/figure/-1.png differ diff --git a/ggsql-R/tests/testthat/test-engine.R b/ggsql-R/tests/testthat/test-engine.R index 460fce3c..688dcf27 100644 --- a/ggsql-R/tests/testthat/test-engine.R +++ b/ggsql-R/tests/testthat/test-engine.R @@ -1,7 +1,3 @@ -skip_if_not_installed("png") -skip_if_not_installed("rsvg") -skip_if_not_installed("V8") - run_query <- function(query, ...) { opts <- knitr::opts_current$get() opts$code <- query @@ -48,6 +44,250 @@ test_that("engine does not return a table when merely creating data", { expect_snapshot(cat(out)) }) +# --- Data reference tests (r: and py: prefixes) --- + +test_that("r: prefix resolves R objects", { + # Put data into the knitr global environment + assign("test_df", mtcars[1:5, c("mpg", "disp")], envir = knitr::knit_global()) + on.exit(rm("test_df", envir = knitr::knit_global())) + + query <- "SELECT mpg, disp FROM r:test_df" + out <- run_query(query) + expect_snapshot(cat(out)) +}) + +test_that("r: prefix works in visualisation queries", { + assign("test_df", mtcars[1:5, c("mpg", "disp")], envir = knitr::knit_global()) + on.exit(rm("test_df", envir = knitr::knit_global())) + + query <- c( + "SELECT * FROM r:test_df", + "VISUALISE mpg AS x, disp AS y", + "DRAW point" + ) + out <- run_query(query, dev = "png") + expect_type(out, "character") + expect_length(out, 1L) +}) + +test_that("r: prefix errors for missing objects", { + query <- "SELECT * FROM r:nonexistent_object_xyz" + out <- run_query(query) + expect_match(out, "not found", ignore.case = TRUE) +}) + +test_that("r: prefix errors for non-data-frame objects", { + assign("not_a_df", "just a string", envir = knitr::knit_global()) + on.exit(rm("not_a_df", envir = knitr::knit_global())) + + query <- "SELECT * FROM r:not_a_df" + out <- run_query(query) + expect_match(out, "data frame", ignore.case = TRUE) +}) + +test_that("multiple r: refs in one query work", { + assign("df_a", data.frame(id = 1:3, x = 10:12), envir = knitr::knit_global()) + assign("df_b", data.frame(id = 1:3, y = 20:22), envir = knitr::knit_global()) + on.exit({ + rm("df_a", envir = knitr::knit_global()) + rm("df_b", envir = knitr::knit_global()) + }) + + query <- "SELECT a.id, a.x, b.y FROM r:df_a a JOIN r:df_b b ON a.id = b.id" + out <- run_query(query) + expect_snapshot(cat(out)) +}) + +# --- output.var and sql proxy tests --- + +test_that("output.var captures SQL result as data frame", { + query <- "SELECT 1 AS x, 2 AS y" + run_query(query, output.var = "captured_df") + df <- get("captured_df", envir = knitr::knit_global()) + on.exit(rm("captured_df", envir = knitr::knit_global())) + + expect_s3_class(df, "data.frame") + expect_equal(nrow(df), 1) + expect_equal(names(df), c("x", "y")) +}) + +test_that("output.var captures Vega-Lite JSON for viz queries", { + assign("test_df", mtcars[1:5, c("mpg", "disp")], envir = knitr::knit_global()) + on.exit( + rm(list = c("test_df", "captured_json"), envir = knitr::knit_global()), + add = TRUE + ) + + query <- c( + "SELECT * FROM r:test_df", + "VISUALISE mpg AS x, disp AS y", + "DRAW point" + ) + run_query(query, output.var = "captured_json") + json <- get("captured_json", envir = knitr::knit_global()) + + expect_type(json, "character") + expect_match(json, "vega-lite") +}) + +#test_that("sql proxy can access registered tables", { +# reader <- get_engine_reader() +# ggsql_register(reader, mtcars[1:3, c("mpg", "disp")], "proxy_test") +# +# sql_obj <- get("sql", envir = knitr::knit_global()) +# df <- sql_obj$proxy_test +# expect_s3_class(df, "data.frame") +# expect_equal(nrow(df), 3) +# expect_equal(names(df), c("mpg", "disp")) +#}) + +#test_that("sql proxy names() lists tables", { +# reader <- get_engine_reader() +# ggsql_register(reader, data.frame(a = 1), "names_test") +# +# sql_obj <- get("sql", envir = knitr::knit_global()) +# tbl_names <- names(sql_obj) +# expect_true("names_test" %in% tbl_names) +#}) + +# --- Inline chunk options (--| and #|) --- + +test_that("--| prefix parses chunk options", { + query <- c( + "--| output.var: my_result", + "SELECT 1 AS x, 2 AS y" + ) + run_query(query) + df <- get("my_result", envir = knitr::knit_global()) + on.exit(rm("my_result", envir = knitr::knit_global())) + + expect_s3_class(df, "data.frame") + expect_equal(names(df), c("x", "y")) +}) + +test_that("#| prefix parses chunk options", { + query <- c( + "#| output.var: my_result2", + "SELECT 1 AS a, 2 AS b" + ) + run_query(query) + df <- get("my_result2", envir = knitr::knit_global()) + on.exit(rm("my_result2", envir = knitr::knit_global())) + + expect_s3_class(df, "data.frame") + expect_equal(names(df), c("a", "b")) +}) + +test_that("Quarto-style kebab-case options are converted", { + query <- c( + "--| output-var: my_result3", + "SELECT 10 AS val" + ) + run_query(query) + df <- get("my_result3", envir = knitr::knit_global()) + on.exit(rm("my_result3", envir = knitr::knit_global())) + + expect_s3_class(df, "data.frame") +}) + +# --- Connection option tests --- + +test_that("connection option creates a DuckDB reader", { + query <- "SELECT 1 AS x, 2 AS y" + out <- run_query(query, connection = "duckdb://memory") + expect_snapshot(cat(out)) +}) + +test_that("connection option rejects unsupported schemes", { + query <- "SELECT 1 AS x" + out <- run_query(query, connection = "mysql://localhost") + expect_match(out, "Unsupported connection scheme") +}) + +test_that("connection option rejects invalid format", { + query <- "SELECT 1 AS x" + out <- run_query(query, connection = "not-a-uri") + expect_match(out, "Invalid connection string") +}) + +# --- Writer option tests --- + +test_that("writer defaults to interactive vegalite", { + query <- c( + paste0("SELECT mpg, disp FROM '", data_file, "'"), + "VISUALISE mpg AS x, disp AS y", + "DRAW point" + ) + out <- run_query(query) + expect_match(out, "vega-embed") +}) + +test_that("writer = 'vegalite_svg' produces SVG output", { + skip_if_not_installed("V8") + skip_on_cran() + skip_if_not_installed("withr") + + fig_dir <- withr::local_tempdir() + + query <- c( + paste0("SELECT mpg, disp FROM '", data_file, "'"), + "VISUALISE mpg AS x, disp AS y", + "DRAW point" + ) + out <- run_query( + query, + writer = "vegalite_svg", + fig.path = paste0(fig_dir, "/fig-"), + label = "test-svg" + ) + + svg_files <- list.files(fig_dir, pattern = "\\.svg$") + expect_length(svg_files, 1L) + expect_match(out, "\\.svg") +}) + +test_that("writer = 'vegalite_png' produces PNG output", { + skip_if_not_installed("V8") + skip_if_not_installed("rsvg") + skip_on_cran() + skip_if_not_installed("withr") + + fig_dir <- withr::local_tempdir() + + query <- c( + paste0("SELECT mpg, disp FROM '", data_file, "'"), + "VISUALISE mpg AS x, disp AS y", + "DRAW point" + ) + out <- run_query( + query, + writer = "vegalite_png", + fig.path = paste0(fig_dir, "/fig-"), + label = "test-png" + ) + + png_files <- list.files(fig_dir, pattern = "\\.png$") + expect_length(png_files, 1L) + expect_match(out, "\\.png") +}) + +test_that("writer option is ignored for plain SQL", { + query <- "SELECT 1 AS x, 2 AS y" + out <- run_query(query, writer = "vegalite_png") + # Should produce a table, not an image + expect_snapshot(cat(out)) +}) + +test_that("invalid writer option produces error", { + query <- c( + paste0("SELECT mpg, disp FROM '", data_file, "'"), + "VISUALISE mpg AS x, disp AS y", + "DRAW point" + ) + out <- run_query(query, writer = "ggplot2") + expect_match(out, "Unsupported writer") +}) + test_that("we can knit a mixed-chunk document", { skip_if_not_installed("withr") @@ -66,6 +306,9 @@ test_that("we can knit a mixed-chunk document", { out <- knitr::knit(input = in_file, output = out_file, quiet = TRUE) expect_equal(out_file, out) + expect_true(file.exists(out)) - expect_snapshot_file(out) + # Check that visualization was rendered (contains vega-embed script) + content <- readLines(out) + expect_true(any(grepl("vega-embed", content))) }) diff --git a/ggsql-R/tests/testthat/test-reader.R b/ggsql-R/tests/testthat/test-reader.R new file mode 100644 index 00000000..b49f532c --- /dev/null +++ b/ggsql-R/tests/testthat/test-reader.R @@ -0,0 +1,56 @@ +test_that("duckdb_reader creates a reader", { + reader <- duckdb_reader() + expect_s3_class(reader, "Reader") +}) + +test_that("ggsql_register registers a data frame", { + reader <- duckdb_reader() + result <- ggsql_register(reader, mtcars, "cars") + expect_invisible(ggsql_register(reader, iris, "iris")) + # Returns reader for piping + + expect_s3_class(result, "Reader") +}) + +test_that("ggsql_register with replace works", { + reader <- duckdb_reader() + ggsql_register(reader, mtcars, "data") + ggsql_register(reader, iris, "data", replace = TRUE) + df <- ggsql_execute_sql(reader, "SELECT * FROM data LIMIT 1") + expect_true("Sepal.Length" %in% names(df)) +}) + +test_that("ggsql_unregister removes a table", { + reader <- duckdb_reader() + ggsql_register(reader, mtcars, "cars") + ggsql_unregister(reader, "cars") + expect_error(ggsql_execute_sql(reader, "SELECT * FROM cars")) +}) + +test_that("ggsql_execute_sql returns a data frame", { + reader <- duckdb_reader() + ggsql_register(reader, mtcars, "cars") + df <- ggsql_execute_sql(reader, "SELECT mpg, disp FROM cars LIMIT 5") + expect_s3_class(df, "data.frame") + expect_equal(nrow(df), 5) + expect_equal(names(df), c("mpg", "disp")) +}) + +test_that("ggsql_execute returns a spec", { + reader <- duckdb_reader() + ggsql_register(reader, mtcars, "cars") + spec <- ggsql_execute( + reader, + "SELECT * FROM cars VISUALISE mpg AS x, disp AS y DRAW point" + ) + expect_s3_class(spec, "Spec") +}) + +test_that("piping works", { + reader <- duckdb_reader() + result <- reader |> + ggsql_register(mtcars, "cars") |> + ggsql_execute_sql("SELECT mpg FROM cars LIMIT 3") + expect_s3_class(result, "data.frame") + expect_equal(nrow(result), 3) +}) diff --git a/ggsql-R/tests/testthat/test-spec.R b/ggsql-R/tests/testthat/test-spec.R new file mode 100644 index 00000000..a0bf0c8d --- /dev/null +++ b/ggsql-R/tests/testthat/test-spec.R @@ -0,0 +1,80 @@ +test_that("ggsql_metadata returns correct structure", { + reader <- duckdb_reader() + ggsql_register(reader, mtcars, "cars") + spec <- ggsql_execute( + reader, + "SELECT * FROM cars VISUALISE mpg AS x, disp AS y DRAW point" + ) + m <- ggsql_metadata(spec) + expect_type(m, "list") + expect_equal(m$rows, 32L) + expect_type(m$columns, "character") + expect_equal(m$layer_count, 1L) +}) + +test_that("ggsql_sql returns the SQL portion", { + reader <- duckdb_reader() + ggsql_register(reader, mtcars, "cars") + spec <- ggsql_execute( + reader, + "SELECT * FROM cars VISUALISE mpg AS x, disp AS y DRAW point" + ) + sql <- ggsql_sql(spec) + expect_type(sql, "character") + expect_match(sql, "SELECT") +}) + +test_that("ggsql_visual returns the VISUALISE portion", { + reader <- duckdb_reader() + ggsql_register(reader, mtcars, "cars") + spec <- ggsql_execute( + reader, + "SELECT * FROM cars VISUALISE mpg AS x, disp AS y DRAW point" + ) + vis <- ggsql_visual(spec) + expect_type(vis, "character") + expect_match(vis, "VISUALISE") +}) + +test_that("ggsql_layer_count returns integer", { + reader <- duckdb_reader() + ggsql_register(reader, mtcars, "cars") + spec <- ggsql_execute( + reader, + "SELECT * FROM cars VISUALISE mpg AS x, disp AS y DRAW point DRAW line MAPPING mpg AS x, disp AS y" + ) + expect_equal(ggsql_layer_count(spec), 2L) +}) + +test_that("ggsql_layer_data returns a data frame", { + reader <- duckdb_reader() + ggsql_register(reader, mtcars, "cars") + spec <- ggsql_execute( + reader, + "SELECT * FROM cars VISUALISE mpg AS x, disp AS y DRAW point" + ) + df <- ggsql_layer_data(spec, 1L) + expect_s3_class(df, "data.frame") + expect_equal(nrow(df), 32) +}) + +test_that("ggsql_warnings returns a data frame", { + reader <- duckdb_reader() + ggsql_register(reader, mtcars, "cars") + spec <- ggsql_execute( + reader, + "SELECT * FROM cars VISUALISE mpg AS x, disp AS y DRAW point" + ) + w <- ggsql_warnings(spec) + expect_s3_class(w, "data.frame") +}) + +test_that("spec str method shows metadata", { + reader <- duckdb_reader() + ggsql_register(reader, mtcars, "cars") + spec <- ggsql_execute( + reader, + "SELECT * FROM cars VISUALISE mpg AS x, disp AS y DRAW point" + ) + expect_invisible(str(spec)) +}) diff --git a/ggsql-R/tests/testthat/test-validate.R b/ggsql-R/tests/testthat/test-validate.R new file mode 100644 index 00000000..0db12252 --- /dev/null +++ b/ggsql-R/tests/testthat/test-validate.R @@ -0,0 +1,42 @@ +test_that("ggsql_validate returns a ggsql_validated object", { + v <- ggsql_validate( + "SELECT 1 AS x, 2 AS y VISUALISE DRAW point MAPPING x AS x, y AS y" + ) + expect_s3_class(v, "ggsql_validated") + expect_true(v$has_visual) + expect_true(v$valid) +}) + +test_that("ggsql_validate detects errors", { + v <- ggsql_validate("SELECT 1 AS x VISUALISE x DRAW point") + expect_false(v$valid) + expect_true(NROW(v$errors) > 0) +}) + +test_that("ggsql_validate handles pure SQL", { + v <- ggsql_validate("SELECT 1 AS x") + expect_false(v$has_visual) + expect_true(v$valid) +}) + +test_that("ggsql_has_visual works", { + v <- ggsql_validate("SELECT 1 AS x VISUALISE x DRAW point") + expect_true(ggsql_has_visual(v)) + + v2 <- ggsql_validate("SELECT 1 AS x") + expect_false(ggsql_has_visual(v2)) +}) + +test_that("ggsql_is_valid works", { + v <- ggsql_validate( + "SELECT 1 AS x, 2 AS y VISUALISE DRAW point MAPPING x AS x, y AS y" + ) + expect_true(ggsql_is_valid(v)) +}) + +test_that("print.ggsql_validated works", { + v <- ggsql_validate( + "SELECT 1 AS x, 2 AS y VISUALISE DRAW point MAPPING x AS x, y AS y" + ) + expect_invisible(print(v)) +}) diff --git a/ggsql-R/tests/testthat/test-writer.R b/ggsql-R/tests/testthat/test-writer.R new file mode 100644 index 00000000..27f6a871 --- /dev/null +++ b/ggsql-R/tests/testthat/test-writer.R @@ -0,0 +1,20 @@ +test_that("vegalite_writer creates a writer", { + writer <- vegalite_writer() + expect_s3_class(writer, "Writer") +}) + +test_that("ggsql_render returns Vega-Lite JSON", { + reader <- duckdb_reader() + ggsql_register(reader, mtcars, "cars") + spec <- ggsql_execute( + reader, + "SELECT * FROM cars VISUALISE mpg AS x, disp AS y DRAW point" + ) + writer <- vegalite_writer() + json <- ggsql_render(writer, spec) + expect_type(json, "character") + expect_match(json, "vega-lite") + # Should be valid JSON + parsed <- jsonlite::fromJSON(json) + expect_true("$schema" %in% names(parsed)) +}) diff --git a/ggsql-R/tools/config.R b/ggsql-R/tools/config.R new file mode 100644 index 00000000..06d57cdd --- /dev/null +++ b/ggsql-R/tools/config.R @@ -0,0 +1,112 @@ +# Note: Any variables prefixed with `.` are used for text +# replacement in the Makevars.in and Makevars.win.in + +# check the packages MSRV first +source("tools/msrv.R") + +# check DEBUG and NOT_CRAN environment variables +env_debug <- Sys.getenv("DEBUG") +env_not_cran <- Sys.getenv("NOT_CRAN") + +# check if the vendored zip file exists +vendor_exists <- file.exists("src/rust/vendor.tar.xz") + +is_not_cran <- env_not_cran != "" +is_debug <- env_debug != "" + +if (is_debug) { + # if we have DEBUG then we set not cran to true + # CRAN is always release build + is_not_cran <- TRUE + message("Creating DEBUG build.") +} + +if (!is_not_cran) { + message("Building for CRAN.") +} + +# we set cran flags only if NOT_CRAN is empty and if +# the vendored crates are present. +.cran_flags <- ifelse( + !is_not_cran && vendor_exists, + "-j 2 --offline", + "" +) + +# when DEBUG env var is present we use `--debug` build +.profile <- ifelse(is_debug, "", "--release") +.clean_targets <- ifelse(is_debug, "", "$(TARGET_DIR)") + +# We specify this target when building for webR +webr_target <- "wasm32-unknown-emscripten" + +# here we check if the platform we are building for is webr +is_wasm <- identical(R.version$platform, webr_target) + +# print to terminal to inform we are building for webr +if (is_wasm) { + message("Building for WebR") +} + +# we check if we are making a debug build or not +# if so, the LIBDIR environment variable becomes: +# LIBDIR = $(TARGET_DIR)/{wasm32-unknown-emscripten}/debug +# this will be used to fill out the LIBDIR env var for Makevars.in +target_libpath <- if (is_wasm) "wasm32-unknown-emscripten" else NULL +cfg <- if (is_debug) "debug" else "release" + +# used to replace @LIBDIR@ +.libdir <- paste(c(target_libpath, cfg), collapse = "/") + +# use this to replace @TARGET@ +# we specify the target _only_ on webR +# there may be use cases later where this can be adapted or expanded +.target <- ifelse(is_wasm, paste0("--target=", webr_target), "") + +# add panic exports only for WASM builds +.panic_exports <- ifelse( + is_wasm, + "CARGO_PROFILE_DEV_PANIC=\"abort\" CARGO_PROFILE_RELEASE_PANIC=\"abort\" ", + "" +) + +# read in the Makevars.in file checking +is_windows <- .Platform[["OS.type"]] == "windows" + +# if windows we replace in the Makevars.win.in +mv_fp <- ifelse( + is_windows, + "src/Makevars.win.in", + "src/Makevars.in" +) + +# set the output file +mv_ofp <- ifelse( + is_windows, + "src/Makevars.win", + "src/Makevars" +) + +# delete the existing Makevars{.win/.wasm} +if (file.exists(mv_ofp)) { + message("Cleaning previous `", mv_ofp, "`.") + invisible(file.remove(mv_ofp)) +} + +# read as a single string +mv_txt <- readLines(mv_fp) + +# replace placeholder values +new_txt <- gsub("@CRAN_FLAGS@", .cran_flags, mv_txt) |> + gsub("@PROFILE@", .profile, x = _) |> + gsub("@CLEAN_TARGET@", .clean_targets, x = _) |> + gsub("@LIBDIR@", .libdir, x = _) |> + gsub("@TARGET@", .target, x = _) |> + gsub("@PANIC_EXPORTS@", .panic_exports, x = _) + +message("Writing `", mv_ofp, "`.") +con <- file(mv_ofp, open = "wb") +writeLines(new_txt, con, sep = "\n") +close(con) + +message("`tools/config.R` has finished.") diff --git a/ggsql-R/tools/msrv.R b/ggsql-R/tools/msrv.R new file mode 100644 index 00000000..9a4f76e2 --- /dev/null +++ b/ggsql-R/tools/msrv.R @@ -0,0 +1,120 @@ +# read the DESCRIPTION file +desc <- read.dcf("DESCRIPTION") + +if (!"SystemRequirements" %in% colnames(desc)) { + fmt <- c( + "`SystemRequirements` not found in `DESCRIPTION`.", + "Please specify `SystemRequirements: Cargo (Rust's package manager), rustc`" + ) + stop(paste(fmt, collapse = "\n")) +} + +# extract system requirements +sysreqs <- desc[, "SystemRequirements"] + +# check that cargo and rustc is found +if (!grepl("cargo", sysreqs, ignore.case = TRUE)) { + stop( + "You must specify `Cargo (Rust's package manager)` in your `SystemRequirements`" + ) +} + +if (!grepl("rustc", sysreqs, ignore.case = TRUE)) { + stop( + "You must specify `Cargo (Rust's package manager), rustc` in your `SystemRequirements`" + ) +} + +# split into parts +parts <- strsplit(sysreqs, ", ")[[1]] + +# identify which is the rustc +rustc_ver <- parts[grepl("rustc", parts)] + +# perform checks for the presence of rustc and cargo on the OS +no_cargo_msg <- c( + "----------------------- [CARGO NOT FOUND]--------------------------", + "The 'cargo' command was not found on the PATH. Please install Cargo", + "from: https://www.rust-lang.org/tools/install", + "", + "Alternatively, you may install Cargo from your OS package manager:", + " - Debian/Ubuntu: apt-get install cargo", + " - Fedora/CentOS: dnf install cargo", + " - macOS: brew install rust", + "-------------------------------------------------------------------" +) + +no_rustc_msg <- c( + "----------------------- [RUST NOT FOUND]---------------------------", + "The 'rustc' compiler was not found on the PATH. Please install", + paste(rustc_ver, "or higher from:"), + "https://www.rust-lang.org/tools/install", + "", + "Alternatively, you may install Rust from your OS package manager:", + " - Debian/Ubuntu: apt-get install rustc", + " - Fedora/CentOS: dnf install rustc", + " - macOS: brew install rust", + "-------------------------------------------------------------------" +) + +# Add {user}/.cargo/bin to path before checking +new_path <- paste0( + Sys.getenv("PATH"), + ":", + paste0(Sys.getenv("HOME"), "/.cargo/bin") +) + +# set the path with the new path +Sys.setenv("PATH" = new_path) + +# check for rustc installation +rustc_version <- tryCatch( + system("rustc --version", intern = TRUE), + error = function(e) { + stop(paste(no_rustc_msg, collapse = "\n")) + } +) + +# check for cargo installation +cargo_version <- tryCatch( + system("cargo --version", intern = TRUE), + error = function(e) { + stop(paste(no_cargo_msg, collapse = "\n")) + } +) + +# helper function to extract versions +extract_semver <- function(ver) { + if (grepl("\\d+\\.\\d+(\\.\\d+)?", ver)) { + sub(".*?(\\d+\\.\\d+(\\.\\d+)?).*", "\\1", ver) + } else { + NA + } +} + +# get the MSRV +msrv <- extract_semver(rustc_ver) + +# extract current version +current_rust_version <- extract_semver(rustc_version) + +# perform check +if (!is.na(msrv)) { + # -1 when current version is later + # 0 when they are the same + # 1 when MSRV is newer than current + is_msrv <- utils::compareVersion(msrv, current_rust_version) + if (is_msrv == 1) { + fmt <- paste0( + "\n------------------ [UNSUPPORTED RUST VERSION]------------------\n", + "- Minimum supported Rust version is %s.\n", + "- Installed Rust version is %s.\n", + "---------------------------------------------------------------" + ) + stop(sprintf(fmt, msrv, current_rust_version)) + } +} + +# print the versions +versions_fmt <- "Using %s\nUsing %s" +message(sprintf(versions_fmt, cargo_version, rustc_version)) diff --git a/ggsql-R/vignettes/.gitignore b/ggsql-R/vignettes/.gitignore new file mode 100644 index 00000000..097b2416 --- /dev/null +++ b/ggsql-R/vignettes/.gitignore @@ -0,0 +1,2 @@ +*.html +*.R diff --git a/ggsql-R/vignettes/engine.qmd b/ggsql-R/vignettes/engine.qmd new file mode 100644 index 00000000..1d6e5f0d --- /dev/null +++ b/ggsql-R/vignettes/engine.qmd @@ -0,0 +1,20 @@ +--- +title: "The ggsql knitr engine" +knitr: + opts_chunk: + collapse: true + comment: "#>" +description: | + An introduction to using the ggsql knitr engine in Rmarkdown and + Quarto +vignette: > + %\VignetteIndexEntry{The ggsql knitr engine} + %\VignetteEngine{quarto::html} + %\VignetteEncoding{UTF-8} +--- + +```{r setup} +library(ggsql) +``` + +The main selling point of the ggsql R package is arguably it's knitr engine that allows you to add `{ggsql}` blocks to your Rmarkdown and Quarto documents. While ggsql also provides a Jupyter kernel that Quarto can use, Jupyter only allows a single kernel at a time, so if you wish to mix R and/or Python blocks with ggsql visualizations, then the ggsql knitr engine is the way. diff --git a/ggsql-R/vignettes/ggsql.qmd b/ggsql-R/vignettes/ggsql.qmd new file mode 100644 index 00000000..adc62bce --- /dev/null +++ b/ggsql-R/vignettes/ggsql.qmd @@ -0,0 +1,116 @@ +--- +title: "Getting started" +knitr: + opts_chunk: + collapse: true + comment: "#>" +description: | + A short introduction to interacting with ggsql from R +vignette: > + %\VignetteIndexEntry{Getting started} + %\VignetteEngine{quarto::html} + %\VignetteEncoding{UTF-8} +--- + +```{r setup} +library(ggsql) +``` + +The ggsql package is an R binding to the [ggsql visualization library](https://ggsql.org). It allows you to set up readers to interact with different data backends, execute queries, and define writers to handle rendering. + +In addition to this it also provide a knitr engine so that you can write ggsql blocks in your Rmarkdown and Quarto documents. This part of the package has it's own vignette so head there if that is your main interest. + +## Package anatomy +The ggsql R package follows the same division as the main library which is split into a reader, plot, and writer module. You start by creating a reader which interacts with your data backend. You then execute queries against this reader (effectively using the plot module). Lastly, you can render the result using a writer you define. + +### Creating a reader +ggsql understands multiple backends, but in this vignette we focus on the DuckDB reader since it is both powerful and doesn't require any additional setup. You create a DuckDB reader using the aptly named `duckdb_reader()` function: + +```{r} +ddb <- duckdb_reader() +``` + +By default it creates a connection to an in-memory database, but you can point it at a database file to connect to that instead: + +```{r} +#| eval: false +ddb2 <- duckdb_reader("my/amazing/data.db") +``` + +While a reader is mainly in service of executing queries against, you can do something else with it as well, e.g. register data to it that will be available to queries on equal footing with any "real" tables in the database: + +```{r} +ggsql_register(ddb, gapminder::gapminder, "gapminder") +``` + +We can see all the tables currently available with: + +```{r} +ggsql_table_names(ddb) +``` + +And if we wanted to we could fetch the data back using `ggsql_table()` (works for both registered and native tables and views), or unregister it using `ggsql_unregister()` (only for registered tables) + +### Executing a query +As mentioned, the main purpose of a reader is to be the backend on which a ggsql query are executed. While it is possible to execute pure SQL queries and get back a data.frame: + +```{r} +ggsql_execute_sql(ddb, " +SELECT MAX(pop) AS population, country FROM gapminder +GROUP BY country +ORDER BY population DESC +LIMIT 6 +") +``` + +The main motivation is of course to create visualizations. This vignette will not go into detail with the ggsql syntax. For that, head to the [documentation on the website](https://ggsql.org/syntax/). If you are familiar with ggplot2 you should be able to understand the gist of it. + +```{r} +plot <- ggsql_execute(ddb, " +SELECT * FROM gapminder +WHERE year = 2007 + +VISUALIZE gdpPercap AS x, lifeExp AS y, continent AS stroke, pop AS size +DRAW point + SETTING fill => null +SCALE size TO [2, 15] +") + +str(plot) +``` + +As you can see, executing a visual query does not in itself produce a plot, but +creates a data structure that contains the information necessary to render it. The analogue is the ggplot object you create when using ggplot2. + +You can use this object for introspection, e.g. get the visual part of the query: + +```{r} +ggsql_visual(plot) +``` + +### Rendering a plot +Finally we arrive at what we was here for all along: How to get a plot out of it. ggsql works with the concept of writers which are somewhat analogous to graphics devices in R. They are responsible for figuring out a visual representation of the abstract encoding in the plot specification. For the moment ggsql only comes with a vegalite writer so this is also the only one available in the R package: + +```{r} +vlr <- vegalite_writer() +``` + +Often you don't have to think about this at all since printing the result of a query automatically creates a writer and renders it so that it behaves in the same way as ggplot object: + +```{r} +plot +``` + +However, if you are interested in capturing what the writer produces you can call `ggsql_render()` explicitly: + +```{r} +ggsql_render(vlr, plot) +``` + +We might also be interested in capturing the plot as a static image. We can use the `ggsql_save()` function for that which can save the output to either a vegalite json object (like the one above), an SVG or a PNG. For the latter two the plot is rendered using the V8 package and the final image captured. + +```{r} +tmp <- tempfile(fileext = ".svg") +ggsql_save(plot, tmp) +readLines(tmp) +``` diff --git a/ggsql-jupyter/src/display.rs b/ggsql-jupyter/src/display.rs index 2683aea1..8de08818 100644 --- a/ggsql-jupyter/src/display.rs +++ b/ggsql-jupyter/src/display.rs @@ -73,79 +73,83 @@ fn format_vegalite(spec: String) -> Value { let vis_id = format!("vis-{}", timestamp); let html = format!( - r#"
- + r#"
+
+
"#, - vis_id, spec_json, vis_id + vis_id = vis_id, + spec_json = spec_json ); json!({ diff --git a/src/Cargo.toml b/src/Cargo.toml index c24259cc..834cad8c 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -26,7 +26,12 @@ csscolorparser.workspace = true palette.workspace = true # Data processing -polars = { workspace = true, features = ["lazy", "sql"] } +polars = { workspace = true, features = [ + "lazy", + "cum_agg", + "dtype-full", + "timezones", +] } polars-ops.workspace = true # Readers diff --git a/src/writer/vegalite/encoding.rs b/src/writer/vegalite/encoding.rs index 3f690233..52a7ede8 100644 --- a/src/writer/vegalite/encoding.rs +++ b/src/writer/vegalite/encoding.rs @@ -237,14 +237,11 @@ pub(super) fn infer_field_type(df: &DataFrame, field: &str) -> String { "quantitative" } Boolean => "nominal", - String => { + String // Check if string column contains numeric values - if is_numeric_string_column(column.as_materialized_series()) { + if is_numeric_string_column(column.as_materialized_series()) => { "quantitative" - } else { - "nominal" } - } Date | Datetime(_, _) | Time => "temporal", _ => "nominal", } diff --git a/src/writer/vegalite/layer.rs b/src/writer/vegalite/layer.rs index a8e60475..1165edb1 100644 --- a/src/writer/vegalite/layer.rs +++ b/src/writer/vegalite/layer.rs @@ -1726,12 +1726,13 @@ impl GeomRenderer for ViolinRenderer { if let Some(cat_field) = categorical_field { match encoding.get_mut("detail") { - Some(detail) if detail.is_object() => { + Some(detail) + if detail.is_object() // Single field object - check if it's already the categorical field, otherwise convert to array - if detail.get("field").and_then(|f| f.as_str()) != Some(&cat_field) { - let existing = detail.clone(); - *detail = json!([existing, {"field": cat_field, "type": "nominal"}]); - } + && detail.get("field").and_then(|f| f.as_str()) != Some(&cat_field) => + { + let existing = detail.clone(); + *detail = json!([existing, {"field": cat_field, "type": "nominal"}]); } Some(detail) if detail.is_array() => { // Array - check if categorical field already present, add if not diff --git a/tree-sitter-ggsql/grammar.js b/tree-sitter-ggsql/grammar.js index b1677b03..d5c8e241 100644 --- a/tree-sitter-ggsql/grammar.js +++ b/tree-sitter-ggsql/grammar.js @@ -282,7 +282,11 @@ module.exports = grammar({ caseInsensitive('ROW'), caseInsensitive('NULLS'), caseInsensitive('FIRST'), - caseInsensitive('LAST') + caseInsensitive('LAST'), + caseInsensitive('QUALIFY'), + caseInsensitive('UNION'), + caseInsensitive('INTERSECT'), + caseInsensitive('EXCEPT') ), // Window function: func() OVER (PARTITION BY ... ORDER BY ... frame)