Repository: prql/prql
Pull request #865 (2022-07-26 23:03:37)

reorganize top-level functions


Patch:
diff --git a/prql-compiler/src/ast/mod.rs b/prql-compiler/src/ast/mod.rs
index 5229776e..f2e4acf1 100644
--- a/prql-compiler/src/ast/mod.rs
+++ b/prql-compiler/src/ast/mod.rs
@@ -19,10 +19,6 @@ use serde::{Deserialize, Serialize};
 
 use crate::error::{Error, Reason, Span};
 
-pub fn display(query: Query) -> String {
-    format!("{}", Item::Query(query))
-}
-
 /// A name. Generally columns, tables, functions, variables.
 pub type Ident = String;
 
diff --git a/prql-compiler/src/cli.rs b/prql-compiler/src/cli.rs
index f51044c7..ee6c3198 100644
--- a/prql-compiler/src/cli.rs
+++ b/prql-compiler/src/cli.rs
@@ -9,11 +9,11 @@ use std::{
 };
 
 use crate::parse;
+use crate::semantic;
 use crate::{
     error::{self, Span},
     semantic::{Context, Frame},
 };
-use crate::{semantic, sql::load_std_lib};
 
 #[derive(Parser)]
 #[clap(name = env!("CARGO_PKG_NAME"), about, version)]
@@ -30,6 +30,9 @@ pub enum Cli {
 
     Debug(CommandIO),
 
+    /// Produces intermediate representation of the query
+    Resolve(CommandIO),
+
     /// Transpiles to SQL
     Compile(CommandIO),
 }
@@ -76,7 +79,7 @@ impl Cli {
             Cli::Format(_) => crate::format(source)?.as_bytes().to_vec(),
             Cli::Debug(_) => {
                 let query = parse(source)?;
-                let (nodes, context) = semantic::resolve_names(query.nodes, None)?;
+                let (nodes, context) = semantic::resolve(query.nodes, None)?;
 
                 semantic::label_references(&nodes, &context, "".to_string(), source.to_string());
 
@@ -86,9 +89,7 @@ impl Cli {
                 let query = parse(source)?;
 
                 // resolve
-                let std_lib = load_std_lib()?;
-                let (_, context) = semantic::resolve_names(std_lib, None)?;
-                let (nodes, context) = semantic::resolve_names(query.nodes, Some(context))?;
+                let (nodes, context) = semantic::resolve(query.nodes, None)?;
 
                 let frames = semantic::collect_frames(nodes);
 
@@ -97,6 +98,12 @@ impl Cli {
                     .as_bytes()
                     .to_vec()
             }
+            Cli::Resolve(_) => {
+                let ast = parse(source)?;
+                let (ir, _) = semantic::resolve(ast.nodes, None)?;
+
+                serde_yaml::to_vec(&ir)?
+            }
             Cli::Compile(_) => crate::compile(source)?.as_bytes().to_vec(),
         })
     }
@@ -104,7 +111,7 @@ impl Cli {
     fn read_input(&mut self) -> Result<(String, String)> {
         use Cli::*;
         match self {
-            Parse(io) | Format(io) | Debug(io) | Annotate(io) | Compile(io) => {
+            Parse(io) | Format(io) | Debug(io) | Annotate(io) | Resolve(io) | Compile(io) => {
                 // Don't wait without a prompt when running `prql-compiler compile` —
                 // it's confusing whether it's waiting for input or not. This
                 // offers the prompt.
@@ -124,7 +131,7 @@ impl Cli {
     fn write_output(&mut self, data: &[u8]) -> std::io::Result<()> {
         use Cli::*;
         match self {
-            Parse(io) | Format(io) | Debug(io) | Annotate(io) | Compile(io) => {
+            Parse(io) | Format(io) | Debug(io) | Annotate(io) | Resolve(io) | Compile(io) => {
                 io.output.write_all(data)
             }
         }
diff --git a/prql-compiler/src/error.rs b/prql-compiler/src/error.rs
index 4782b56f..051bc4c1 100644
--- a/prql-compiler/src/error.rs
+++ b/prql-compiler/src/error.rs
@@ -174,7 +174,7 @@ impl Reason {
                 expected,
                 found,
             } => {
-                let who = who.clone().map(|x| format!("`{x}` ")).unwrap_or_default();
+                let who = who.clone().map(|x| format!("{x} ")).unwrap_or_default();
                 format!("{who}expected {expected}, but found {found}")
             }
             Reason::Unexpected { found } => format!("unexpected {found}"),
diff --git a/prql-compiler/src/lib.rs b/prql-compiler/src/lib.rs
index 67924502..a9f179e4 100644
--- a/prql-compiler/src/lib.rs
+++ b/prql-compiler/src/lib.rs
@@ -3,18 +3,17 @@ pub mod ast;
 mod cli;
 mod error;
 mod parser;
-mod semantic;
+pub mod semantic;
 mod sql;
 mod utils;
 
 pub use anyhow::Result;
-pub use ast::display;
 #[cfg(feature = "cli")]
 pub use cli::Cli;
 pub use error::{format_error, SourceLocation};
 pub use parser::parse;
-pub use semantic::*;
-pub use sql::{resolve_and_translate, translate};
+pub use semantic::resolve;
+pub use sql::translate;
 
 /// Compile a PRQL string into a SQL string.
 ///
@@ -26,13 +25,15 @@ pub fn compile(prql: &str) -> Result<String> {
     parse(prql).and_then(resolve_and_translate)
 }
 
-/// Format an PRQL query
-///
-/// This has two stages:
-/// - [parse] — Build an AST from a PRQL query string.
-/// - [display] — Write a AST back to string.
+pub fn resolve_and_translate(mut query: ast::Query) -> Result<String> {
+    let (nodes, context) = semantic::resolve(query.nodes, None)?;
+    query.nodes = nodes;
+    translate(query, context)
+}
+
+/// Format a PRQL query
 pub fn format(prql: &str) -> Result<String> {
-    parse(prql).map(display)
+    parse(prql).map(|q| format!("{}", ast::Item::Query(q)))
 }
 
 /// Compile a PRQL string into a JSON version of the Query.
@@ -42,7 +43,8 @@ pub fn to_json(prql: &str) -> Result<String> {
 
 /// Convert JSON AST back to PRQL string
 pub fn from_json(json: &str) -> Result<String> {
-    Ok(display(serde_json::from_str(json)?))
+    let query = serde_json::from_str(json)?;
+    Ok(format!("{}", ast::Item::Query(query)))
 }
 
 #[cfg(test)]
diff --git a/prql-compiler/src/semantic/frame.rs b/prql-compiler/src/semantic/frame.rs
index a52d18d7..41ea2363 100644
--- a/prql-compiler/src/semantic/frame.rs
+++ b/prql-compiler/src/semantic/frame.rs
@@ -25,7 +25,7 @@ pub enum FrameColumn {
 }
 
 impl Frame {
-    fn push_column(&mut self, name: Option<String>, id: usize) {
+    pub fn push_column(&mut self, name: Option<String>, id: usize) {
         // remove columns with the same name
         if let Some(name) = &name {
             self.columns.retain(|c| match c {
@@ -134,7 +134,9 @@ impl Frame {
                         self.push_column(Some(name.clone()), id);
                     }
                 }
-                _ => unreachable!("assign must contain only idents after being resolved"),
+                item => unreachable!(
+                    "assign must contain only idents after being resolved, but got `{item}`",
+                ),
             }
         }
     }
diff --git a/prql-compiler/src/semantic/mod.rs b/prql-compiler/src/semantic/mod.rs
index 83564c97..d2bcfa11 100644
--- a/prql-compiler/src/semantic/mod.rs
+++ b/prql-compiler/src/semantic/mod.rs
@@ -7,9 +7,29 @@ mod reporting;
 mod scope;
 mod transforms;
 
+use crate::ast::Node;
+
 pub use self::context::Context;
 pub use self::declarations::{Declaration, Declarations};
 pub use self::frame::{Frame, FrameColumn};
 pub use self::scope::{split_var_name, Scope};
-pub use name_resolver::resolve_names;
 pub use reporting::{collect_frames, label_references};
+
+/// Runs semantic analysis on the query, using current state.
+///
+/// Note that this removes function declarations from AST and saves them as current context.
+pub fn resolve(nodes: Vec<Node>, context: Option<Context>) -> anyhow::Result<(Vec<Node>, Context)> {
+    let context = context.unwrap_or_else(load_std_lib);
+
+    let (nodes, context) = name_resolver::resolve_names(nodes, context)?;
+    Ok((nodes, context))
+}
+
+pub fn load_std_lib() -> Context {
+    use crate::parse;
+    let std_lib = include_str!("./stdlib.prql");
+    let nodes = parse(std_lib).unwrap().nodes;
+
+    let (_, context) = name_resolver::resolve_names(nodes, Context::default()).unwrap();
+    context
+}
diff --git a/prql-compiler/src/semantic/name_resolver.rs b/prql-compiler/src/semantic/name_resolver.rs
index 9584438b..13d68040 100644
--- a/prql-compiler/src/semantic/name_resolver.rs
+++ b/prql-compiler/src/semantic/name_resolver.rs
@@ -4,20 +4,18 @@ use anyhow::{bail, Result};
 use itertools::Itertools;
 
 use crate::ast::ast_fold::*;
+use crate::ast::*;
 use crate::error::{Error, Reason, Span, WithErrorInfo};
-use crate::{ast::*, split_var_name, Declaration};
 
 use super::complexity::determine_complexity;
 use super::frame::extract_sorts;
 use super::transforms;
-use super::Context;
+use super::{split_var_name, Context, Declaration};
 
 /// Runs semantic analysis on the query, using current state.
 ///
 /// Note that this removes function declarations from AST and saves them as current context.
-pub fn resolve_names(nodes: Vec<Node>, context: Option<Context>) -> Result<(Vec<Node>, Context)> {
-    let context = context.unwrap_or_else(init_context);
-
+pub fn resolve_names(nodes: Vec<Node>, context: Context) -> Result<(Vec<Node>, Context)> {
     let mut resolver = NameResolver::new(context);
 
     let nodes = resolver.fold_nodes(nodes)?;
@@ -574,28 +572,19 @@ impl NameResolver {
     }
 }
 
-/// Loads `internal.prql` which contains type definitions of transforms
-pub fn init_context() -> Context {
-    use crate::parse;
-    let transforms = include_str!("./transforms.prql");
-    let transforms = parse(transforms).unwrap().nodes;
-
-    let (_, context) = resolve_names(transforms, Some(Context::default())).unwrap();
-    context
-}
-
 #[cfg(test)]
 mod tests {
     use insta::assert_snapshot;
     use serde_yaml::from_str;
 
+    use crate::semantic::load_std_lib;
     use crate::{parse, resolve_and_translate};
 
     use super::*;
 
     #[test]
     fn test_scopes_during_from() {
-        let context = init_context();
+        let context = load_std_lib();
 
         let mut resolver = NameResolver::new(context);
 
@@ -618,7 +607,7 @@ mod tests {
 
     #[test]
     fn test_scopes_during_select() {
-        let context = init_context();
+        let context = load_std_lib();
 
         let mut resolver = NameResolver::new(context);
 
@@ -663,12 +652,14 @@ mod tests {
 
     #[test]
     fn test_variable_scoping() {
+        let context = load_std_lib();
+
         let prql = r#"
         from employees
         select first_name
         select last_name
         "#;
-        let result = parse(prql).and_then(|x| resolve_names(x.nodes, None));
+        let result = parse(prql).and_then(|x| resolve_names(x.nodes, context));
         assert!(result.is_err());
 
         let prql = r#"
@@ -688,22 +679,25 @@ mod tests {
 
     #[test]
     fn test_join_using_two_tables() {
+        let context = load_std_lib();
+
         let prql = r#"
         from employees
         select [first_name, emp_no]
         join salaries [emp_no]
         select [first_name, salaries.salary]
         "#;
-        let result = parse(prql).and_then(|x| resolve_names(x.nodes, None));
+        let result = parse(prql).and_then(|x| resolve_names(x.nodes, context));
         result.unwrap();
 
+        let context = load_std_lib();
         let prql = r#"
         from employees
         select first_name
         join salaries [emp_no]
         select [first_name, salaries.salary]
         "#;
-        let result = parse(prql).and_then(|x| resolve_names(x.nodes, None));
+        let result = parse(prql).and_then(|x| resolve_names(x.nodes, context));
         assert!(result.is_err());
     }
 
diff --git a/prql-compiler/src/sql/stdlib.prql b/prql-compiler/src/semantic/stdlib.prql
similarity index 71%
rename from prql-compiler/src/sql/stdlib.prql
rename to prql-compiler/src/semantic/stdlib.prql
index 2dd92a2d..23b70e50 100644
--- a/prql-compiler/src/sql/stdlib.prql
+++ b/prql-compiler/src/semantic/stdlib.prql
@@ -1,3 +1,18 @@
+# Transform type definitions
+
+# make sure to update cast_transfrom if you change any of the declarations here
+
+func from<table> source -> 0
+func select<table> assigns tbl -> 0
+func filter<table> condition tbl -> 0
+func derive<table> assigns tbl -> 0
+func aggregate<table> assigns tbl -> 0
+func sort<table> by tbl -> 0
+func take<table> expr tbl -> 0
+func join<table> with filter side:inner tbl -> 0
+func group<table> by pipeline tbl -> 0
+func window<table> rows:0..0 range:0..0 expanding:false rolling:0 pipeline tbl -> 0
+
 # Aggregate Functions
 
 func min <scalar|column> column ->  s"MIN({column})"
@@ -15,7 +30,7 @@ func count_distinct <scalar|column> column ->  s"COUNT(DISTINCT `{column}`)"
 # TODO: Introduce a notation for getting start and end out of a ranges
 # could be range.0? or range.start? But to make this happen, we need to make
 # changes to how variables are resolved.
-func in<scalar> range value ->  s"{value} BETWEEN {range}"
+func in<bool> range value ->  s"{value} BETWEEN {range}"
 
 # Casting functions
 
diff --git a/prql-compiler/src/semantic/transforms.prql b/prql-compiler/src/semantic/transforms.prql
deleted file mode 100644
index 38a6324e..00000000
--- a/prql-compiler/src/semantic/transforms.prql
+++ /dev/null
@@ -1,12 +0,0 @@
-# Transform type definitions
-
-func from<table> with -> 0
-func select<table> assigns frame -> 0
-func filter<table> conditions frame -> 0
-func derive<table> assigns frame -> 0
-func aggregate<table> assigns frame -> 0
-func sort<table> by frame -> 0
-func take<table> expr frame -> 0
-func join<table> with filter side:inner frame -> 0
-func group<table> by pipeline frame -> 0
-func window<table> rows:0..0 range:0..0 expanding:false rolling:0 pipeline frame -> 0
diff --git a/prql-compiler/src/semantic/transforms.rs b/prql-compiler/src/semantic/transforms.rs
index bd54c8a0..0b760b51 100644
--- a/prql-compiler/src/semantic/transforms.rs
+++ b/prql-compiler/src/semantic/transforms.rs
@@ -278,23 +278,20 @@ mod tests {
     use insta::assert_yaml_snapshot;
 
     use crate::parse;
-    use crate::semantic::resolve_names;
-    use crate::sql::load_std_lib;
+    use crate::semantic::{load_std_lib, resolve};
 
     #[test]
     fn test_simple_casts() {
         let query = parse(r#"filter upper country = "USA""#).unwrap();
-        assert!(resolve_names(query.nodes, None).is_err());
+        assert!(resolve(query.nodes, None).is_err());
 
         let query = parse(r#"take"#).unwrap();
-        assert!(resolve_names(query.nodes, None).is_err());
+        assert!(resolve(query.nodes, None).is_err());
     }
 
     #[test]
     fn test_aggregate_positional_arg() {
-        let stdlib = load_std_lib().unwrap();
-        let (_, context) = resolve_names(stdlib, None).unwrap();
-        let context = Some(context);
+        let context = Some(load_std_lib());
 
         // distinct query #292
         let query = parse(
@@ -307,7 +304,7 @@ mod tests {
         ",
         )
         .unwrap();
-        let (result, _) = resolve_names(query.nodes, context.clone()).unwrap();
+        let (result, _) = resolve(query.nodes, context.clone()).unwrap();
         assert_yaml_snapshot!(result, @r###"
         ---
         - Pipeline:
@@ -347,7 +344,7 @@ mod tests {
         ",
         )
         .unwrap();
-        let result = resolve_names(query.nodes, context.clone());
+        let result = resolve(query.nodes, context.clone());
         assert!(result.is_err());
 
         // oops, two arguments
@@ -358,7 +355,7 @@ mod tests {
         ",
         )
         .unwrap();
-        let result = resolve_names(query.nodes, context.clone());
+        let result = resolve(query.nodes, context.clone());
         assert!(result.is_err());
 
         // correct function call
@@ -371,7 +368,7 @@ mod tests {
         ",
         )
         .unwrap();
-        let (result, _) = resolve_names(query.nodes, context).unwrap();
+        let (result, _) = resolve(query.nodes, context).unwrap();
         assert_yaml_snapshot!(result, @r###"
         ---
         - Pipeline:
@@ -399,9 +396,7 @@ mod tests {
 
     #[test]
     fn test_transform_sort() {
-        let stdlib = load_std_lib().unwrap();
-        let (_, context) = resolve_names(stdlib, None).unwrap();
-        let context = Some(context);
+        let context = Some(load_std_lib());
 
         let query = parse(
             "
@@ -415,7 +410,7 @@ mod tests {
         )
         .unwrap();
 
-        let (result, _) = resolve_names(query.nodes, context).unwrap();
+        let (result, _) = resolve(query.nodes, context).unwrap();
         assert_yaml_snapshot!(result, @r###"
         ---
         - Pipeline:
diff --git a/prql-compiler/src/sql/distinct.rs b/prql-compiler/src/sql/distinct.rs
index 5f78334a..ff5b1d33 100644
--- a/prql-compiler/src/sql/distinct.rs
+++ b/prql-compiler/src/sql/distinct.rs
@@ -1,7 +1,7 @@
 use anyhow::Result;
 
 use crate::ast::{ast_fold::AstFold, *};
-use crate::Declaration;
+use crate::semantic::Declaration;
 
 use super::materializer::MaterializationContext;
 
diff --git a/prql-compiler/src/sql/materializer.rs b/prql-compiler/src/sql/materializer.rs
index e453457f..fb06e57b 100644
--- a/prql-compiler/src/sql/materializer.rs
+++ b/prql-compiler/src/sql/materializer.rs
@@ -3,10 +3,7 @@
 //! contains no query-specific logic.
 use crate::ast::ast_fold::*;
 use crate::ast::*;
-use crate::semantic;
-use crate::Declaration;
-use crate::Declarations;
-use crate::Frame;
+use crate::semantic::{Context, Declaration, Declarations, Frame};
 
 use anyhow::{anyhow, Result};
 use itertools::zip;
@@ -80,8 +77,8 @@ impl MaterializationContext {
     }
 }
 
-impl From<semantic::Context> for MaterializationContext {
-    fn from(context: semantic::Context) -> Self {
+impl From<Context> for MaterializationContext {
+    fn from(context: Context) -> Self {
         MaterializationContext {
             frame: Frame::default(),
             declarations: context.declarations,
@@ -326,7 +323,7 @@ impl std::fmt::Debug for MaterializationContext {
 mod test {
 
     use super::*;
-    use crate::{parse, semantic::resolve_names, utils::diff};
+    use crate::{parse, resolve, utils::diff};
     use insta::{assert_display_snapshot, assert_snapshot, assert_yaml_snapshot};
     use serde_yaml::to_string;
 
@@ -335,7 +332,7 @@ mod test {
     }
 
     fn resolve_and_materialize(query: Query) -> Result<Vec<Node>> {
-        let (res, context) = resolve_names(query.nodes, None)?;
+        let (res, context) = resolve(query.nodes, None)?;
 
         let pipeline = find_pipeline(res);
 
@@ -354,7 +351,7 @@ mod test {
     "#,
         )?;
 
-        let (res, context) = resolve_names(query.nodes, None)?;
+        let (res, context) = resolve(query.nodes, None)?;
 
         let pipeline = find_pipeline(res);
 
@@ -370,7 +367,7 @@ mod test {
         @@ -5,7 +5,3 @@
                  name: employees
                  alias: ~
-                 declared_at: 36
+                 declared_at: 79
         -  - Transform:
         -      Derive:
         -        - Ident: gross_salary
@@ -384,10 +381,6 @@ mod test {
     fn test_replace_variables_2() -> Result<()> {
         let query = parse(
             r#"
-func count ->  s"COUNT(*)"
-func average column ->  s"AVG({column})"
-func sum column ->  s"SUM({column})"
-
 from employees
 filter country == "USA"                           # Each line transforms the previous result.
 derive [                                         # This adds columns / variables.
@@ -421,7 +414,7 @@ take 20
     #[test]
     fn test_non_existent_function() -> Result<()> {
         let query = parse(r#"from mytable | filter (myfunc col1)"#)?;
-        assert!(resolve_names(query.nodes, None).is_err());
+        assert!(resolve(query.nodes, None).is_err());
 
         Ok(())
     }
@@ -430,30 +423,15 @@ take 20
     fn test_run_functions_args() -> Result<()> {
         let query = parse(
             r#"
-        func count x ->  s"count({x})"
-
         from employees
         aggregate [
-        count salary
+            sum salary
         ]
         "#,
         )?;
 
         assert_yaml_snapshot!(query.nodes, @r###"
         ---
-        - FuncDef:
-            name: count
-            positional_params:
-              - - Ident: x
-                - ~
-            named_params: []
-            body:
-              SString:
-                - String: count(
-                - Expr:
-                    Ident: x
-                - String: )
-            return_type: ~
         - Pipeline:
             nodes:
               - FuncCall:
@@ -466,14 +444,14 @@ take 20
                   args:
                     - List:
                         - FuncCall:
-                            name: count
+                            name: sum
                             args:
                               - Ident: salary
                             named_args: {}
                   named_args: {}
         "###);
 
-        let (res, context) = resolve_names(query.nodes, None)?;
+        let (res, context) = resolve(query.nodes, None)?;
 
         let pipeline = find_pipeline(res);
 
@@ -490,7 +468,7 @@ take 20
                assigns:
         -        - Ident: "<unnamed>"
         +        - SString:
-        +            - String: count(
+        +            - String: SUM(
         +            - Expr:
         +                Ident: salary
         +            - String: )
@@ -540,7 +518,7 @@ take 20
             From:
               name: a
               alias: ~
-              declared_at: 41
+              declared_at: 84
         "###);
 
         Ok(())
@@ -550,14 +528,12 @@ take 20
     fn test_run_inline_pipelines() -> Result<()> {
         let query = parse(
             r#"
-        func sum x ->  s"SUM({x})"
-
         from a
         aggregate [one = (foo | sum), two = (foo | sum)]
         "#,
         )?;
 
-        let (res, context) = resolve_names(query.nodes, None)?;
+        let (res, context) = resolve(query.nodes, None)?;
 
         let pipeline = find_pipeline(res);
 
@@ -586,7 +562,6 @@ take 20
         // Test it'll run the `sum foo` function first.
         let query = parse(
             r#"
-        func sum x ->  s"SUM({x})"
         func plus_one x ->  x + 1
 
         from a
@@ -602,7 +577,7 @@ take 20
             From:
               name: a
               alias: ~
-              declared_at: 40
+              declared_at: 81
         - Transform:
             Aggregate:
               assigns:
@@ -644,7 +619,7 @@ take 20
             From:
               name: foo_table
               alias: ~
-              declared_at: 39
+              declared_at: 82
         "###);
 
         Ok(())
@@ -654,11 +629,9 @@ take 20
     fn test_materialize_1() -> Result<()> {
         let query = parse(
             r#"
-        func count x ->  s"count({x})"
-
         from employees
         aggregate [
-            count salary
+            sum salary
         ]
         "#,
         )?;
@@ -671,12 +644,12 @@ take 20
             From:
               name: employees
               alias: ~
-              declared_at: 38
+              declared_at: 79
         - Transform:
             Aggregate:
               assigns:
                 - SString:
-                    - String: count(
+                    - String: SUM(
                     - Expr:
                         Ident: salary
                     - String: )
@@ -690,10 +663,6 @@ take 20
     fn test_materialize_2() -> Result<()> {
         let query = parse(
             r#"
-func count ->  s"COUNT(*)"
-func average column ->  s"AVG({column})"
-func sum column ->  s"SUM({column})"
-
 from employees
 filter country == "USA"                           # Each line transforms the previous result.
 derive [                                         # This adds columns / variables.
@@ -761,8 +730,6 @@ take 20
     fn test_variable_after_aggregate() -> Result<()> {
         let query = parse(
             r#"
-        func average column ->  s"AVG({column})"
-
         from employees
         group [title, emp_no] (
             aggregate [emp_salary = average salary]
@@ -780,7 +747,7 @@ take 20
             From:
               name: employees
               alias: ~
-              declared_at: 38
+              declared_at: 79
         - Transform:
             Group:
               by:
@@ -843,8 +810,8 @@ take 20
         "#,
         )?;
 
-        let (res1, context) = resolve_names(query1.nodes, None)?;
-        let (res2, context) = resolve_names(query2.nodes, Some(context))?;
+        let (res1, context) = resolve(query1.nodes, None)?;
+        let (res2, context) = resolve(query2.nodes, Some(context))?;
 
         let (mat, frame, context) = materialize(find_pipeline(res1), context.into(), None)?;
 
@@ -854,7 +821,7 @@ take 20
             From:
               name: orders
               alias: ~
-              declared_at: 36
+              declared_at: 79
         - Transform:
             Take:
               range:
@@ -886,14 +853,14 @@ take 20
             From:
               name: table_1
               alias: ~
-              declared_at: 41
+              declared_at: 84
         - Transform:
             Join:
               side: Inner
               with:
                 name: customers
                 alias: ~
-                declared_at: 42
+                declared_at: 85
               filter:
                 Using:
                   - Ident: customer_no
diff --git a/prql-compiler/src/sql/mod.rs b/prql-compiler/src/sql/mod.rs
index 67a56a74..8f14dff0 100644
--- a/prql-compiler/src/sql/mod.rs
+++ b/prql-compiler/src/sql/mod.rs
@@ -5,25 +5,3 @@ mod un_group;
 
 pub use materializer::{materialize, MaterializedFrame};
 pub use translator::translate;
-
-use anyhow::Result;
-
-use crate::ast::{Node, Query};
-use crate::semantic;
-
-/// Resolve all variable and function calls using SQL stdlib and then translate AST into SQL.
-pub fn resolve_and_translate(mut query: Query) -> Result<String> {
-    let std_lib = load_std_lib()?;
-    let (_, context) = semantic::resolve_names(std_lib, None)?;
-
-    let (nodes, context) = semantic::resolve_names(query.nodes, Some(context))?;
-
-    query.nodes = nodes;
-    translate(query, context)
-}
-
-pub fn load_std_lib() -> Result<Vec<Node>> {
-    use crate::parse;
-    let std_lib = include_str!("./stdlib.prql");
-    Ok(parse(std_lib)?.nodes)
-}
diff --git a/prql-compiler/src/sql/translator.rs b/prql-compiler/src/sql/translator.rs
index 195d67f7..cf715693 100644
--- a/prql-compiler/src/sql/translator.rs
+++ b/prql-compiler/src/sql/translator.rs
@@ -887,7 +887,7 @@ impl From<Vec<Node>> for AtomicTable {
 #[cfg(test)]
 mod test {
     use super::*;
-    use crate::{parser::parse, resolve_and_translate, resolve_names, sql::load_std_lib};
+    use crate::{parser::parse, resolve, resolve_and_translate};
     use insta::{assert_display_snapshot, assert_snapshot, assert_yaml_snapshot};
     use serde_yaml::from_str;
 
@@ -1076,10 +1076,7 @@ mod test {
     }
 
     fn parse_and_resolve(prql: &str) -> Result<Pipeline> {
-        let std_lib = load_std_lib()?;
-        let (_, context) = resolve_names(std_lib, None)?;
-
-        let (mut nodes, _) = resolve_names(parse(prql)?.nodes, Some(context))?;
+        let (mut nodes, _) = resolve(parse(prql)?.nodes, None)?;
         let pipeline = nodes.remove(nodes.len() - 1).coerce_to_pipeline();
         Ok(pipeline)
     }


Test patch:
diff --git a/prql-compiler/src/sql/snapshots/prql_compiler__sql__materializer__test__materialize_2.snap b/prql-compiler/src/sql/snapshots/prql_compiler__sql__materializer__test__materialize_2.snap
index 4dc88e79..b2f66cfc 100644
--- a/prql-compiler/src/sql/snapshots/prql_compiler__sql__materializer__test__materialize_2.snap
+++ b/prql-compiler/src/sql/snapshots/prql_compiler__sql__materializer__test__materialize_2.snap
@@ -6,7 +6,7 @@ expression: mat
     From:
       name: employees
       alias: ~
-      declared_at: 41
+      declared_at: 79
 - Transform:
     Filter:
       Binary:
@@ -107,7 +107,11 @@ expression: mat
                                 Ident: benefits_cost
                         - String: )
                     - SString:
-                        - String: COUNT(*)
+                        - String: COUNT(
+                        - Expr:
+                            SString:
+                              - String: "*"
+                        - String: )
                   by:
                     - Ident: title
                     - Ident: country
diff --git a/prql-compiler/src/sql/snapshots/prql_compiler__sql__materializer__test__materialize_3.snap b/prql-compiler/src/sql/snapshots/prql_compiler__sql__materializer__test__materialize_3.snap
index d2a40ead..0eeda704 100644
--- a/prql-compiler/src/sql/snapshots/prql_compiler__sql__materializer__test__materialize_3.snap
+++ b/prql-compiler/src/sql/snapshots/prql_compiler__sql__materializer__test__materialize_3.snap
@@ -6,5 +6,5 @@ expression: mat
     From:
       name: prices
       alias: ~
-      declared_at: 46
+      declared_at: 89
 
diff --git a/prql-compiler/src/sql/snapshots/prql_compiler__sql__materializer__test__replace_variables_2.snap b/prql-compiler/src/sql/snapshots/prql_compiler__sql__materializer__test__replace_variables_2.snap
index a37dd3ed..89377db6 100644
--- a/prql-compiler/src/sql/snapshots/prql_compiler__sql__materializer__test__replace_variables_2.snap
+++ b/prql-compiler/src/sql/snapshots/prql_compiler__sql__materializer__test__replace_variables_2.snap
@@ -6,7 +6,7 @@ expression: "&mat"
     From:
       name: employees
       alias: ~
-      declared_at: 41
+      declared_at: 79
 - Transform:
     Filter:
       Binary:
@@ -107,7 +107,11 @@ expression: "&mat"
                                 Ident: benefits_cost
                         - String: )
                     - SString:
-                        - String: COUNT(*)
+                        - String: COUNT(
+                        - Expr:
+                            SString:
+                              - String: "*"
+                        - String: )
                   by:
                     - Ident: title
                     - Ident: country