Skip to content

Commit

Permalink
TypeQL 3.0 (#342)
Browse files Browse the repository at this point in the history
## Usage and product changes

User-defined functions and structs:
```typeql
fun mean_salary($c: company) -> double? :
    match 
        (company: $c, employee: $_) isa employment, has salary $s;
    return mean($s); 
```
```typeql
struct dated_coordinate:
    longitude value double,
    latitude value double,
    date value datetime;
```

Query pipelines:
```
with fun costliest_printer($employee: employee) -> printer? :
  match 
    ($printer, $employee) isa print_permission;
    $printer has cost_per_page $cost;
  sort $cost desc;
  return first($printer);
match
  $printer isa printer, has office_number $n, has newly_installed true;
  $employee isa employee, has office_number $n;
put ($employee, $printer) isa print_permission;
match 
  $high_cost_printer = costliest_printer($employee), has printer_name $name;
  not { $printer is $high_cost_printer; };
  $employee has contact $address;
insert 
  $notice isa queued_email, has recipient $address, 
  has content "Do you still need the printer " + $name + "?";
```

New undefine syntax allows user to be more precise as to what is being
undefined:
```typeql
undefine
owns age from person;
@regex from first-name;
as name from person owns first-name;
```
New, more concise delete syntax:
```typeql
match $p isa person, has name $n;
delete $n of $p;
```

Implement JSON-like string unescaping (closes #106).

See [The TypeDB 3.0 Roadmap](<https://typedb.com/blog/typedb-3-roadmap>)
for more details!
  • Loading branch information
dmitrii-ubskii authored Jul 8, 2024
1 parent fc0a191 commit 4a279a8
Show file tree
Hide file tree
Showing 91 changed files with 8,457 additions and 4,170 deletions.
9 changes: 5 additions & 4 deletions dependencies/maven/artifacts.snapshot
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
@maven//:com_eclipsesource_minimal_json_minimal_json_0_9_5
@maven//:com_electronwill_night_config_core_3_6_5
@maven//:com_electronwill_night_config_toml_3_6_5
@maven//:com_fasterxml_jackson_core_jackson_annotations_2_10_1
@maven//:com_fasterxml_jackson_core_jackson_core_2_10_1
@maven//:com_fasterxml_jackson_core_jackson_databind_2_10_1
@maven//:com_fasterxml_jackson_core_jackson_annotations_2_16_0
@maven//:com_fasterxml_jackson_core_jackson_core_2_16_0
@maven//:com_fasterxml_jackson_core_jackson_databind_2_16_0
@maven//:com_google_code_findbugs_jsr305_3_0_2
@maven//:com_google_errorprone_error_prone_annotations_2_3_4
@maven//:com_google_guava_failureaccess_1_0_1
@maven//:com_google_guava_guava_30_1_jre
@maven//:com_google_guava_listenablefuture_9999_0_empty_to_avoid_conflict_with_guava
@maven//:com_google_http_client_google_http_client_1_34_2
@maven//:com_google_j2objc_j2objc_annotations_1_3
@maven//:com_vdurmont_semver4j_3_1_0
@maven//:commons_codec_commons_codec_1_13
@maven//:commons_io_commons_io_2_3
@maven//:commons_logging_commons_logging_1_2
Expand Down Expand Up @@ -42,5 +43,5 @@
@maven//:org_jsoup_jsoup_1_16_1
@maven//:org_kohsuke_github_api_1_101
@maven//:org_slf4j_slf4j_api_2_0_0
@maven//:org_yaml_snakeyaml_1_25
@maven//:org_yaml_snakeyaml_2_2
@maven//:org_zeroturnaround_zt_exec_1_10
4 changes: 2 additions & 2 deletions dependencies/vaticle/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
def vaticle_dependencies():
git_repository(
name = "vaticle_dependencies",
remote = "https://github.com/dmitrii-ubskii/vaticle-dependencies",
commit = "b13ccddfddcac1d56a029d98e3893f74b267c5ae", # sync-marker: do not remove this comment, this is used for sync-dependencies by @vaticle_dependencies
remote = "https://github.com/vaticle/dependencies",
commit = "78d937a49135453965ddd68c51de7f90b8aeba15", # sync-marker: do not remove this comment, this is used for sync-dependencies by @vaticle_dependencies
)

def vaticle_typedb_behaviour():
Expand Down
9 changes: 1 addition & 8 deletions rust/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,7 @@ checkstyle_test(
name = "checkstyle",
include = glob([
"*",
"builder/**",
"common/**",
"parser/**",
"pattern/**",
"query/**",
"tests/**",
"util/**",
"variable/**",
"*/**",
], exclude = [
"target/**",
"README.md",
Expand Down
257 changes: 257 additions & 0 deletions rust/annotation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use std::fmt::{self, Write};

use crate::{
common::{identifier::Identifier, token, Span},
util::write_joined,
value::Literal,
};

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Annotation {
Abstract(Abstract),
Cardinality(Cardinality),
Cascade(Cascade),
Distinct(Distinct),
Independent(Independent),
Key(Key),
Range(Range),
Regex(Regex),
Subkey(Subkey),
Unique(Unique),
Values(Values),
}

impl fmt::Display for Annotation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Abstract(inner) => fmt::Display::fmt(inner, f),
Self::Cardinality(inner) => fmt::Display::fmt(inner, f),
Self::Cascade(inner) => fmt::Display::fmt(inner, f),
Self::Distinct(inner) => fmt::Display::fmt(inner, f),
Self::Independent(inner) => fmt::Display::fmt(inner, f),
Self::Key(inner) => fmt::Display::fmt(inner, f),
Self::Range(inner) => fmt::Display::fmt(inner, f),
Self::Regex(inner) => fmt::Display::fmt(inner, f),
Self::Subkey(inner) => fmt::Display::fmt(inner, f),
Self::Unique(inner) => fmt::Display::fmt(inner, f),
Self::Values(inner) => fmt::Display::fmt(inner, f),
}
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Abstract {
span: Option<Span>,
}

impl Abstract {
pub fn new(span: Option<Span>) -> Self {
Self { span }
}
}

impl fmt::Display for Abstract {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "@{}", token::Annotation::Abstract)
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Cardinality {
span: Option<Span>,
min: Literal,
max: Option<Literal>,
}

impl Cardinality {
pub fn new(span: Option<Span>, min: Literal, max: Option<Literal>) -> Self {
Self { span, min, max }
}
}

impl fmt::Display for Cardinality {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "@{}({}..", token::Annotation::Cardinality, self.min)?;
if let Some(max) = &self.max {
write!(f, "{}", max)?;
}
f.write_char(')')?;
Ok(())
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Cascade {
span: Option<Span>,
}

impl Cascade {
pub fn new(span: Option<Span>) -> Self {
Self { span }
}
}

impl fmt::Display for Cascade {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "@{}", token::Annotation::Cascade)
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Distinct {
span: Option<Span>,
}

impl Distinct {
pub fn new(span: Option<Span>) -> Self {
Self { span }
}
}

impl fmt::Display for Distinct {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "@{}", token::Annotation::Distinct)
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Independent {
span: Option<Span>,
}

impl Independent {
pub fn new(span: Option<Span>) -> Self {
Self { span }
}
}

impl fmt::Display for Independent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "@{}", token::Annotation::Independent)
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Key {
span: Option<Span>,
}

impl Key {
pub fn new(span: Option<Span>) -> Self {
Self { span }
}
}

impl fmt::Display for Key {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "@{}", token::Annotation::Key)
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Range {
span: Option<Span>,
min: Option<Literal>,
max: Option<Literal>,
}

impl Range {
pub fn new(span: Option<Span>, min: Option<Literal>, max: Option<Literal>) -> Self {
Self { span, min, max }
}
}

impl fmt::Display for Range {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "@{}(", token::Annotation::Range)?;
if let Some(min) = &self.min {
write!(f, "{}", min)?;
}
f.write_str("..")?;
if let Some(max) = &self.max {
write!(f, "{}", max)?;
}
f.write_char(')')?;
Ok(())
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Regex {
span: Option<Span>,
regex: Literal,
}

impl Regex {
pub fn new(span: Option<Span>, regex: Literal) -> Self {
Self { span, regex }
}
}

impl fmt::Display for Regex {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "@{}({})", token::Annotation::Regex, self.regex)
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Subkey {
span: Option<Span>,
ident: Identifier,
}

impl Subkey {
pub fn new(span: Option<Span>, ident: Identifier) -> Self {
Self { span, ident }
}
}

impl fmt::Display for Subkey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "@{}({})", token::Annotation::Subkey, self.ident)
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Unique {
span: Option<Span>,
}

impl Unique {
pub fn new(span: Option<Span>) -> Self {
Self { span }
}
}

impl fmt::Display for Unique {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "@{}", token::Annotation::Unique)
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Values {
span: Option<Span>,
values: Vec<Literal>,
}

impl Values {
pub fn new(span: Option<Span>, values: Vec<Literal>) -> Self {
Self { span, values }
}
}

impl fmt::Display for Values {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "@{}(", token::Annotation::Values)?;
write_joined!(f, ", ", &self.values)?;
f.write_char(')')?;
Ok(())
}
}
27 changes: 24 additions & 3 deletions rust/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,33 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use crate::pattern::Label;
use crate::{common::identifier::Identifier, type_::Label, variable::Variable};

#[macro_export]
macro_rules! typeql_define {
macro_rules! define {
($($def:expr),* $(,)?) => {
$crate::query::TypeQLDefine::build(vec![$($def.into()),*])
$crate::query::schema::Define::build(vec![$($def.into()),*])
}
}

#[macro_export]
macro_rules! undefine {
($($def:expr),* $(,)?) => {
$crate::query::schema::Undefine::build(vec![$($def.into()),*])
}
}

#[macro_export]
macro_rules! match_ {
($($pattern:expr),* $(,)?) => {
$crate::query::pipeline::stage::Match::build(vec![$($pattern.into()),*])
}
}

pub fn var(name: impl Into<Identifier>) -> Variable {
Variable::Named(None, name.into())
}

pub fn type_(name: impl Into<Identifier>) -> Label {
Label::Identifier(name.into())
}
14 changes: 9 additions & 5 deletions rust/common/error/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::{error::Error as StdError, fmt};
use itertools::Itertools;
use pest::error::{Error as PestError, LineColLocation};

use crate::{error_messages, write_joined};
use crate::{error_messages, util::write_joined};

#[macro_use]
mod macros;
Expand Down Expand Up @@ -38,7 +38,7 @@ impl From<Vec<TypeQLError>> for Error {
}

pub(crate) fn syntax_error<T: pest::RuleType>(query: &str, error: PestError<T>) -> TypeQLError {
let (error_line_nr, _) = match error.line_col {
let (error_line_nr, error_col) = match error.line_col {
LineColLocation::Pos((line, col)) => (line, col),
LineColLocation::Span((line, col), _) => (line, col),
};
Expand All @@ -55,7 +55,7 @@ pub(crate) fn syntax_error<T: pest::RuleType>(query: &str, error: PestError<T>)
}
})
.join("\n");
TypeQLError::SyntaxErrorDetailed { error_line_nr, formatted_error }
TypeQLError::SyntaxErrorDetailed { error_line_nr, error_col, formatted_error }
}

impl fmt::Display for Error {
Expand All @@ -75,10 +75,14 @@ pub fn collect_err(i: impl IntoIterator<Item = Result<(), Error>>) -> Result<(),

error_messages! { TypeQLError
code: "TQL", type: "TypeQL Error",
SyntaxErrorDetailed { error_line_nr: usize, formatted_error: String } =
3: "There is a syntax error near line {error_line_nr}:\n{formatted_error}",
SyntaxErrorDetailed { error_line_nr: usize, error_col: usize, formatted_error: String } =
3: "There is a syntax error at {error_line_nr}:{error_col}:\n{formatted_error}",
InvalidCasting { enum_name: &'static str, variant: &'static str, expected_variant: &'static str, typename: &'static str } =
4: "Enum '{enum_name}::{variant}' does not match '{expected_variant}', and cannot be unwrapped into '{typename}'.",
InvalidLiteral { variant: &'static str, expected_variant: &'static str } =
5: "Attempting to parse a {variant} literal as {expected_variant}",
InvalidStringEscape { escape: String, full_string: String } =
6: "Encountered invalid escape sequence {escape:?} while parsing {full_string:?}.",
/*
MissingPatterns =
5: "The query has not been provided with any patterns.",
Expand Down
Loading

0 comments on commit 4a279a8

Please sign in to comment.