Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions test/code/parser/parser.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
import re
from dataclasses import dataclass
from typing import List, Dict
from typing import List, Dict, Tuple
import logging
logger = logging.getLogger('main')
# To see debug log, set logging level to debug in main.py
Expand Down Expand Up @@ -114,9 +114,17 @@ def retrieve_antora_include(self, include_str: str):
if tags_match.startswith('tags='):
tags = tags_match.split('=')[1].split(';')

line_nrs: Tuple[str, str] = (None, None)
if tags_match.startswith('lines='):
line_nrs = tags_match.split('=')[1].split('..')

# Read tagged lines from Antora include
with open(file_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
if line_nrs[1]:
lines = lines[:int(line_nrs[1])]
if line_nrs[0]:
lines = lines[int(line_nrs[0]) - 1:]

tagged_lines: Dict[str, List[str]] = {}
current_tag = None
Expand Down Expand Up @@ -148,10 +156,13 @@ def retrieve_antora_include(self, include_str: str):
logging.debug(f"... finished scanning included file, resolved tags: {tagged_lines}")

output_lines = []
for tag in tags:
if tagged_lines.get(tag) is None:
self.error(f"Include is missing tag {tag}")
output_lines += tagged_lines[tag]
if tags:
for tag in tags:
if tagged_lines.get(tag) is None:
self.error(f"Include is missing tag {tag}")
output_lines += tagged_lines[tag]
else:
output_lines = lines

return output_lines

Expand Down
4 changes: 3 additions & 1 deletion test/code/runners/typeql_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from enum import Enum
from typing import List, Dict, Tuple, Union
from test.code.parser.parser import ParsedTest
import re
import logging
logger = logging.getLogger('main')
# To see debug log, set logging level to debug in main.py
Expand Down Expand Up @@ -93,6 +94,7 @@ def run_failing_queries(self, queries: List[str], type: TransactionType) -> str:
return FailureMode.NoFailure

def run_transaction(self, queries: List[str], type: TransactionType, rollback=False) -> Union[int, None]:
queries = [q for qs in queries for q in re.split(r'\bend\s*;', qs) if q.strip()]
with self.driver.transaction(self.db, type) as tx:
try:
for q in queries:
Expand Down Expand Up @@ -236,4 +238,4 @@ def try_tests(self, parsed_tests: List[ParsedTest], adoc_path: str, file_config:

current_test_index += 1

return None
return None
545 changes: 545 additions & 0 deletions tutorials/modules/ROOT/attachments/bookstore-data.tql

Large diffs are not rendered by default.

300 changes: 300 additions & 0 deletions tutorials/modules/ROOT/attachments/bookstore-schema.tql
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
#
# 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.
#

define

entity book @abstract,
owns isbn @card(0..2),
owns isbn-13 @key,
owns isbn-10 @unique,
owns title,
owns page-count,
owns genre @card(0..),
owns price,
plays contribution:work,
plays publishing:published,
plays promotion-inclusion:item,
plays order-line:item,
plays rating:rated,
plays recommendation:recommended;

entity hardback sub book,
owns stock;

entity paperback sub book,
owns stock;

entity ebook sub book;

entity contributor,
owns name,
plays contribution:contributor,
plays authoring:author,
plays editing:editor,
plays illustrating:illustrator;

entity company @abstract,
owns name;

entity publisher sub company,
plays publishing:publisher;

entity courier sub company,
plays delivery:deliverer;

entity publication,
owns year,
plays publishing:publication,
plays locating:located;

entity user,
owns id @key,
owns name,
owns birth-date,
owns total-spending,
owns loyalty-tier,
plays action-execution:executor,
plays locating:located,
plays recommendation:recipient;

entity order,
owns id @key,
owns status,
plays order-line:order,
plays action-execution:action,
plays delivery:delivered;

entity promotion,
owns code @key,
owns name,
owns start-timestamp,
owns end-timestamp,
plays promotion-inclusion:promotion;

entity review,
owns id @key,
owns score,
owns verified,
plays rating:review,
plays action-execution:action;

entity login,
owns success,
plays action-execution:action;

entity address,
owns street,
plays delivery:destination,
plays locating:located;

entity place @abstract,
owns name,
plays locating:located,
plays locating:location;

entity city sub place;

entity state sub place;

entity country sub place;

relation contribution,
relates contributor,
relates work;

relation authoring sub contribution,
relates author as contributor;

relation editing sub contribution,
relates editor as contributor;

relation illustrating sub contribution,
relates illustrator as contributor;

relation publishing,
relates publisher,
relates published,
relates publication;

relation promotion-inclusion,
relates promotion,
relates item,
owns discount;

relation order-line,
relates order,
relates item,
owns quantity;

relation rating,
relates review,
relates rated;

relation action-execution,
relates action,
relates executor,
owns timestamp;

relation delivery,
relates deliverer,
relates delivered,
relates destination;

relation locating,
relates located,
relates location;

relation recommendation,
relates recommended,
relates recipient;

attribute isbn @abstract, value string;
attribute isbn-13 sub isbn;
attribute isbn-10 sub isbn;
attribute title, value string;
attribute page-count, value integer;
attribute genre, value string;
attribute stock, value integer;
attribute price, value double;
attribute discount, value double;
attribute id, value string;
attribute code, value string;
attribute name, value string;
attribute birth-date, value datetime;
attribute street, value string;
attribute year, value integer;
attribute quantity, value integer;
attribute score, value integer;
attribute verified, value boolean;
attribute timestamp, value datetime;
attribute start-timestamp, value datetime;
attribute end-timestamp, value datetime;
attribute status, value string @values("invalid", "pending", "paid", "dispatched", "delivered", "returned", "canceled");
attribute success, value boolean;
attribute total-spending, value double;
attribute loyalty-tier, value integer @range(0..5);

# TODO: Change to check
fun is_review_verified_by_purchase($review: review) -> { order }:
match
($review, $product) isa rating;
($order, $product) isa order-line;
($user, $review) isa action-execution, has timestamp $review-time;
($user, $order) isa action-execution, has timestamp $order-time;
$review-time > $order-time;
return { $order };

fun book_recommendations_for($user: user) -> {book}:
match
$new-book isa book;
{
let $new-book in book_recommendations_by_author($user);
} or {
let $new-book in book_recommendations_by_genre($user);
};
return { $new-book };

fun book_recommendations_by_genre($user: user) -> { book }:
match
$user isa user;
$liked-book isa book;
{
($user, $order-for-liked) isa action-execution;
($order-for-liked, $liked-book) isa order-line;
} or {
($user, $review-for-liked) isa action-execution;
($review-for-liked, $liked-book) isa rating;
$review-for-liked has score >= 7;
};
$new-book isa book;
not { {
($user, $order-for-new) isa action-execution;
($order-for-new, $new-book) isa order-line;
} or {
($user, $review-for-new) isa action-execution;
($review-for-new, $new-book) isa rating;
}; };
$liked-book has genre $shared-genre;
$new-book has genre $shared-genre;
not { {
$shared-genre == "fiction";
} or {
$shared-genre == "nonfiction";
}; };
return { $new-book };

fun book_recommendations_by_author($user: user) -> { book }:
match
$user isa user;
$liked-book isa book;
{
($user, $order-for-liked) isa action-execution;
($order-for-liked, $liked-book) isa order-line;
} or {
($user, $review-for-liked) isa action-execution;
($review-for-liked, $liked-book) isa rating;
$review-for-liked has score >= 7;
};
$new-book isa book;
not { {
($user, $order-for-new) isa action-execution;
($order-for-new, $new-book) isa order-line;
} or {
($user, $review-for-new) isa action-execution;
($review-for-new, $new-book) isa rating;
}; };
($liked-book, $shared-author) isa authoring;
($new-book, $shared-author) isa authoring;
return { $new-book };

fun order_line_best_price($line: order-line) -> { double }:
match
($order) isa action-execution, has timestamp $order-time;
$line isa order-line, links ($order, $item);
$item has price $retail-price;
let $time_value = $order-time;
let $best-discount = best_discount_for_item($item, $time_value);
let $discounted-price = round(100 * $retail-price * (1 - $best-discount)) / 100;
$line has quantity $quantity;
let $line-total = $quantity * $discounted-price;
return { $line-total };

fun best_discount_for_item($item: book, $order-time: datetime) -> double:
match
{
$inclusion isa promotion-inclusion,
links ($promotion, $item),
has discount $discount-attr;
$promotion has start-timestamp <= $order-time,
has end-timestamp >= $order-time;
let $discount = $discount-attr;
} or {
let $discount = 0.0; # default
};
return max($discount);

fun transitive_places($place: place) -> { place }:
match
{
locating (located: $place, location: $parent);
} or {
locating (located: $place, location: $middle);
let $parent in transitive_places($middle);
};
return { $parent };
Loading