From c5247f5e6510e3f2446c35419de67c7bbeaf51b5 Mon Sep 17 00:00:00 2001 From: Roberto Franchini Date: Thu, 4 Sep 2025 20:31:29 +0200 Subject: [PATCH 01/11] #2230 initial work on enhanced variable behaviour in SQL script --- .../sql/executor/BasicCommandContext.java | 48 ++++++----- .../query/sql/executor/CommandContext.java | 8 +- .../com/arcadedb/query/sql/BatchTest.java | 16 ++++ .../query/sql/parser/BatchScriptTest.java | 79 ++++++++++--------- 4 files changed, 91 insertions(+), 60 deletions(-) diff --git a/engine/src/main/java/com/arcadedb/query/sql/executor/BasicCommandContext.java b/engine/src/main/java/com/arcadedb/query/sql/executor/BasicCommandContext.java index 879264feba..500dfa75fa 100644 --- a/engine/src/main/java/com/arcadedb/query/sql/executor/BasicCommandContext.java +++ b/engine/src/main/java/com/arcadedb/query/sql/executor/BasicCommandContext.java @@ -23,7 +23,10 @@ import com.arcadedb.database.DatabaseInternal; import com.arcadedb.database.Document; -import java.util.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; /** * Basic implementation of CommandContext interface that stores variables in a map. Supports parent/child context to build a tree @@ -109,47 +112,56 @@ public Object getVariable(final String name) { return getVariable(name, null); } - public Object getVariable(String name, final Object iDefault) { + public Object getVariable(String name, final Object defaultValue) { if (name == null) - return iDefault; + return defaultValue; - final Object result; + Object result; if (name.startsWith("$")) name = name.substring(1); - final String firstPart; - firstPart = name; + String fieldName = null; + if (name.contains(".")) { + String[] parts = name.split("\\."); + name = parts[0]; + fieldName = parts[1]; + } - if (firstPart.equalsIgnoreCase("CONTEXT")) + if (name.equalsIgnoreCase("CONTEXT")) result = getVariables(); - else if (firstPart.equalsIgnoreCase("PARENT")) + else if (name.equalsIgnoreCase("PARENT")) result = parent; - else if (firstPart.equalsIgnoreCase("ROOT")) { + else if (name.equalsIgnoreCase("ROOT")) { CommandContext p = this; while (p.getParent() != null) p = p.getParent(); result = p; + } else { - if (variables != null && variables.containsKey(firstPart)) - result = variables.get(firstPart); + if (variables != null && variables.containsKey(name)) + result = variables.get(name); else { if (child != null) - result = child.getVariable(firstPart); + result = child.getVariable(name); else - result = getVariableFromParentHierarchy(firstPart); + result = getVariableFromParentHierarchy(name); } } - return result != null ? result : iDefault; + if (fieldName != null) { + if (result instanceof Result result1) + result = result1.getProperty(fieldName); + } + return result != null ? result : defaultValue; } - protected Object getVariableFromParentHierarchy(final String varName) { - if (this.variables != null && variables.containsKey(varName)) { - return variables.get(varName); + protected Object getVariableFromParentHierarchy(final String name) { + if (this.variables != null && variables.containsKey(name)) { + return variables.get(name); } if (parent != null && parent instanceof BasicCommandContext context) { - return context.getVariableFromParentHierarchy(varName); + return context.getVariableFromParentHierarchy(name); } return null; } diff --git a/engine/src/main/java/com/arcadedb/query/sql/executor/CommandContext.java b/engine/src/main/java/com/arcadedb/query/sql/executor/CommandContext.java index 81dd33ec21..8722e60c2e 100644 --- a/engine/src/main/java/com/arcadedb/query/sql/executor/CommandContext.java +++ b/engine/src/main/java/com/arcadedb/query/sql/executor/CommandContext.java @@ -35,11 +35,11 @@ public interface CommandContext { Object getVariablePath(String name, Object iDefault); - Object getVariable(String iName); + Object getVariable(String name); - Object getVariable(String iName, Object iDefaultValue); + Object getVariable(String name, Object iDefaultValue); - CommandContext setVariable(String iName, Object iValue); + CommandContext setVariable(String name, Object iValue); CommandContext incrementVariable(String getNeighbors); @@ -47,7 +47,7 @@ public interface CommandContext { CommandContext getParent(); - CommandContext setParent(CommandContext iParentContext); + CommandContext setParent(CommandContext parentContext); CommandContext setChild(CommandContext context); diff --git a/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java b/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java index de828f451d..c535043f15 100644 --- a/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java +++ b/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java @@ -256,6 +256,22 @@ public void testForeachResultSet() { assertThat((Integer) result.next().getProperty("value")).isEqualTo(100); } + @Test + public void testForeachResultSetReadFieldName() { + database.command("sql", "CREATE DOCUMENT TYPE DocumentType"); + database.transaction(() -> { + database.command("sql", "INSERT INTO DocumentType set a = 'aaaa' "); + }); + + final ResultSet result = database.command("sqlscript", """ + LET row = select from DocumentType; + LET counter = $row.a; + RETURN $counter; + """); + assertThat(result.hasNext()).isTrue(); + assertThat(result.next().getProperty("value")).isEqualTo("aaaa"); + } + @Test public void testUsingReservedVariableNames() { try { diff --git a/engine/src/test/java/com/arcadedb/query/sql/parser/BatchScriptTest.java b/engine/src/test/java/com/arcadedb/query/sql/parser/BatchScriptTest.java index 0a91e2f843..d4a8bc5355 100755 --- a/engine/src/test/java/com/arcadedb/query/sql/parser/BatchScriptTest.java +++ b/engine/src/test/java/com/arcadedb/query/sql/parser/BatchScriptTest.java @@ -35,49 +35,52 @@ public void testPlain() { checkRightSyntax("begin;\nselect from foo;/*foo bar*/ return bar;"); checkRightSyntax("/*foo bar*/ begin;\nselect from foo;return bar;/*foo bar*/ "); - String s = ""// - + "begin;"// - + "let $a = select from foo let a = 13 where bar = 'baz';"// - + "let $b = insert into foo set name = 'baz';"// - + "let $c = update v set name = 'lkajsd';"// - + "if($c < $a){"// - + " update v set surname = baz;"// - + " if($c < $b){"// - + " return 0;"// - + " }"// - + "}"// - + "return 1;"; + String s = """ + begin; + let $a = select from foo let a = 13 where bar = 'baz'; + let $b = insert into foo set name = 'baz'; + let $c = update v set name = 'lkajsd'; + if($c < $a){ + update v set surname = baz; + if($c < $b){ + return 0; + } + } + return 1;"""; checkRightSyntax(s); - s = ""// - + "begin;\n"// - + "let $a = select from foo let a = 13 where bar = 'baz';\n"// - + "let $b = insert into foo set name = 'baz';\n"// - + "let $c = update v set name = 'lkajsd';\n"// - + "if($c < $a){\n"// - + " update v set surname = baz;\n"// - + " if($c < $b){\n"// - + " return 0;\n"// - + " }\n"// - + "}\n"// - + "return 1;\n"; + s = """ + + begin; + let $a = select from foo let a = 13 where bar = 'baz'; + let $b = insert into foo set name = 'baz'; + let $c = update v set name = 'lkajsd'; + if($c < $a){ + update v set surname = baz; + if($c < $b){ + return 0; + } + } + return 1; + """; checkRightSyntax(s); - s = ""// - + "begin;\n"// - + "let $a = select from foo let a = 13 where bar = 'baz';\n"// - + "let $b = insert into foo set name = 'baz';\n"// - + "let $c = update v set \n"// - + "/** foo bar */\n"// - + "name = 'lkajsd';\n"// - + "if($c < $a){\n"// - + " update v set surname = baz;\n"// - + " if($c < $b){\n"// - + " return 0;\n"// - + " }\n"// - + "}\n"// - + "return 1;\n"; + s = """ + begin; + let $a = select from foo let a = 13 where bar = 'baz'; + let $b = insert into foo set name = 'baz'; + let $c = update v set + /** foo bar */ + name = 'lkajsd'; + if($c < $a){ + update v set surname = baz; + if($c < $b){ + return 0; + } + } + return 1; + """; checkRightSyntax(s); s = "let a = select 1 as result;let b = select 2 as result;return [$a,$b];"; From c78a6183f8f7ddfd6fa3cddc0f34cc508d6026cb Mon Sep 17 00:00:00 2001 From: Roberto Franchini Date: Fri, 5 Sep 2025 12:06:37 +0200 Subject: [PATCH 02/11] #2230 enhance variable handling in SQL script execution --- .../sql/executor/SelectExecutionPlanner.java | 29 ++++++++++++-- .../com/arcadedb/query/sql/BatchTest.java | 39 +++++++++++++++++-- 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/engine/src/main/java/com/arcadedb/query/sql/executor/SelectExecutionPlanner.java b/engine/src/main/java/com/arcadedb/query/sql/executor/SelectExecutionPlanner.java index e38bb3ad0d..6e496962d6 100644 --- a/engine/src/main/java/com/arcadedb/query/sql/executor/SelectExecutionPlanner.java +++ b/engine/src/main/java/com/arcadedb/query/sql/executor/SelectExecutionPlanner.java @@ -72,8 +72,18 @@ import com.arcadedb.schema.Type; import com.arcadedb.utility.Pair; -import java.util.*; -import java.util.stream.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; import static com.arcadedb.schema.Property.RID_PROPERTY; import static com.arcadedb.schema.Schema.INDEX_TYPE.FULL_TEXT; @@ -432,13 +442,24 @@ protected static void optimizeQuery(final QueryPlanningInfo info, final CommandC } private static void rewriteIndexChainsAsSubqueries(QueryPlanningInfo info, CommandContext context) { - if (context == null || context.getDatabase() == null) { + if (context == null || + context.getDatabase() == null) { return; } - if (info.whereClause != null && info.target != null && info.target.getItem().getIdentifier() != null) { + + if (info.whereClause != null && + info.target != null && + info.target.getItem().getIdentifier() != null) { + String className = info.target.getItem().getIdentifier().getStringValue(); + if (className.startsWith("$")) { + className = (String) context.getVariable(className); + info.target.getItem().setIdentifier(new Identifier(className)); + } + Schema schema = context.getDatabase().getSchema(); DocumentType type = schema.getType(className); + info.whereClause.getBaseExpression().rewriteIndexChainsAsSubqueries(context, type); } } diff --git a/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java b/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java index c535043f15..8c4f1b97c5 100644 --- a/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java +++ b/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java @@ -20,6 +20,7 @@ import com.arcadedb.TestHelper; import com.arcadedb.exception.CommandSQLParsingException; +import com.arcadedb.graph.Edge; import com.arcadedb.query.sql.executor.Result; import com.arcadedb.query.sql.executor.ResultSet; import org.junit.jupiter.api.Test; @@ -257,21 +258,51 @@ public void testForeachResultSet() { } @Test - public void testForeachResultSetReadFieldName() { + public void testFromSingleResultReadValueFromField() { database.command("sql", "CREATE DOCUMENT TYPE DocumentType"); database.transaction(() -> { - database.command("sql", "INSERT INTO DocumentType set a = 'aaaa' "); + database.command("sql", "INSERT INTO DocumentType set field = 'aaaa' "); }); final ResultSet result = database.command("sqlscript", """ LET row = select from DocumentType; - LET counter = $row.a; - RETURN $counter; + LET fieldValue = $row.field; + RETURN $fieldValue; """); assertThat(result.hasNext()).isTrue(); assertThat(result.next().getProperty("value")).isEqualTo("aaaa"); } + @Test + public void testReadTypeFromVariable() { + database.command("sql", "CREATE VERTEX TYPE V1"); + database.command("sql", "CREATE VERTEX TYPE V2"); + database.command("sql", "CREATE EDGE TYPE HasSource"); + database.transaction(() -> { + for (int i = 0; i < 10; i++) { + database.command("sql", "INSERT INTO V1 set id = ? , vType = ? ", i, "V2"); + database.command("sql", "INSERT INTO V2 set id = ? ", i); + } + }); + + final ResultSet resultSet = database.command("sqlscript", """ + BEGIN; + LET sources = SELECT FROM V1 WHERE id = '1'; + LET source = $sources[0]; + LET type = $source.vType; + LET target = SELECT FROM $type WHERE id = '9'; + LET e = CREATE EDGE HasSource FROM $target TO $source IF NOT EXISTS ; + COMMIT; + RETURN $e; + """); + + assertThat(resultSet.hasNext()).isTrue(); + Edge edge = resultSet.next().getEdge().get(); + assertThat(edge.getInVertex().getInteger("id")).isEqualTo(1); + assertThat(edge.getOutVertex().getInteger("id")).isEqualTo(9); + + } + @Test public void testUsingReservedVariableNames() { try { From 17fbbab7fd3558b6ad11b8be1e22388f4fe13e07 Mon Sep 17 00:00:00 2001 From: Roberto Franchini Date: Fri, 5 Sep 2025 14:23:44 +0200 Subject: [PATCH 03/11] #2230 enhance dynamic naming in SQL script execution --- .../e2e/RemoteDatabaseJavaApiTest.java | 6 +++-- .../executor/CreateEdgeExecutionPlanner.java | 23 +++++++++++-------- .../CreateVertexExecutionPlanner.java | 10 +++++++- .../sql/executor/DeleteExecutionPlanner.java | 6 +++-- .../sql/executor/SelectExecutionPlanner.java | 10 ++++---- .../com/arcadedb/query/sql/BatchTest.java | 3 ++- 6 files changed, 37 insertions(+), 21 deletions(-) diff --git a/e2e/src/test/java/com/arcadedb/e2e/RemoteDatabaseJavaApiTest.java b/e2e/src/test/java/com/arcadedb/e2e/RemoteDatabaseJavaApiTest.java index 1f5a8d19e7..af98a2efc6 100644 --- a/e2e/src/test/java/com/arcadedb/e2e/RemoteDatabaseJavaApiTest.java +++ b/e2e/src/test/java/com/arcadedb/e2e/RemoteDatabaseJavaApiTest.java @@ -136,9 +136,11 @@ void createTypesAndDataWithSqlScripts() { database.command("sqlscript", """ - BEGIN;LET photo = CREATE VERTEX Photos SET id = "p5555", name = "download3.jpg"; + BEGIN; + LET photo = CREATE VERTEX Photos SET id = "p5555", name = "download3.jpg"; LET user = SELECT FROM Users WHERE id = "u1111"; - LET userEdge = CREATE EDGE HasUploaded FROM $user TO $photo SET kind = "User_Photos"; + LET edgeType = 'HasUploaded'; + LET userEdge = CREATE EDGE $edgeType FROM $user TO $photo SET kind = "User_Photos"; COMMIT RETRY 30; RETURN $photo;"""); diff --git a/engine/src/main/java/com/arcadedb/query/sql/executor/CreateEdgeExecutionPlanner.java b/engine/src/main/java/com/arcadedb/query/sql/executor/CreateEdgeExecutionPlanner.java index 10a9f28561..74671659fa 100644 --- a/engine/src/main/java/com/arcadedb/query/sql/executor/CreateEdgeExecutionPlanner.java +++ b/engine/src/main/java/com/arcadedb/query/sql/executor/CreateEdgeExecutionPlanner.java @@ -20,7 +20,6 @@ import com.arcadedb.database.Database; import com.arcadedb.exception.CommandSQLParsingException; -import com.arcadedb.index.TypeIndex; import com.arcadedb.query.sql.parser.CreateEdgeStatement; import com.arcadedb.query.sql.parser.Expression; import com.arcadedb.query.sql.parser.Identifier; @@ -29,7 +28,6 @@ import com.arcadedb.query.sql.parser.JsonArray; import com.arcadedb.query.sql.parser.UpdateItem; import com.arcadedb.schema.DocumentType; -import com.arcadedb.schema.EdgeType; import java.util.ArrayList; import java.util.List; @@ -39,7 +37,7 @@ */ public class CreateEdgeExecutionPlanner { - protected Identifier targetClass; + protected Identifier targetType; protected final Identifier targetBucketName; protected final Expression leftExpression; protected final Expression rightExpression; @@ -48,7 +46,7 @@ public class CreateEdgeExecutionPlanner { protected final InsertBody body; public CreateEdgeExecutionPlanner(final CreateEdgeStatement statement) { - this.targetClass = statement.getTargetType() == null ? null : statement.getTargetType().copy(); + this.targetType = statement.getTargetType() == null ? null : statement.getTargetType().copy(); this.targetBucketName = statement.getTargetBucketName() == null ? null : statement.getTargetBucketName().copy(); this.leftExpression = statement.getLeftExpression() == null ? null : statement.getLeftExpression().copy(); this.rightExpression = statement.getRightExpression() == null ? null : statement.getRightExpression().copy(); @@ -65,7 +63,12 @@ public CreateEdgeExecutionPlanner(final CreateEdgeStatement statement) { public InsertExecutionPlan createExecutionPlan(final CommandContext context) { - if (targetClass == null) { + if (targetType.getStringValue().startsWith("$")) { + String variable = (String) context.getVariable(targetType.getStringValue()); + targetType = new Identifier(variable); + } + + if (targetType == null) { if (targetBucketName == null) { throw new CommandSQLParsingException("Missing target"); } else { @@ -73,7 +76,7 @@ public InsertExecutionPlan createExecutionPlan(final CommandContext context) { final DocumentType typez = db.getSchema() .getTypeByBucketId((db.getSchema().getBucketByName(targetBucketName.getStringValue()).getFileId())); if (typez != null) { - targetClass = new Identifier(typez.getName()); + targetType = new Identifier(typez.getName()); } else { throw new CommandSQLParsingException("Missing target"); } @@ -100,10 +103,10 @@ public InsertExecutionPlan createExecutionPlan(final CommandContext context) { // .findFirst() // .orElse(null); // } else - uniqueIndexName = null; + uniqueIndexName = null; result.chain( - new CreateEdgesStep(targetClass, targetBucketName, uniqueIndexName, new Identifier("$__ARCADEDB_CREATE_EDGE_fromV"), + new CreateEdgesStep(targetType, targetBucketName, uniqueIndexName, new Identifier("$__ARCADEDB_CREATE_EDGE_fromV"), new Identifier("$__ARCADEDB_CREATE_EDGE_toV"), unidirectional, ifNotExists, context)); handleSetFields(result, body, context); @@ -118,8 +121,8 @@ private void handleGlobalLet(final InsertExecutionPlan result, final Identifier } private void handleCheckType(final InsertExecutionPlan result, final CommandContext context) { - if (targetClass != null) { - result.chain(new CheckIsEdgeTypeStep(targetClass.getStringValue(), context)); + if (targetType != null) { + result.chain(new CheckIsEdgeTypeStep(targetType.getStringValue(), context)); } } diff --git a/engine/src/main/java/com/arcadedb/query/sql/executor/CreateVertexExecutionPlanner.java b/engine/src/main/java/com/arcadedb/query/sql/executor/CreateVertexExecutionPlanner.java index 088adbff95..3f28d6af16 100644 --- a/engine/src/main/java/com/arcadedb/query/sql/executor/CreateVertexExecutionPlanner.java +++ b/engine/src/main/java/com/arcadedb/query/sql/executor/CreateVertexExecutionPlanner.java @@ -20,13 +20,16 @@ import com.arcadedb.exception.CommandSQLParsingException; import com.arcadedb.query.sql.parser.CreateVertexStatement; +import com.arcadedb.query.sql.parser.Identifier; -import java.util.*; +import java.util.ArrayList; +import java.util.List; /** * @author Luigi Dell'Aquila (luigi.dellaquila-(at)-gmail.com) */ public class CreateVertexExecutionPlanner extends InsertExecutionPlanner { + public CreateVertexExecutionPlanner(final CreateVertexStatement statement) { this.targetType = statement.getTargetType() == null ? null : statement.getTargetType().copy(); this.targetBucketName = statement.getTargetBucketName() == null ? null : statement.getTargetBucketName().copy(); @@ -40,6 +43,11 @@ public CreateVertexExecutionPlanner(final CreateVertexStatement statement) { @Override public InsertExecutionPlan createExecutionPlan(final CommandContext context) { + if (targetType.getStringValue().startsWith("$")) { + String variable = (String) context.getVariable(targetType.getStringValue()); + targetType = new Identifier(variable); + } + final InsertExecutionPlan prev = super.createExecutionPlan(context); final List steps = new ArrayList<>(prev.getSteps()); final InsertExecutionPlan result = new InsertExecutionPlan(context); diff --git a/engine/src/main/java/com/arcadedb/query/sql/executor/DeleteExecutionPlanner.java b/engine/src/main/java/com/arcadedb/query/sql/executor/DeleteExecutionPlanner.java index eb514d4989..51590443a3 100644 --- a/engine/src/main/java/com/arcadedb/query/sql/executor/DeleteExecutionPlanner.java +++ b/engine/src/main/java/com/arcadedb/query/sql/executor/DeleteExecutionPlanner.java @@ -168,10 +168,12 @@ private void handleLimit(final UpdateExecutionPlan plan, final CommandContext co plan.chain(new LimitExecutionStep(limit, context)); } - private void handleTarget(final UpdateExecutionPlan result, final CommandContext context, final FromClause target, + private void handleTarget(final UpdateExecutionPlan result, + final CommandContext context, + final FromClause fromClause, final WhereClause whereClause) { final SelectStatement sourceStatement = new SelectStatement(-1); - sourceStatement.setTarget(target); + sourceStatement.setTarget(fromClause); sourceStatement.setWhereClause(whereClause); final SelectExecutionPlanner planner = new SelectExecutionPlanner(sourceStatement); result.chain( diff --git a/engine/src/main/java/com/arcadedb/query/sql/executor/SelectExecutionPlanner.java b/engine/src/main/java/com/arcadedb/query/sql/executor/SelectExecutionPlanner.java index 6e496962d6..7caf71d778 100644 --- a/engine/src/main/java/com/arcadedb/query/sql/executor/SelectExecutionPlanner.java +++ b/engine/src/main/java/com/arcadedb/query/sql/executor/SelectExecutionPlanner.java @@ -451,14 +451,14 @@ private static void rewriteIndexChainsAsSubqueries(QueryPlanningInfo info, Comma info.target != null && info.target.getItem().getIdentifier() != null) { - String className = info.target.getItem().getIdentifier().getStringValue(); - if (className.startsWith("$")) { - className = (String) context.getVariable(className); - info.target.getItem().setIdentifier(new Identifier(className)); + String typeName = info.target.getItem().getIdentifier().getStringValue(); + if (typeName.startsWith("$")) { + typeName = (String) context.getVariable(typeName); + info.target.getItem().setIdentifier(new Identifier(typeName)); } Schema schema = context.getDatabase().getSchema(); - DocumentType type = schema.getType(className); + DocumentType type = schema.getType(typeName); info.whereClause.getBaseExpression().rewriteIndexChainsAsSubqueries(context, type); } diff --git a/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java b/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java index 8c4f1b97c5..e45b9e7dd3 100644 --- a/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java +++ b/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java @@ -291,7 +291,8 @@ public void testReadTypeFromVariable() { LET source = $sources[0]; LET type = $source.vType; LET target = SELECT FROM $type WHERE id = '9'; - LET e = CREATE EDGE HasSource FROM $target TO $source IF NOT EXISTS ; + LET edgeType = 'HasSource'; + LET e = CREATE EDGE $edgeType FROM $target TO $source IF NOT EXISTS ; COMMIT; RETURN $e; """); From d1fab6ef7861e055b2cb2bd3836288eb007efe87 Mon Sep 17 00:00:00 2001 From: Roberto Franchini Date: Fri, 5 Sep 2025 14:32:05 +0200 Subject: [PATCH 04/11] fix: handle nested property access in SQL command context --- .../query/sql/executor/BasicCommandContext.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/engine/src/main/java/com/arcadedb/query/sql/executor/BasicCommandContext.java b/engine/src/main/java/com/arcadedb/query/sql/executor/BasicCommandContext.java index 500dfa75fa..f8ae31c278 100644 --- a/engine/src/main/java/com/arcadedb/query/sql/executor/BasicCommandContext.java +++ b/engine/src/main/java/com/arcadedb/query/sql/executor/BasicCommandContext.java @@ -123,9 +123,15 @@ public Object getVariable(String name, final Object defaultValue) { String fieldName = null; if (name.contains(".")) { - String[] parts = name.split("\\."); + final String[] parts = name.split("\\."); + if (parts.length > 2) { + throw new com.arcadedb.exception.CommandSQLParsingException( + "Nested property access is not supported in this context: " + name); + } name = parts[0]; - fieldName = parts[1]; + if (parts.length > 1) { + fieldName = parts[1]; + } } if (name.equalsIgnoreCase("CONTEXT")) From 92ffb79d8506adb07944e0e7e66cb41657e6aab0 Mon Sep 17 00:00:00 2001 From: Roberto Franchini Date: Mon, 8 Sep 2025 14:17:29 +0200 Subject: [PATCH 05/11] feat: enhance dynamic variable handling in SQL script execution --- .../query/sql/SQLScriptQueryEngine.java | 3 +- .../CreateVertexExecutionPlanner.java | 4 -- .../sql/executor/InsertExecutionPlanner.java | 14 +++++-- .../com/arcadedb/query/sql/BatchTest.java | 40 ++++++++++++++----- 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/engine/src/main/java/com/arcadedb/query/sql/SQLScriptQueryEngine.java b/engine/src/main/java/com/arcadedb/query/sql/SQLScriptQueryEngine.java index 4e451adcbc..b0580c3a19 100644 --- a/engine/src/main/java/com/arcadedb/query/sql/SQLScriptQueryEngine.java +++ b/engine/src/main/java/com/arcadedb/query/sql/SQLScriptQueryEngine.java @@ -213,8 +213,9 @@ private ResultSet executeInternal(final List statements, final Comman throw new CommandSQLParsingException("Found COMMIT statement without a BEGIN"); } - if (stm instanceof LetStatement letStatement) + if (stm instanceof LetStatement letStatement) { scriptContext.declareScriptVariable(letStatement.getVariableName().getStringValue()); + } } return new LocalResultSet(plan); diff --git a/engine/src/main/java/com/arcadedb/query/sql/executor/CreateVertexExecutionPlanner.java b/engine/src/main/java/com/arcadedb/query/sql/executor/CreateVertexExecutionPlanner.java index 3f28d6af16..fc869b8b73 100644 --- a/engine/src/main/java/com/arcadedb/query/sql/executor/CreateVertexExecutionPlanner.java +++ b/engine/src/main/java/com/arcadedb/query/sql/executor/CreateVertexExecutionPlanner.java @@ -43,10 +43,6 @@ public CreateVertexExecutionPlanner(final CreateVertexStatement statement) { @Override public InsertExecutionPlan createExecutionPlan(final CommandContext context) { - if (targetType.getStringValue().startsWith("$")) { - String variable = (String) context.getVariable(targetType.getStringValue()); - targetType = new Identifier(variable); - } final InsertExecutionPlan prev = super.createExecutionPlan(context); final List steps = new ArrayList<>(prev.getSteps()); diff --git a/engine/src/main/java/com/arcadedb/query/sql/executor/InsertExecutionPlanner.java b/engine/src/main/java/com/arcadedb/query/sql/executor/InsertExecutionPlanner.java index a077b32389..6197b285fc 100644 --- a/engine/src/main/java/com/arcadedb/query/sql/executor/InsertExecutionPlanner.java +++ b/engine/src/main/java/com/arcadedb/query/sql/executor/InsertExecutionPlanner.java @@ -55,6 +55,12 @@ public InsertExecutionPlanner(final InsertStatement statement) { } public InsertExecutionPlan createExecutionPlan(final CommandContext context) { + + if (targetType.getStringValue().startsWith("$")) { + String variable = (String) context.getVariable(targetType.getStringValue()); + targetType = new Identifier(variable); + } + final InsertExecutionPlan result = new InsertExecutionPlan(context); if (selectStatement != null) { @@ -62,7 +68,7 @@ public InsertExecutionPlan createExecutionPlan(final CommandContext context) { } else { handleCreateRecord(result, this.insertBody, context); } - handleTargetClass(result, targetType, context); + handleTargetType(result, targetType, context); handleSetFields(result, insertBody, context); if (targetBucket != null) { String name = targetBucket.getBucketName(); @@ -113,9 +119,9 @@ private void handleSetFields(final InsertExecutionPlan result, final InsertBody } } - private void handleTargetClass(final InsertExecutionPlan result, final Identifier targetClass, final CommandContext context) { - if (targetClass != null) - result.chain(new SetDocumentStepStep(targetClass, context)); + private void handleTargetType(final InsertExecutionPlan result, final Identifier targetType, final CommandContext context) { + if (targetType != null) + result.chain(new SetDocumentStepStep(targetType, context)); } private void handleCreateRecord(final InsertExecutionPlan result, final InsertBody body, final CommandContext context) { diff --git a/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java b/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java index e45b9e7dd3..6c8cb2217b 100644 --- a/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java +++ b/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java @@ -274,23 +274,43 @@ public void testFromSingleResultReadValueFromField() { } @Test - public void testReadTypeFromVariable() { - database.command("sql", "CREATE VERTEX TYPE V1"); - database.command("sql", "CREATE VERTEX TYPE V2"); - database.command("sql", "CREATE EDGE TYPE HasSource"); + public void testDynamicDocumentTypeName() { + database.command("sql", "CREATE DOCUMENT TYPE TheDoc"); + + database.transaction(() -> { + database.command("sqlscript", """ + LET docType = 'TheDoc'; + LET d =INSERT INTO $docType SET id = 1; + """); + }); + + assertThat(database.query("sql", "SELECT count() AS value FROM TheDoc").next().getProperty("value")).isEqualTo(1); + } + @Test + public void testDynamicGraphTypesNames() { + database.command("sql", "CREATE DOCUMENT TYPE TheDoc"); + database.transaction(() -> { - for (int i = 0; i < 10; i++) { - database.command("sql", "INSERT INTO V1 set id = ? , vType = ? ", i, "V2"); - database.command("sql", "INSERT INTO V2 set id = ? ", i); - } + database.command("sqlscript", """ + LET numbers = [1, 2, 3]; + LET vTypes = ['V1', 'V2']; + FOREACH ($i IN $numbers) { + FOREACH ($vType IN $vTypes) { + CREATE VERTEX $vType SET id = $i, vType = 'V2'; + } + } + """); }); + assertThat(database.query("sql", "SELECT count() AS value FROM V1").next().getProperty("value")).isEqualTo(3); + assertThat(database.query("sql", "SELECT count() AS value FROM V2").next().getProperty("value")).isEqualTo(3); + final ResultSet resultSet = database.command("sqlscript", """ BEGIN; LET sources = SELECT FROM V1 WHERE id = '1'; LET source = $sources[0]; LET type = $source.vType; - LET target = SELECT FROM $type WHERE id = '9'; + LET target = SELECT FROM $type WHERE id = '3'; LET edgeType = 'HasSource'; LET e = CREATE EDGE $edgeType FROM $target TO $source IF NOT EXISTS ; COMMIT; @@ -300,7 +320,7 @@ public void testReadTypeFromVariable() { assertThat(resultSet.hasNext()).isTrue(); Edge edge = resultSet.next().getEdge().get(); assertThat(edge.getInVertex().getInteger("id")).isEqualTo(1); - assertThat(edge.getOutVertex().getInteger("id")).isEqualTo(9); + assertThat(edge.getOutVertex().getInteger("id")).isEqualTo(3); } From 8b9abd880f4dfd8c2ef9dd8bda11be4444df5b5b Mon Sep 17 00:00:00 2001 From: Roberto Franchini Date: Mon, 8 Sep 2025 14:59:00 +0200 Subject: [PATCH 06/11] feat: update dynamic naming for SQL script types in BatchTest --- engine/src/test/java/com/arcadedb/query/sql/BatchTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java b/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java index 6c8cb2217b..8d855182e6 100644 --- a/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java +++ b/engine/src/test/java/com/arcadedb/query/sql/BatchTest.java @@ -288,7 +288,9 @@ public void testDynamicDocumentTypeName() { } @Test public void testDynamicGraphTypesNames() { - database.command("sql", "CREATE DOCUMENT TYPE TheDoc"); + database.command("sql", "CREATE VERTEX TYPE V1"); + database.command("sql", "CREATE VERTEX TYPE V2"); + database.command("sql", "CREATE EDGE TYPE HasSource"); database.transaction(() -> { database.command("sqlscript", """ From 439cc27ac3a5bba211455619d1307defdaa85eed Mon Sep 17 00:00:00 2001 From: Roberto Franchini Date: Mon, 8 Sep 2025 16:15:20 +0200 Subject: [PATCH 07/11] feat: implement dynamic variable handling for SQL script types --- .../parser/CreateTypeAbstractStatement.java | 7 ++++ .../java/com/arcadedb/query/sql/DDLTest.java | 34 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/engine/src/main/java/com/arcadedb/query/sql/parser/CreateTypeAbstractStatement.java b/engine/src/main/java/com/arcadedb/query/sql/parser/CreateTypeAbstractStatement.java index c0f0394c42..91d5a95cd6 100644 --- a/engine/src/main/java/com/arcadedb/query/sql/parser/CreateTypeAbstractStatement.java +++ b/engine/src/main/java/com/arcadedb/query/sql/parser/CreateTypeAbstractStatement.java @@ -67,6 +67,12 @@ public CreateTypeAbstractStatement(final int id) { @Override public ResultSet executeDDL(final CommandContext context) { + Identifier prevName= name; + if (name.getStringValue().startsWith("$")) { + String variable = (String) context.getVariable(name.getStringValue()); + name = new Identifier(variable); + } + final Schema schema = context.getDatabase().getSchema(); if (schema.existsType(name.getStringValue())) { if (ifNotExists) { @@ -88,6 +94,7 @@ public ResultSet executeDDL(final CommandContext context) { for (final DocumentType c : superclasses) type.addSuperType(c); + name = prevName; return new InternalResultSet(result); } diff --git a/engine/src/test/java/com/arcadedb/query/sql/DDLTest.java b/engine/src/test/java/com/arcadedb/query/sql/DDLTest.java index a41c8a44ea..210adefdd3 100644 --- a/engine/src/test/java/com/arcadedb/query/sql/DDLTest.java +++ b/engine/src/test/java/com/arcadedb/query/sql/DDLTest.java @@ -19,6 +19,8 @@ package com.arcadedb.query.sql; import com.arcadedb.TestHelper; +import com.arcadedb.query.sql.executor.ResultSet; +import com.arcadedb.schema.Schema; import org.junit.jupiter.api.Test; import java.util.stream.IntStream; @@ -36,6 +38,38 @@ protected void beginTest() { } + @Test + void testDynamicSchemaCreation() { + database.command("sqlscript", """ + BEGIN; + LET vTypes = ['V1', 'V2', 'V3']; + FOREACH ($vType IN $vTypes) { + CREATE VERTEX TYPE $vType EXTENDS V; + } + LET eTypes = ['E1', 'E2', 'E3']; + FOREACH ($eType IN $eTypes) { + CREATE EDGE TYPE $eType ; + } + LET dTypes = ['D1', 'D2', 'D3']; + FOREACH ($dType IN $dTypes) { + CREATE DOCUMENT TYPE $dType ; + } + COMMIT; + """); + + Schema schema = database.getSchema(); + assertThat(schema.existsType("V1")).isTrue(); + assertThat(schema.existsType("V2")).isTrue(); + assertThat(schema.existsType("V3")).isTrue(); + assertThat(schema.existsType("D1")).isTrue(); + assertThat(schema.existsType("D2")).isTrue(); + assertThat(schema.existsType("D3")).isTrue(); + assertThat(schema.existsType("E1")).isTrue(); + assertThat(schema.existsType("E2")).isTrue(); + assertThat(schema.existsType("E3")).isTrue(); + + } + @Test void testGraphWithSql() { From e943a66ac68203e2b87e5d3572e1c6e35789e4a5 Mon Sep 17 00:00:00 2001 From: Roberto Franchini Date: Mon, 8 Sep 2025 16:50:00 +0200 Subject: [PATCH 08/11] feat: enhance dynamic naming and variable handling in SQL script execution --- .../sql/parser/CreateIndexStatement.java | 25 ++++++++++++++----- .../sql/parser/CreatePropertyStatement.java | 7 ++++++ .../com/arcadedb/schema/TypeIndexBuilder.java | 1 + .../java/com/arcadedb/query/sql/DDLTest.java | 19 +++++++++++++- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/engine/src/main/java/com/arcadedb/query/sql/parser/CreateIndexStatement.java b/engine/src/main/java/com/arcadedb/query/sql/parser/CreateIndexStatement.java index 344b5268bb..1744efcfb4 100644 --- a/engine/src/main/java/com/arcadedb/query/sql/parser/CreateIndexStatement.java +++ b/engine/src/main/java/com/arcadedb/query/sql/parser/CreateIndexStatement.java @@ -52,21 +52,32 @@ public CreateIndexStatement(final int id) { @Override public void validate() throws CommandSQLParsingException { - final String typeAsString = type.getStringValue(); - if (typeAsString.equalsIgnoreCase("FULL_TEXT")) + final String typeAsString = type.getStringValue().toUpperCase(); + switch (typeAsString) { + case "FULL_TEXT" -> { ; - else if (typeAsString.equalsIgnoreCase("UNIQUE")) + } + case "UNIQUE" -> { ; - else if (typeAsString.equalsIgnoreCase("NOTUNIQUE")) + } + case "NOTUNIQUE" -> { ; - else - throw new CommandSQLParsingException("Index type '" + typeAsString + "' is not supported"); + } + default -> throw new CommandSQLParsingException("Index type '" + typeAsString + "' is not supported"); + } } @Override public ResultSet executeDDL(final CommandContext context) { final Database database = context.getDatabase(); + Identifier prevName= typeName; + if (typeName.getStringValue().startsWith("$")) { + String variable = (String) context.getVariable(typeName.getStringValue()); + typeName = new Identifier(variable); + name = null; + } + if (name == null) // GENERATE THE NAME AUTOMATICALLY name = new Identifier(typeName.getStringValue() + propertyList.toString().replace(", ", ",")); @@ -114,6 +125,8 @@ else if (typeAsString.equalsIgnoreCase("UNIQUE")) { } }).create(); + typeName = prevName; + final InternalResultSet rs = new InternalResultSet(); final ResultInternal result = new ResultInternal(context.getDatabase()); result.setProperty("operation", "create index"); diff --git a/engine/src/main/java/com/arcadedb/query/sql/parser/CreatePropertyStatement.java b/engine/src/main/java/com/arcadedb/query/sql/parser/CreatePropertyStatement.java index 2a9576fbd3..206f433b6d 100644 --- a/engine/src/main/java/com/arcadedb/query/sql/parser/CreatePropertyStatement.java +++ b/engine/src/main/java/com/arcadedb/query/sql/parser/CreatePropertyStatement.java @@ -61,6 +61,12 @@ public ResultSet executeDDL(final CommandContext context) { private void executeInternal(final CommandContext context, final ResultInternal result) { final Database db = context.getDatabase(); + Identifier prevType= typeName; + if (typeName.getStringValue().startsWith("$")) { + String variable = (String) context.getVariable(typeName.getStringValue()); + typeName = new Identifier(variable); + } + final DocumentType typez = db.getSchema().getType(typeName.getStringValue()); if (typez == null) throw new CommandExecutionException("Type '" + typeName.getStringValue() + "' not found"); @@ -81,6 +87,7 @@ private void executeInternal(final CommandContext context, final ResultInternal final Object val = attr.setOnProperty(internalProp, context); result.setProperty(attr.settingName.getStringValue(), val); } + typeName = prevType; } @Override diff --git a/engine/src/main/java/com/arcadedb/schema/TypeIndexBuilder.java b/engine/src/main/java/com/arcadedb/schema/TypeIndexBuilder.java index 0012bbffe3..522a15e7b4 100644 --- a/engine/src/main/java/com/arcadedb/schema/TypeIndexBuilder.java +++ b/engine/src/main/java/com/arcadedb/schema/TypeIndexBuilder.java @@ -30,6 +30,7 @@ import com.arcadedb.index.IndexException; import com.arcadedb.index.IndexInternal; import com.arcadedb.index.TypeIndex; +import com.arcadedb.query.sql.parser.Identifier; import com.arcadedb.security.SecurityDatabaseUser; import java.util.*; diff --git a/engine/src/test/java/com/arcadedb/query/sql/DDLTest.java b/engine/src/test/java/com/arcadedb/query/sql/DDLTest.java index 210adefdd3..cc7b56effd 100644 --- a/engine/src/test/java/com/arcadedb/query/sql/DDLTest.java +++ b/engine/src/test/java/com/arcadedb/query/sql/DDLTest.java @@ -19,7 +19,6 @@ package com.arcadedb.query.sql; import com.arcadedb.TestHelper; -import com.arcadedb.query.sql.executor.ResultSet; import com.arcadedb.schema.Schema; import org.junit.jupiter.api.Test; @@ -42,31 +41,49 @@ protected void beginTest() { void testDynamicSchemaCreation() { database.command("sqlscript", """ BEGIN; + LET vTypes = ['V1', 'V2', 'V3']; FOREACH ($vType IN $vTypes) { CREATE VERTEX TYPE $vType EXTENDS V; } + LET eTypes = ['E1', 'E2', 'E3']; FOREACH ($eType IN $eTypes) { CREATE EDGE TYPE $eType ; } + LET dTypes = ['D1', 'D2', 'D3']; FOREACH ($dType IN $dTypes) { CREATE DOCUMENT TYPE $dType ; } + + LET types = ['V1', 'V2', 'V3','E1', 'E2', 'E3','D1', 'D2', 'D3']; + FOREACH ($type IN $types) { + CREATE PROPERTY $type.id STRING; + CREATE INDEX ON $type (id) UNIQUE NULL_STRATEGY SKIP; + } COMMIT; """); Schema schema = database.getSchema(); assertThat(schema.existsType("V1")).isTrue(); + assertThat(schema.existsIndex("V1[id]")).isTrue(); assertThat(schema.existsType("V2")).isTrue(); + assertThat(schema.existsIndex("V2[id]")).isTrue(); assertThat(schema.existsType("V3")).isTrue(); + assertThat(schema.existsIndex("V3[id]")).isTrue(); assertThat(schema.existsType("D1")).isTrue(); + assertThat(schema.existsIndex("D1[id]")).isTrue(); assertThat(schema.existsType("D2")).isTrue(); + assertThat(schema.existsIndex("D2[id]")).isTrue(); assertThat(schema.existsType("D3")).isTrue(); + assertThat(schema.existsIndex("D3[id]")).isTrue(); assertThat(schema.existsType("E1")).isTrue(); + assertThat(schema.existsIndex("E1[id]")).isTrue(); assertThat(schema.existsType("E2")).isTrue(); + assertThat(schema.existsIndex("E2[id]")).isTrue(); assertThat(schema.existsType("E3")).isTrue(); + assertThat(schema.existsIndex("E3[id]")).isTrue(); } From a4fd3926775f684c9c30849cb7c122d5baacfb90 Mon Sep 17 00:00:00 2001 From: Roberto Franchini Date: Mon, 8 Sep 2025 16:59:03 +0200 Subject: [PATCH 09/11] feat: enhance dynamic naming and variable handling in SQL script execution --- engine/src/test/java/com/arcadedb/query/sql/DDLTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/src/test/java/com/arcadedb/query/sql/DDLTest.java b/engine/src/test/java/com/arcadedb/query/sql/DDLTest.java index cc7b56effd..eefa29e203 100644 --- a/engine/src/test/java/com/arcadedb/query/sql/DDLTest.java +++ b/engine/src/test/java/com/arcadedb/query/sql/DDLTest.java @@ -49,12 +49,12 @@ void testDynamicSchemaCreation() { LET eTypes = ['E1', 'E2', 'E3']; FOREACH ($eType IN $eTypes) { - CREATE EDGE TYPE $eType ; + CREATE EDGE TYPE $eType EXTENDS E; } LET dTypes = ['D1', 'D2', 'D3']; FOREACH ($dType IN $dTypes) { - CREATE DOCUMENT TYPE $dType ; + CREATE DOCUMENT TYPE $dType ; } LET types = ['V1', 'V2', 'V3','E1', 'E2', 'E3','D1', 'D2', 'D3']; From 49a3d24256b5d1d5524665ac1ac1db8689a9f784 Mon Sep 17 00:00:00 2001 From: Roberto Franchini Date: Mon, 8 Sep 2025 17:01:10 +0200 Subject: [PATCH 10/11] feat: improve null safety in targetType handling for SQL execution planning --- .../arcadedb/query/sql/executor/InsertExecutionPlanner.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/engine/src/main/java/com/arcadedb/query/sql/executor/InsertExecutionPlanner.java b/engine/src/main/java/com/arcadedb/query/sql/executor/InsertExecutionPlanner.java index 6197b285fc..6606ebc52b 100644 --- a/engine/src/main/java/com/arcadedb/query/sql/executor/InsertExecutionPlanner.java +++ b/engine/src/main/java/com/arcadedb/query/sql/executor/InsertExecutionPlanner.java @@ -28,7 +28,8 @@ import com.arcadedb.query.sql.parser.SelectStatement; import com.arcadedb.query.sql.parser.UpdateItem; -import java.util.*; +import java.util.ArrayList; +import java.util.List; /** * Created by luigidellaquila on 08/08/16. @@ -56,7 +57,7 @@ public InsertExecutionPlanner(final InsertStatement statement) { public InsertExecutionPlan createExecutionPlan(final CommandContext context) { - if (targetType.getStringValue().startsWith("$")) { + if (targetType != null && targetType.getStringValue().startsWith("$")) { String variable = (String) context.getVariable(targetType.getStringValue()); targetType = new Identifier(variable); } From 261d1bb3a9df08fff74c0a41b1d4264554a9933a Mon Sep 17 00:00:00 2001 From: Roberto Franchini Date: Mon, 8 Sep 2025 17:56:47 +0200 Subject: [PATCH 11/11] feat: add dynamic SQL script for schema creation and property indexing --- .../e2e/RemoteDatabaseJavaApiTest.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/e2e/src/test/java/com/arcadedb/e2e/RemoteDatabaseJavaApiTest.java b/e2e/src/test/java/com/arcadedb/e2e/RemoteDatabaseJavaApiTest.java index af98a2efc6..a5231da1a2 100644 --- a/e2e/src/test/java/com/arcadedb/e2e/RemoteDatabaseJavaApiTest.java +++ b/e2e/src/test/java/com/arcadedb/e2e/RemoteDatabaseJavaApiTest.java @@ -24,6 +24,7 @@ import com.arcadedb.query.sql.executor.Result; import com.arcadedb.query.sql.executor.ResultSet; import com.arcadedb.remote.RemoteDatabase; +import com.arcadedb.schema.Schema; import com.arcadedb.utility.CollectionUtils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -166,6 +167,47 @@ void renameTypeAndAliases() { } + @Test + void createSchemaWithDynamicSqlScript() { + database.command("sqlscript", """ + BEGIN; + + LET vTypes = ['V1', 'V2', 'V3']; + FOREACH ($vType IN $vTypes) { + CREATE VERTEX TYPE $vType; + } + + LET eTypes = ['E1', 'E2', 'E3']; + FOREACH ($eType IN $eTypes) { + CREATE EDGE TYPE $eType; + } + + LET dTypes = ['D1', 'D2', 'D3']; + FOREACH ($dType IN $dTypes) { + CREATE DOCUMENT TYPE $dType ; + } + + LET types = ['V1', 'V2', 'V3','E1', 'E2', 'E3','D1', 'D2', 'D3']; + FOREACH ($type IN $types) { + CREATE PROPERTY $type.id STRING; + CREATE INDEX ON $type (id) UNIQUE NULL_STRATEGY SKIP; + } + COMMIT; + """); + + Schema schema = database.getSchema(); + System.out.println("schema.toString() = " + schema.toString()); + assertThat(schema.existsType("V1")).isTrue(); + assertThat(schema.existsType("V2")).isTrue(); + assertThat(schema.existsType("V3")).isTrue(); + assertThat(schema.existsType("D1")).isTrue(); + assertThat(schema.existsType("D2")).isTrue(); + assertThat(schema.existsType("D3")).isTrue(); + assertThat(schema.existsType("E1")).isTrue(); + assertThat(schema.existsType("E2")).isTrue(); + assertThat(schema.existsType("E3")).isTrue(); + } + @Test @Disabled void testMultipleInsert() throws SQLException, ClassNotFoundException {