Skip to content

Commit

Permalink
feat!: rewrite the prql_compile() function (#317)
Browse files Browse the repository at this point in the history
  • Loading branch information
eitsupi authored Sep 21, 2024
1 parent dde9f1b commit 0f2105f
Show file tree
Hide file tree
Showing 14 changed files with 152 additions and 113 deletions.
5 changes: 3 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ Suggests:
dplyr,
testthat (>= 3.2.0),
patrick,
withr
withr,
cli
License: MIT + file LICENSE
Language: en-US
Encoding: UTF-8
Expand All @@ -47,4 +48,4 @@ Config/Needs/dev:
rhub
Config/Needs/website:
pkgdown
Config/prqlr/LibVersion: 0.13.0
Config/prqlr/LibVersion: 0.13.1
8 changes: 8 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# prqlr (development version)

## Breaking changes

- For the `prql_compile()` funtion, arguments `format` and `singnature_comment` should be named arguments. (#317)

## New features

- New experimental argument `display` of `prql_compile()` function to colorize the error message from prqlc. (#317)

# prqlr 0.9.0

## Breaking changes
Expand Down
4 changes: 2 additions & 2 deletions R/000-wrappers.R
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ NULL
#' @param signature_comment a logical flag. Whether to add a signature comment to the output SQL query.
#' @return a list contains a SQL string or an error message.
#' @noRd
`compile` <- function(`prql_query`, `target`, `format`, `signature_comment`) {
.Call(savvy_compile__impl, `prql_query`, `target`, `format`, `signature_comment`)
`compile` <- function(`prql_query`, `target`, `format`, `signature_comment`, `display`) {
.Call(savvy_compile__impl, `prql_query`, `target`, `format`, `signature_comment`, `display`)
}

#' @noRd
Expand Down
28 changes: 19 additions & 9 deletions R/compile.R
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
#' @title Compile a PRQL query into a SQL query
#' @param prql_query a PRQL query string.
#' @param target a compile target name to use. If not specified (`NULL`),
#' the target contained in the query will be used.
#' All available target names can be listed with the [prql_get_targets] function.
#' @param format a logical flag (default: `TRUE`). Whether to format the SQL query.
#' @param prql_query A character of PRQL query.
#' @param target A character of the target name to use or `NULL`.
#' If `NULL`, the target contained in the query will be used.
#' All available target names can be listed with the [prql_get_targets()] function.
#' @param ... Ignored.
#' @param format A logical flag (default: `TRUE`). Whether to format the SQL query.
#' @param signature_comment a logical flag. (default: `TRUE`).
#' Whether to add a signature comment to the output SQL query.
#' @return a SQL query string
#' @seealso [prql_get_targets]
#' @param display A character, one of `"plain"` (default) or `"ansi_color"`.
#' If `"ansi_color"`, error will be displayed with ANSI color.
#' @return A character of the compiled SQL query.
#' @examples
#' "from mtcars | filter cyl > 6 | select {cyl, mpg}" |>
#' prql_compile()
Expand Down Expand Up @@ -38,9 +40,17 @@
prql_compile <- function(
prql_query,
target = getOption("prqlr.target", default = NULL),
...,
format = getOption("prqlr.format", default = TRUE),
signature_comment = getOption("prqlr.signature_comment", default = TRUE)) {
compile(prql_query, target %||% "sql.any", format, signature_comment)
signature_comment = getOption("prqlr.signature_comment", default = TRUE),
display = getOption("prqlr.display", default = "plain")) {
compile(
prql_query,
target = target %||% "sql.any",
format = format,
signature_comment = signature_comment,
display = display
)
}

#' @title prqlc's version
Expand Down
4 changes: 3 additions & 1 deletion R/knitr-engine.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# TODO: support the `error=TRUE` option and support `ansi_color`ed error message with the `cli` package.
#' @title PRQL knitr engine
#' @description
#' If options$connection is NULL, the output is SQL query.
Expand Down Expand Up @@ -27,7 +28,8 @@ eng_prql <- function(options) {
prql_compile(
target = options$engine.opts[["target"]] %||% getOption("prqlr.target"),
format = TRUE,
signature_comment = options$engine.opts[["signature_comment"]] %||% getOption("prqlr.signature_comment", TRUE)
signature_comment = options$engine.opts[["signature_comment"]] %||% getOption("prqlr.signature_comment", TRUE),
display = "plain"
)

# Prints a SQL code block if there is no connection
Expand Down
24 changes: 14 additions & 10 deletions man/prql_compile.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ SEXP handle_result(SEXP res_) {
return (SEXP)res;
}

SEXP savvy_compile__impl(SEXP c_arg__prql_query, SEXP c_arg__target, SEXP c_arg__format, SEXP c_arg__signature_comment) {
SEXP res = savvy_compile__ffi(c_arg__prql_query, c_arg__target, c_arg__format, c_arg__signature_comment);
SEXP savvy_compile__impl(SEXP c_arg__prql_query, SEXP c_arg__target, SEXP c_arg__format, SEXP c_arg__signature_comment, SEXP c_arg__display) {
SEXP res = savvy_compile__ffi(c_arg__prql_query, c_arg__target, c_arg__format, c_arg__signature_comment, c_arg__display);
return handle_result(res);
}

Expand Down Expand Up @@ -66,7 +66,7 @@ SEXP savvy_prql_get_targets__impl(void) {


static const R_CallMethodDef CallEntries[] = {
{"savvy_compile__impl", (DL_FUNC) &savvy_compile__impl, 4},
{"savvy_compile__impl", (DL_FUNC) &savvy_compile__impl, 5},
{"savvy_prql_to_pl__impl", (DL_FUNC) &savvy_prql_to_pl__impl, 1},
{"savvy_pl_to_rq__impl", (DL_FUNC) &savvy_pl_to_rq__impl, 1},
{"savvy_rq_to_sql__impl", (DL_FUNC) &savvy_rq_to_sql__impl, 1},
Expand Down
3 changes: 1 addition & 2 deletions src/rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions src/rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "prqlr"
version = "0.13.0"
version = "0.13.1"
edition = "2021"
rust-version = "1.69"
publish = false
Expand All @@ -15,4 +15,3 @@ savvy = "0.6.8"
# prqlc 0.13.0 is not compatible with Rust 1.69.0, so a slightly modified version is installed
# See https://github.com/PRQL/prql/pull/4916
prqlc = { git = "https://github.com/PRQL/prql", rev = "c7bd7a6fc73040394ffbbd85cea2ed6f986fd9dd", default-features = false }
anstream = { version = "0", features = ["auto"] }
2 changes: 1 addition & 1 deletion src/rust/api.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
SEXP savvy_compile__ffi(SEXP c_arg__prql_query, SEXP c_arg__target, SEXP c_arg__format, SEXP c_arg__signature_comment);
SEXP savvy_compile__ffi(SEXP c_arg__prql_query, SEXP c_arg__target, SEXP c_arg__format, SEXP c_arg__signature_comment, SEXP c_arg__display);
SEXP savvy_prql_to_pl__ffi(SEXP c_arg__prql_query);
SEXP savvy_pl_to_rq__ffi(SEXP c_arg__pl_json);
SEXP savvy_rq_to_sql__ffi(SEXP c_arg__rq_json);
Expand Down
89 changes: 38 additions & 51 deletions src/rust/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anstream::ColorChoice;
use savvy::{savvy, Sexp};
use prqlc::ErrorMessages;
use savvy::{savvy, Result, Sexp};
use std::str::FromStr;

/// @title Compile a PRQL query into a SQL query
Expand All @@ -15,96 +15,83 @@ pub fn compile(
target: &str,
format: bool,
signature_comment: bool,
) -> savvy::Result<Sexp> {
display: &str,
) -> Result<Sexp> {
let options = convert_options(CompileOptions {
format,
target: target.to_string(),
signature_comment,
});

let result = options
.and_then(|opts| {
Ok(prql_query)
.and_then(prqlc::prql_to_pl)
.and_then(prqlc::pl_to_rq)
.and_then(|rq| prqlc::rq_to_sql(rq, &opts))
})
.map_err(|e| e.composed(&prql_query.into()));

ColorChoice::write_global(self::ColorChoice::Never);
display: display.to_string(),
})
.map_err(|e| e.to_string())?;

match result {
Ok(msg) => msg.try_into(),
Err(e) => Err(e.to_string().into()),
}
prqlc::compile(prql_query, &options)
.map_err(|e| e.to_string().into())
.and_then(|x| x.try_into())
}

struct CompileOptions {
format: bool,
target: String,
signature_comment: bool,
display: String,
}

fn convert_options(
o: CompileOptions,
) -> core::result::Result<prqlc::Options, prqlc::ErrorMessages> {
let target = prqlc::Target::from_str(&o.target).map_err(prqlc::ErrorMessages::from)?;
fn convert_options(o: CompileOptions) -> core::result::Result<prqlc::Options, ErrorMessages> {
let target = prqlc::Target::from_str(&o.target).map_err(ErrorMessages::from)?;
let display = prqlc::DisplayOptions::from_str(&o.display).map_err(|_| ErrorMessages {
inner: vec![prqlc::Error::new_simple(format!(
"`display` must be one of `plain` or `ansi_color`. got: {}",
&o.display
))
.into()],
})?;

// TODO: support `display` option
Ok(prqlc::Options {
format: o.format,
target,
signature_comment: o.signature_comment,
color: false,
..std::default::Default::default()
display,
})
}

/// @noRd
#[savvy]
pub fn prql_to_pl(prql_query: &str) -> savvy::Result<Sexp> {
let result = Ok(prql_query)
pub fn prql_to_pl(prql_query: &str) -> Result<Sexp> {
Ok(prql_query)
.and_then(prqlc::prql_to_pl)
.and_then(|x| prqlc::json::from_pl(&x));

match result {
Ok(msg) => msg.try_into(),
Err(e) => Err(e.to_string().into()),
}
.and_then(|x| prqlc::json::from_pl(&x))
.map_err(|e| e.to_string().into())
.and_then(|x| x.try_into())
}

/// @noRd
#[savvy]
pub fn pl_to_rq(pl_json: &str) -> savvy::Result<Sexp> {
let result = Ok(pl_json)
pub fn pl_to_rq(pl_json: &str) -> Result<Sexp> {
Ok(pl_json)
.and_then(prqlc::json::to_pl)
.and_then(prqlc::pl_to_rq)
.and_then(|x| prqlc::json::from_rq(&x));

match result {
Ok(msg) => msg.try_into(),
Err(e) => Err(e.to_string().into()),
}
.and_then(|x| prqlc::json::from_rq(&x))
.map_err(|e| e.to_string().into())
.and_then(|x| x.try_into())
}

/// @noRd
#[savvy]
pub fn rq_to_sql(rq_json: &str) -> savvy::Result<Sexp> {
let result = Ok(rq_json)
pub fn rq_to_sql(rq_json: &str) -> Result<Sexp> {
Ok(rq_json)
.and_then(prqlc::json::to_rq)
.and_then(|x| prqlc::rq_to_sql(x, &prqlc::Options::default()));

match result {
Ok(msg) => msg.try_into(),
Err(e) => Err(e.to_string().into()),
}
.and_then(|x| prqlc::rq_to_sql(x, &prqlc::Options::default()))
.map_err(|e| e.to_string().into())
.and_then(|x| x.try_into())
}

/// @title prqlc's version
/// @return a prqlc's version string
/// @noRd
#[savvy]
pub fn compiler_version() -> savvy::Result<Sexp> {
pub fn compiler_version() -> Result<Sexp> {
prqlc::COMPILER_VERSION.to_string().try_into()
}

Expand All @@ -115,6 +102,6 @@ pub fn compiler_version() -> savvy::Result<Sexp> {
/// prql_get_targets()
/// @export
#[savvy]
pub fn prql_get_targets() -> savvy::Result<Sexp> {
pub fn prql_get_targets() -> Result<Sexp> {
prqlc::Target::names().try_into()
}
Loading

0 comments on commit 0f2105f

Please sign in to comment.