Skip to content
This repository has been archived by the owner on Oct 9, 2023. It is now read-only.

Commit

Permalink
Introduce Values to support expressions (#296)
Browse files Browse the repository at this point in the history
## What is the goal of this PR?

Introduce the 'Value' type, which is returned as the result of an expression's computation. This change follows from typedb/typeql#260, which outlines the capabilities of the new expression syntax.

Values (representing any of Long, Double, Boolean, String, or DateTime) are returned as part of `ConceptMap` answers and are subtypes of `Concept` for the time being. Their main API is made of the `.get_value()` method and `.get_value_vype()` method, along with all the standard safe downcasting methods to convert a `Concept` into a `Value`, using `Concept.is_value()` and `Concept.as_value()`.

We also move the import location of `ValueType` from `attribute_type.py` to `concept.py`.

## What are the changes implemented in this PR?

* Introduces the `Value` concept and the required `ValueImpl` that implements it
* Refactor `ValueType` to no longer live within `AttributeType` - now it exists in `Concept.ValueType`
* Updates the test framework for tests involving values, including the new `ExpressionTest` behaviour scenarios, which we also add to CI
  • Loading branch information
flyingsilverfin authored May 26, 2023
1 parent ea839a8 commit 6155300
Show file tree
Hide file tree
Showing 23 changed files with 588 additions and 207 deletions.
2 changes: 2 additions & 0 deletions .factory/automation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ build:
bazel run @vaticle_dependencies//distribution/artifact:create-netrc
.factory/test-core.sh //tests/behaviour/typeql/language/match/... --test_output=errors
.factory/test-core.sh //tests/behaviour/typeql/language/get/... --test_output=errors
.factory/test-core.sh //tests/behaviour/typeql/language/expression/... --test_output=errors
test-behaviour-match-cluster:
image: vaticle-ubuntu-22.04
type: foreground
Expand All @@ -135,6 +136,7 @@ build:
bazel run @vaticle_dependencies//distribution/artifact:create-netrc
.factory/test-cluster.sh //tests/behaviour/typeql/language/match/... --test_output=errors
.factory/test-cluster.sh //tests/behaviour/typeql/language/get/... --test_output=errors
.factory/test-cluster.sh //tests/behaviour/typeql/language/expression/... --test_output=errors
test-behaviour-writable-core:
image: vaticle-ubuntu-22.04
type: foreground
Expand Down
4 changes: 2 additions & 2 deletions dependencies/vaticle/artifacts.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def vaticle_typedb_artifacts():
artifact_name = "typedb-server-{platform}-{version}.{ext}",
tag_source = deployment["artifact.release"],
commit_source = deployment["artifact.snapshot"],
commit = "0f43f6654dff206d168711d90785d12df4c98b5e",
commit = "cb119c536c44275f58df7b54da033f8fe076cac5",
)

def vaticle_typedb_cluster_artifacts():
Expand All @@ -39,5 +39,5 @@ def vaticle_typedb_cluster_artifacts():
artifact_name = "typedb-cluster-all-{platform}-{version}.{ext}",
tag_source = deployment_private["artifact.release"],
commit_source = deployment_private["artifact.snapshot"],
commit = "9b70d31b54ed0162ce5df6ac4ab6180229bd7cb9",
commit = "8044753056dd20b8e6bec6f62036eb0003d4ba06",
)
6 changes: 3 additions & 3 deletions dependencies/vaticle/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,19 @@ def vaticle_dependencies():
git_repository(
name = "vaticle_dependencies",
remote = "https://github.com/vaticle/dependencies",
commit = "e0446ffa70cacca89cb1faa2cd6f299c3784d845", # sync-marker: do not remove this comment, this is used for sync-dependencies by @vaticle_dependencies
commit = "385716283e1e64245c3679a06054e271a0608ac1", # sync-marker: do not remove this comment, this is used for sync-dependencies by @vaticle_dependencies
)

def vaticle_typedb_common():
git_repository(
name = "vaticle_typedb_common",
remote = "https://github.com/vaticle/typedb-common",
tag = "2.17.0" # sync-marker: do not remove this comment, this is used for sync-dependencies by @vaticle_typedb_common
commit = "9372dfb227d54c6eb631eed02e67f250e55e657e" # sync-marker: do not remove this comment, this is used for sync-dependencies by @vaticle_typedb_common
)

def vaticle_typedb_behaviour():
git_repository(
name = "vaticle_typedb_behaviour",
remote = "https://github.com/vaticle/typedb-behaviour",
commit = "aa675d9052046b1a4ffd45f444854d8735028702" # sync-marker: do not remove this comment, this is used for sync-dependencies by @vaticle_typedb_behaviour
commit = "767bf98fef7383addf42a1ae6e97a44874bb4f0b" # sync-marker: do not remove this comment, this is used for sync-dependencies by @vaticle_typedb_behaviour
)
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

## Dependencies

typedb-protocol==2.18.0.dev0
typedb-protocol==2.18.0.dev2
grpcio>=1.43.0,<2
protobuf>=3.15.6,<4
parse==1.18.0
2 changes: 1 addition & 1 deletion tests/behaviour/concept/thing/attribute/attribute_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def step_impl(context: Context, var1: str, var2: str):


@step("attribute {var:Var} has value type: {value_type:ValueType}")
def step_impl(context: Context, var: str, value_type: AttributeType.ValueType):
def step_impl(context: Context, var: str, value_type: ValueType):
assert_that(context.get(var).as_attribute().get_type().get_value_type(), is_(value_type))


Expand Down
74 changes: 35 additions & 39 deletions tests/behaviour/concept/type/attributetype/attribute_type_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,94 +21,90 @@

from behave import *
from hamcrest import *
from typedb.client import *

from tests.behaviour.config.parameters import parse_value_type, parse_list, parse_label
from tests.behaviour.context import Context
from typedb.client import *


@step("put attribute type: {type_label}, with value type: {value_type}")
def step_impl(context: Context, type_label: str, value_type: str):
context.tx().concepts().put_attribute_type(type_label, parse_value_type(value_type))
@step("put attribute type: {type_label}, with value type: {value_type:ValueType}")
def step_impl(context: Context, type_label: str, value_type: ValueType):
context.tx().concepts().put_attribute_type(type_label, value_type)


@step("attribute({type_label}) get value type: {value_type}")
def step_impl(context: Context, type_label: str, value_type: str):
@step("attribute({type_label}) get value type: {value_type:ValueType}")
def step_impl(context: Context, type_label: str, value_type: ValueType):
assert_that(context.tx().concepts().get_attribute_type(type_label).get_value_type(),
is_(parse_value_type(value_type)))
is_(value_type))


@step("attribute({type_label}) get supertype value type: {value_type}")
def step_impl(context: Context, type_label: str, value_type: str):
@step("attribute({type_label}) get supertype value type: {value_type:ValueType}")
def step_impl(context: Context, type_label: str, value_type: ValueType):
supertype = context.tx().concepts().get_attribute_type(type_label).as_remote(
context.tx()).get_supertype().as_attribute_type()
assert_that(supertype.get_value_type(), is_(parse_value_type(value_type)))
assert_that(supertype.get_value_type(), is_(value_type))


def attribute_type_as_value_type(context: Context, type_label: str, value_type: AttributeType.ValueType):
def attribute_type_as_value_type(context: Context, type_label: str, value_type: ValueType):
attribute_type = context.tx().concepts().get_attribute_type(type_label)
if value_type is AttributeType.ValueType.OBJECT:
if value_type is ValueType.OBJECT:
return attribute_type
elif value_type is AttributeType.ValueType.BOOLEAN:
elif value_type is ValueType.BOOLEAN:
return attribute_type.as_boolean()
elif value_type is AttributeType.ValueType.LONG:
elif value_type is ValueType.LONG:
return attribute_type.as_long()
elif value_type is AttributeType.ValueType.DOUBLE:
elif value_type is ValueType.DOUBLE:
return attribute_type.as_double()
elif value_type is AttributeType.ValueType.STRING:
elif value_type is ValueType.STRING:
return attribute_type.as_string()
elif value_type is AttributeType.ValueType.DATETIME:
elif value_type is ValueType.DATETIME:
return attribute_type.as_datetime()
else:
raise ValueError("Unrecognised value type: " + str(value_type))


@step("attribute({type_label}) as({value_type}) get subtypes contain")
def step_impl(context: Context, type_label: str, value_type: str):
@step("attribute({type_label}) as({value_type:ValueType}) get subtypes contain")
def step_impl(context: Context, type_label: str, value_type: ValueType):
sub_labels = [parse_label(s) for s in parse_list(context.table)]
attribute_type = attribute_type_as_value_type(context, type_label, parse_value_type(value_type))
attribute_type = attribute_type_as_value_type(context, type_label, value_type)
actuals = list(map(lambda tt: tt.get_label(), attribute_type.as_remote(context.tx()).get_subtypes()))
for sub_label in sub_labels:
assert_that(sub_label, is_in(actuals))


@step("attribute({type_label}) as({value_type}) get subtypes do not contain")
def step_impl(context: Context, type_label: str, value_type: str):
@step("attribute({type_label}) as({value_type:ValueType}) get subtypes do not contain")
def step_impl(context: Context, type_label: str, value_type: ValueType):
sub_labels = [parse_label(s) for s in parse_list(context.table)]
attribute_type = attribute_type_as_value_type(context, type_label, parse_value_type(value_type))
attribute_type = attribute_type_as_value_type(context, type_label, value_type)
actuals = list(map(lambda tt: tt.get_label(), attribute_type.as_remote(context.tx()).get_subtypes()))
for sub_label in sub_labels:
assert_that(sub_label, not_(is_in(actuals)))


@step("attribute({type_label}) as({value_type}) set regex: {regex}")
def step_impl(context: Context, type_label: str, value_type, regex: str):
value_type = parse_value_type(value_type)
assert_that(value_type, is_(AttributeType.ValueType.STRING))
@step("attribute({type_label}) as({value_type:ValueType}) set regex: {regex}")
def step_impl(context: Context, type_label: str, value_type: ValueType, regex: str):
assert_that(value_type, is_(ValueType.STRING))
attribute_type = attribute_type_as_value_type(context, type_label, value_type)
attribute_type.as_remote(context.tx()).set_regex(regex)


@step("attribute({type_label}) as({value_type}) unset regex")
def step_impl(context: Context, type_label: str, value_type):
value_type = parse_value_type(value_type)
assert_that(value_type, is_(AttributeType.ValueType.STRING))
@step("attribute({type_label}) as({value_type:ValueType}) unset regex")
def step_impl(context: Context, type_label: str, value_type: ValueType):
assert_that(value_type, is_(ValueType.STRING))
attribute_type = attribute_type_as_value_type(context, type_label, value_type)
attribute_type.as_remote(context.tx()).set_regex(None)


@step("attribute({type_label}) as({value_type}) get regex: {regex}")
def step_impl(context: Context, type_label: str, value_type, regex: str):
value_type = parse_value_type(value_type)
assert_that(value_type, is_(AttributeType.ValueType.STRING))
@step("attribute({type_label}) as({value_type:ValueType}) get regex: {regex}")
def step_impl(context: Context, type_label: str, value_type: ValueType, regex: str):
assert_that(value_type, is_(ValueType.STRING))
attribute_type = attribute_type_as_value_type(context, type_label, value_type)
assert_that(attribute_type.as_remote(context.tx()).get_regex(), is_(regex))


@step("attribute({type_label}) as({value_type}) does not have any regex")
def step_impl(context: Context, type_label: str, value_type):
value_type = parse_value_type(value_type)
assert_that(value_type, is_(AttributeType.ValueType.STRING))
@step("attribute({type_label}) as({value_type:ValueType}) does not have any regex")
def step_impl(context: Context, type_label: str, value_type: ValueType):
assert_that(value_type, is_(ValueType.STRING))
attribute_type = attribute_type_as_value_type(context, type_label, value_type)
assert_that(attribute_type.as_remote(context.tx()).get_regex(), is_(None))

Expand Down
12 changes: 6 additions & 6 deletions tests/behaviour/config/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,13 +129,13 @@ def parse_var(text: str):


@parse.with_pattern(r"long|double|string|boolean|datetime")
def parse_value_type(value: str) -> AttributeType.ValueType:
def parse_value_type(value: str) -> ValueType:
mapping = {
"long": AttributeType.ValueType.LONG,
"double": AttributeType.ValueType.DOUBLE,
"string": AttributeType.ValueType.STRING,
"boolean": AttributeType.ValueType.BOOLEAN,
"datetime": AttributeType.ValueType.DATETIME
"long": ValueType.LONG,
"double": ValueType.DOUBLE,
"string": ValueType.STRING,
"boolean": ValueType.BOOLEAN,
"datetime": ValueType.DATETIME
}
return mapping[value]

Expand Down
55 changes: 55 additions & 0 deletions tests/behaviour/typeql/language/expression/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#
# Copyright (C) 2022 Vaticle
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

package(default_visibility = ["//tests/behaviour:__subpackages__"])
load("//tools:behave_rule.bzl", "typedb_behaviour_py_test")
load("@vaticle_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test")

typedb_behaviour_py_test(
name = "test",
feats = ["@vaticle_typedb_behaviour//typeql/language:expression.feature"],
background_core = ["//tests/behaviour/background:core"],
background_cluster = ["//tests/behaviour/background:cluster"],
steps = [
"//tests/behaviour/connection:steps",
"//tests/behaviour/connection/database:steps",
"//tests/behaviour/connection/session:steps",
"//tests/behaviour/connection/transaction:steps",
"//tests/behaviour/typeql:steps",
],
deps = [
"//:client_python",
"//tests/behaviour:context",
"//tests/behaviour/util:util",
"//tests/behaviour/config:parameters",
"//tests/behaviour/background",
],
native_typedb_artifact = "//tests:native-typedb-artifact",
native_typedb_cluster_artifact = "//tests:native-typedb-cluster-artifact",
size = "medium",
)

checkstyle_test(
name = "checkstyle",
include = glob(["*"]),
license_type = "apache-header",
size = "small",
)
Loading

0 comments on commit 6155300

Please sign in to comment.