From 636847b1cbc8c0173af812565c789b2577ebfaa8 Mon Sep 17 00:00:00 2001 From: Bob Garner Date: Sat, 8 Jul 2023 04:12:11 -0700 Subject: [PATCH 01/12] Added fatal log when no default domain is set and it needs to use it. --- .../transform/template/tree/FTTransformSession.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/entityc/compiler/transform/template/tree/FTTransformSession.java b/src/main/java/org/entityc/compiler/transform/template/tree/FTTransformSession.java index dba7326..dde29bc 100644 --- a/src/main/java/org/entityc/compiler/transform/template/tree/FTTransformSession.java +++ b/src/main/java/org/entityc/compiler/transform/template/tree/FTTransformSession.java @@ -34,6 +34,8 @@ import java.util.Stack; import java.util.function.Predicate; +import static org.entityc.compiler.transform.template.tree.FTLog.Level.FATAL; + public class FTTransformSession { private static final List kUnasignable = Arrays.asList("null", "true", "false"); @@ -72,7 +74,11 @@ public FTTransformSession(MTRoot root, MTConfiguration configuration, FTTemplate addReadonlyNamedValue("space", space); addReadonlyNamedValue("rootTemplate", templateTransform); if (template.getDefaultDomainName() != null) { - addReadonlyNamedValue("domain", space.getDomainWithName(template.getDefaultDomainName())); + MTDomain defaultDomain = space.getDomainWithName(template.getDefaultDomainName()); + if (defaultDomain == null) { + ECLog.logFatal("Unable to find default name named: " + template.getDefaultDomainName()); + } + addReadonlyNamedValue("domain", defaultDomain); } setValue("__assert_info", false); setValue("__assert_debug", false); From 6770681e3567782ad4f7883dd36be32799e66116 Mon Sep 17 00:00:00 2001 From: Bob Garner Date: Thu, 13 Jul 2023 13:58:00 -0700 Subject: [PATCH 02/12] Added nameas filter to provide direct access to naming methods. --- docs/etl/ETL.md | 20 +++++++ .../org/entityc/compiler/EntityCompiler.java | 4 +- .../compiler/model/domain/MTNamingMethod.java | 5 ++ .../template/tree/filter/FTNameAsFilter.java | 58 +++++++++++++++++++ 4 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/entityc/compiler/transform/template/tree/filter/FTNameAsFilter.java diff --git a/docs/etl/ETL.md b/docs/etl/ETL.md index 32624dd..3732976 100644 --- a/docs/etl/ETL.md +++ b/docs/etl/ETL.md @@ -130,6 +130,7 @@ Here is the full list of filters: | [`name`](#filter_detail_name) | This simply calls `getName()` on the input. It is more of a convenient way to get the name by using a filter. | | [`path`](#filter_detail_path) | This will convert a string or namespace object into a string where by a '/' character is used as a delimiter instead of a '.'. This is useful when you need to convert a namespace into a filepath. | | [`plural`](#filter_detail_plural) | This will attempt to pluralize the last word of the input string. If it can't determine the pluralization it may just return the same string. | +| [`rename`](#filter_detail_rename) | Places underscore between words then forces all characters to be lowercase. | | [`reverse`](#filter_detail_reverse) | Given a collection of objects, this will return a collection that has the reverse order of the input. | | [`sort`](#filter_detail_sort) | Given a collection of objects, this will return a collection that is sorted by name. This is useful when generating code that is consistent each time in terms of the order of objects in the output. | | [`title`](#filter_detail_title) | Given a string of words in camel case format, this will capitalize each word in the string except those words that are typically not capitalized in a title (such as 'of', 'the'. 'and', etc.). | @@ -443,6 +444,25 @@ Valid inputs for this filter are:
+ +##### Filter: `rename` + +Places underscore between words then forces all characters to be lowercase. + +Valid inputs for this filter are: + +| Class of Valid Input | Description | +|---|---| +| `String` | The string to change into an underscore lowercase format. | + +This filter has the following parameters: + +| Usage with Parameter | Description | +|---|---| +| `rename:`*method* | Specifies the renaming method: standard, underscore, underscoreLowercase, underscoreUppercase, lowercase, uppercase, capitalize, dashesLowercase, dashesUppercase, parentPrefix | + +
+ ##### Filter: `reverse` diff --git a/src/main/java/org/entityc/compiler/EntityCompiler.java b/src/main/java/org/entityc/compiler/EntityCompiler.java index edf072d..b7d5846 100644 --- a/src/main/java/org/entityc/compiler/EntityCompiler.java +++ b/src/main/java/org/entityc/compiler/EntityCompiler.java @@ -52,8 +52,8 @@ public class EntityCompiler { - public static final String COMPILER_VERSION = "0.15.0"; - public static final String LANGUAGE_VERSION = "0.12.6"; + public static final String COMPILER_VERSION = "0.16.0"; + public static final String LANGUAGE_VERSION = "0.13.0"; private static final Map defineValues = new HashMap<>(); private static final Set templateSearchPath = new HashSet<>(); private static CommandLine commandLine; diff --git a/src/main/java/org/entityc/compiler/model/domain/MTNamingMethod.java b/src/main/java/org/entityc/compiler/model/domain/MTNamingMethod.java index 7a76f13..63fefe0 100644 --- a/src/main/java/org/entityc/compiler/model/domain/MTNamingMethod.java +++ b/src/main/java/org/entityc/compiler/model/domain/MTNamingMethod.java @@ -6,6 +6,7 @@ package org.entityc.compiler.model.domain; +import org.entityc.compiler.util.ECLog; import org.entityc.compiler.util.ECStringUtil; public enum MTNamingMethod { @@ -39,6 +40,10 @@ public static MTNamingMethod fromName(String name) { return null; } + public String getName() { + return name; + } + public String getDelimiter() { return delimiter; } diff --git a/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTNameAsFilter.java b/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTNameAsFilter.java new file mode 100644 index 0000000..4da6eb7 --- /dev/null +++ b/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTNameAsFilter.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019-2022 The EntityC Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.md file in the project root. + */ + +package org.entityc.compiler.transform.template.tree.filter; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.entityc.compiler.model.domain.MTNamingMethod; +import org.entityc.compiler.transform.template.tree.FTTransformSession; +import org.entityc.compiler.transform.template.tree.expression.FTExpression; +import org.entityc.compiler.transform.template.tree.expression.FTOperand; +import org.entityc.compiler.util.ECLog; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public class FTNameAsFilter extends FTFilter { + + public FTNameAsFilter() { + super(null, "nameas", + "Places underscore between words then forces all characters to be lowercase."); + this.addFilterParam(new FTFilterParam("method", + "Specifies the naming method: " + String.join(", ", Arrays.stream(MTNamingMethod.values()).map(MTNamingMethod::getName).toArray(String[]::new)))); + addSingleInputType(String.class, "The string to change into an underscore lowercase format."); + } + + @Override + public Object filter(ParserRuleContext ctx, FTTransformSession session, Object input, List paramValues, Map options) { + checkInput(ctx, input, paramValues, options); + + if (paramValues.size() == 0) { + ECLog.logFatal(ctx, "Must specify a naming method. Valid values are: " + String.join(", ", Arrays.stream(MTNamingMethod.values()).map(MTNamingMethod::getName).toArray(String[]::new))); + } + + if (input instanceof String) { + String inputString = (String) input; + FTExpression methodParam = paramValues.get(0); + String methodName = null; + if (methodParam.isOperand()) { + methodName = ((FTOperand) methodParam).getName(); + } + else + { + ECLog.logFatal(ctx, "Naming method must be specified directly. For example: entity|nameas:uppercase"); + } + MTNamingMethod namingMethod = MTNamingMethod.fromName(methodName); + if (namingMethod == null) { + ECLog.logFatal(ctx, "Unknown naming method: " + methodName); + } + return namingMethod.rename(inputString); + } + + return null; + } +} From f0dd79ed4099f2812f0cd174c461dfd853c317bd Mon Sep 17 00:00:00 2001 From: Bob Garner Date: Tue, 1 Aug 2023 07:18:40 -0700 Subject: [PATCH 03/12] More bug fixes and added getImplicitToEntity() method on relationship. This method will make it easier for templates to get the many-to-many entity via the implicit table added. --- docs/emc/EMC_entity.md | 6 +++ docs/etl/ETL.md | 40 +++++++++---------- .../model/domain/MTDERelationship.java | 4 +- .../compiler/model/entity/MTRelationship.java | 12 ++++++ .../transform/MTVImplicitTransform.java | 13 +++--- 5 files changed, 48 insertions(+), 27 deletions(-) diff --git a/docs/emc/EMC_entity.md b/docs/emc/EMC_entity.md index 33b3b7f..ae35c7e 100644 --- a/docs/emc/EMC_entity.md +++ b/docs/emc/EMC_entity.md @@ -1226,6 +1226,12 @@ Returns the "from" part of the relationship which references the entity in which
+#### `MTEntity` **`implicitToEntity`** + +Gets the entity on the other side of an implicit many-to-many entity. + +
+ #### `boolean` **`isImplicit`** Indicates whether the relationship was created because although it was not declared it can be implied based on relationships declared to this entity. diff --git a/docs/etl/ETL.md b/docs/etl/ETL.md index 3732976..61cc871 100644 --- a/docs/etl/ETL.md +++ b/docs/etl/ETL.md @@ -128,9 +128,9 @@ Here is the full list of filters: | [`lowercase`](#filter_detail_lowercase) | Forces all characters of the input to be lowercase. | | [`map`](#filter_detail_map) | This filter is probably the most complicated one but can be very powerful in helping to pattern match an expression at its input with one provided as a parameter. When the expressions match, it not only returns true but also maps operands from the input expression to the parameter expression. | | [`name`](#filter_detail_name) | This simply calls `getName()` on the input. It is more of a convenient way to get the name by using a filter. | +| [`nameas`](#filter_detail_nameas) | Places underscore between words then forces all characters to be lowercase. | | [`path`](#filter_detail_path) | This will convert a string or namespace object into a string where by a '/' character is used as a delimiter instead of a '.'. This is useful when you need to convert a namespace into a filepath. | | [`plural`](#filter_detail_plural) | This will attempt to pluralize the last word of the input string. If it can't determine the pluralization it may just return the same string. | -| [`rename`](#filter_detail_rename) | Places underscore between words then forces all characters to be lowercase. | | [`reverse`](#filter_detail_reverse) | Given a collection of objects, this will return a collection that has the reverse order of the input. | | [`sort`](#filter_detail_sort) | Given a collection of objects, this will return a collection that is sorted by name. This is useful when generating code that is consistent each time in terms of the order of objects in the output. | | [`title`](#filter_detail_title) | Given a string of words in camel case format, this will capitalize each word in the string except those words that are typically not capitalized in a title (such as 'of', 'the'. 'and', etc.). | @@ -417,49 +417,49 @@ Valid inputs for this filter are:
- -##### Filter: `path` + +##### Filter: `nameas` -This will convert a string or namespace object into a string where by a '/' character is used as a delimiter instead of a '.'. This is useful when you need to convert a namespace into a filepath. +Places underscore between words then forces all characters to be lowercase. Valid inputs for this filter are: | Class of Valid Input | Description | |---|---| -| `String` | The string that represents a period-delimited namespace (for instance: com.example.something). | -| `MTNamespace` | A namespace object that is obtained from an object in your model. | +| `String` | The string to change into an underscore lowercase format. | + +This filter has the following parameters: + +| Usage with Parameter | Description | +|---|---| +| `nameas:`*method* | Specifies the naming method: standard, underscore, underscoreLowercase, underscoreUppercase, lowercase, uppercase, capitalize, dashesLowercase, dashesUppercase, parentPrefix |
- -##### Filter: `plural` + +##### Filter: `path` -This will attempt to pluralize the last word of the input string. If it can't determine the pluralization it may just return the same string. +This will convert a string or namespace object into a string where by a '/' character is used as a delimiter instead of a '.'. This is useful when you need to convert a namespace into a filepath. Valid inputs for this filter are: | Class of Valid Input | Description | |---|---| -| `String` | The string to pluralize. | +| `String` | The string that represents a period-delimited namespace (for instance: com.example.something). | +| `MTNamespace` | A namespace object that is obtained from an object in your model. |
- -##### Filter: `rename` + +##### Filter: `plural` -Places underscore between words then forces all characters to be lowercase. +This will attempt to pluralize the last word of the input string. If it can't determine the pluralization it may just return the same string. Valid inputs for this filter are: | Class of Valid Input | Description | |---|---| -| `String` | The string to change into an underscore lowercase format. | - -This filter has the following parameters: - -| Usage with Parameter | Description | -|---|---| -| `rename:`*method* | Specifies the renaming method: standard, underscore, underscoreLowercase, underscoreUppercase, lowercase, uppercase, capitalize, dashesLowercase, dashesUppercase, parentPrefix | +| `String` | The string to pluralize. |
diff --git a/src/main/java/org/entityc/compiler/model/domain/MTDERelationship.java b/src/main/java/org/entityc/compiler/model/domain/MTDERelationship.java index aaf1946..33a74f6 100644 --- a/src/main/java/org/entityc/compiler/model/domain/MTDERelationship.java +++ b/src/main/java/org/entityc/compiler/model/domain/MTDERelationship.java @@ -99,13 +99,13 @@ public void setDomainEntity(MTDEntity domainEntity) { @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "Indicates if this relationship is a one-to-many.") public boolean isOneToMany() { - return relationship.isOneToMany(); + return relationship != null && relationship.isOneToMany(); } @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "Indicates if this relationship is a many-to-many.") public boolean isManyToMany() { - return relationship.isManyToMany(); + return relationship != null && relationship.isManyToMany(); } @Override diff --git a/src/main/java/org/entityc/compiler/model/entity/MTRelationship.java b/src/main/java/org/entityc/compiler/model/entity/MTRelationship.java index 7b7ef85..e472e2c 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTRelationship.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTRelationship.java @@ -201,6 +201,18 @@ public boolean isManyToMany() { return getFullRelationshipPlurality() == FullRelationshipPlurality.MANY_TO_MANY; } + @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, + description = + "Gets the entity on the other side of an implicit many-to-many entity.") + public MTEntity getImplicitToEntity() { + for(MTRelationship mmRel : to.getEntity().implicitRelationships) { + if (!mmRel.to.getEntityName().equals(from.getEntityName())) { + return mmRel.to.getEntity(); + } + } + return null; + } + @Override public void accept(MTVisitor visitor) { diff --git a/src/main/java/org/entityc/compiler/transform/MTVImplicitTransform.java b/src/main/java/org/entityc/compiler/transform/MTVImplicitTransform.java index 6d337cb..26366d8 100644 --- a/src/main/java/org/entityc/compiler/transform/MTVImplicitTransform.java +++ b/src/main/java/org/entityc/compiler/transform/MTVImplicitTransform.java @@ -14,6 +14,7 @@ import org.entityc.compiler.model.entity.MTEnum; import org.entityc.compiler.model.entity.MTPrimaryKey; import org.entityc.compiler.model.entity.MTRelationship; +import org.entityc.compiler.util.ECLog; // TODO: Create index from parent relationships @@ -67,32 +68,34 @@ public void visitAttribute(MTAttribute attribute) { public void visitRelationship(MTRelationship relationship) { MTEntity fromEntity = relationship.getFrom().getEntity(); - MTEntity toEntity = relationship.getTo().getEntity(); + MTEntity toEntity = relationship.getTo().getEntity(); if (toEntity == null || fromEntity == null) { relationship.resolveReferences(root.getSpace(), 0); toEntity = relationship.getTo().getEntity(); fromEntity = relationship.getFrom().getEntity(); + if (toEntity == null) { + ECLog.logFatal("The entity \"" + fromEntity.getName() + "\" has a relationship \"" + relationship.getName() + "\" but not to anything."); + } } MTPrimaryKey toPrimaryKey = toEntity.getPrimaryKey(); if (toPrimaryKey == null) { return; } - FullRelationshipPlurality plurality = relationship.getFullRelationshipPlurality(); - MTPrimaryKey fromPrimaryKey = fromEntity.getPrimaryKey(); + FullRelationshipPlurality plurality = relationship.getFullRelationshipPlurality(); + MTPrimaryKey fromPrimaryKey = fromEntity.getPrimaryKey(); if (!relationship.getFrom().getEntity().isImplicit()) { if (fromPrimaryKey == null && plurality != FullRelationshipPlurality.MANY_TO_ONE) { return; } } if (toPrimaryKey.getAttributes().size() != 1 - || (fromPrimaryKey != null && fromPrimaryKey.getAttributes().size() != 1)) { + || (fromPrimaryKey != null && fromPrimaryKey.getAttributes().size() != 1)) { return; // unsupported right now } switch (plurality) { case MANY_TO_MANY: { // create table to support relationship - String virtualEntityName = fromEntity.getName() + "-" + toEntity.getName(); MTEntity.AddImplicitManyToManyEntity(fromEntity.getSpace(), fromEntity, toEntity); } break; From 8742dcb1f4453619a33b29ec157697566a74b0e7 Mon Sep 17 00:00:00 2001 From: Bob Garner Date: Tue, 29 Aug 2023 06:52:22 -0700 Subject: [PATCH 04/12] Added relationship methods to MTEntity. Also improved debug/error print statements. --- docs/emc/EMC_entity.md | 20 ++++++++ .../compiler/model/entity/MTEntity.java | 21 ++++++++ .../repository/LocalRepositoryImporter.java | 3 +- .../repository/RepositoryImportManager.java | 50 ++++++++++--------- 4 files changed, 70 insertions(+), 24 deletions(-) diff --git a/docs/emc/EMC_entity.md b/docs/emc/EMC_entity.md index ae35c7e..32913eb 100644 --- a/docs/emc/EMC_entity.md +++ b/docs/emc/EMC_entity.md @@ -576,6 +576,16 @@ Indicates whether this entity has any attributes. Indicates whether this entity defines any bit fields. +
+ +#### `MTRelationship relationshipNamed(String name)` + +Returns an relationship of this entity with the specified name. + +| Parameter | Description | +|-----|-----| +|`String name` | The name of the relationship to return. | + ### Relationship Category @@ -657,6 +667,16 @@ Indicates whether this entity has a primary parent relationship. A primary paren
+#### `boolean hasRelationshipNamed(String name)` + +Indicates whether this entity has an relationship with the specified name. + +| Parameter | Description | +|-----|-----| +|`String name` | *no description* | + +
+ #### `boolean` **`hasRelationships`** Indicates whether this entity defines any relationships. diff --git a/src/main/java/org/entityc/compiler/model/entity/MTEntity.java b/src/main/java/org/entityc/compiler/model/entity/MTEntity.java index 10ade2a..e457338 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTEntity.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTEntity.java @@ -783,6 +783,27 @@ public MTAttribute getAttributeByName(String attributeName) { return attribute; } + @ModelMethod( + category = ModelMethodCategory.RELATIONSHIP, + description = "Indicates whether this entity has an relationship with the specified name.") + public boolean hasRelationshipNamed(String name) { + for (MTRelationship relationship : relationships) { + if (relationship.getName().equals(name)) { + return true; + } + } + return false; + } + + @ModelMethod( + category = ModelMethodCategory.ATTRIBUTE, + description = "Returns an relationship of this entity with the specified name.") + public MTRelationship relationshipNamed( + @ModelMethodParameter(description = "The name of the relationship to return.") + String name) { + return getRelationshipByName(name); + } + @ModelMethod( category = ModelMethodCategory.RELATIONSHIP, description = "Returns the number of declared relationships.") diff --git a/src/main/java/org/entityc/compiler/repository/LocalRepositoryImporter.java b/src/main/java/org/entityc/compiler/repository/LocalRepositoryImporter.java index 3022d89..a755c8c 100644 --- a/src/main/java/org/entityc/compiler/repository/LocalRepositoryImporter.java +++ b/src/main/java/org/entityc/compiler/repository/LocalRepositoryImporter.java @@ -46,7 +46,8 @@ public RepositoryFile importFromRepository(MTRepository repository, MTRepository fos.close(); } catch (IOException e) { e.printStackTrace(); - ECLog.logFatal("Unable to import file: " + inputFilepath + " >> " + e.getMessage()); + File infile = new File(inputFilepath); + ECLog.logFatal("Unable to import file: " + infile.getAbsolutePath() + " >> " + e.getMessage()); } } return cachedRepositoryFile; diff --git a/src/main/java/org/entityc/compiler/repository/RepositoryImportManager.java b/src/main/java/org/entityc/compiler/repository/RepositoryImportManager.java index 24f1baa..f80663e 100644 --- a/src/main/java/org/entityc/compiler/repository/RepositoryImportManager.java +++ b/src/main/java/org/entityc/compiler/repository/RepositoryImportManager.java @@ -21,10 +21,10 @@ public class RepositoryImportManager { - private final RepositoryCache repositoryCache; - private final Map importersByType = new HashMap<>(); - private List repositoryFilesInOrder = new ArrayList<>(); - private Map repositoryFilesByIdentifier = new HashMap<>(); + private final RepositoryCache repositoryCache; + private final Map importersByType = new HashMap<>(); + private List repositoryFilesInOrder = new ArrayList<>(); + private Map repositoryFilesByIdentifier = new HashMap<>(); public RepositoryImportManager(RepositoryCache.CacheStructure structure) { this.repositoryCache = new RepositoryCache(structure); @@ -55,35 +55,36 @@ public void updateRepositoryCommitSHA1(MTRepository repository) { public RepositoryFile importFromRepository(MTSpace space, MTRepositoryImport repositoryImport, String extension, boolean asInclude) { - String repositoryName = repositoryImport.getRepositoryName(); - MTRepository repository = space.getRepositoryByName(repositoryName); + String repositoryName = repositoryImport.getRepositoryName(); + MTRepository repository = space.getRepositoryByName(repositoryName); if (repository == null) { ECLog.logFatal(repositoryImport, - "In space \"" + space.getName() + "\" cannot find a repository named \"" + repositoryName - + "\"."); - } else if (!repository.isValid()) { + "In space \"" + space.getName() + "\" cannot find a repository named \"" + repositoryName + + "\"."); + } + else if (!repository.isValid()) { ECLog.logFatal(repository, "Repository specification is not valid."); } - String name = repositoryImport.getFilename(); - String filename = name + "." + extension; - MTRepositoryType type = repository.getType(); + String name = repositoryImport.getFilename(); + String filename = name + "." + extension; + MTRepositoryType type = repository.getType(); boolean shouldUseSpaceRepository = space.getRepositoryThatImportedThisSpace() != null - && type == MTRepositoryType.LOCAL; + && type == MTRepositoryType.LOCAL; MTRepository sourceRepository = repository; - String alternatePath = null; + String alternatePath = null; if (shouldUseSpaceRepository) { sourceRepository = space.getRepositoryThatImportedThisSpace(); - alternatePath = repository.getPath(); + alternatePath = repository.getPath(); } RepositoryImporter repositoryImporter = importersByType.get(sourceRepository.getType()); repositoryImporter.updateRepositoryCommitSHA1( - sourceRepository); // if it has one, fetch it so the cache will know if it needs to invalidate itself + sourceRepository); // if it has one, fetch it so the cache will know if it needs to invalidate itself repositoryCache.validateRepositoryInCache(sourceRepository); RepositoryFile cacheRepositoryFile = repositoryCache.getRepositoryFile(sourceRepository, filename, - asInclude); + asInclude); if (sourceRepository.getType() != MTRepositoryType.LOCAL && cacheRepositoryFile.exists()) { // check if it exists in the cache already if (EntityCompiler.isVerbose()) { @@ -94,11 +95,14 @@ public RepositoryFile importFromRepository(MTSpace space, MTRepositoryImport rep } RepositoryFile file = repositoryImporter.importFromRepository(sourceRepository, repositoryImport, - cacheRepositoryFile, extension, alternatePath); + cacheRepositoryFile, extension, alternatePath); if (file == null || !file.exists()) { - String nameOrPath = repository.getType() == MTRepositoryType.LOCAL ? - repository.getPath() : - repositoryName; + String nameOrPath = repositoryName; + + if (repository.getType() == MTRepositoryType.LOCAL) { + File f = new File(repository.getPath()); + nameOrPath = f.getAbsolutePath(); + } ECLog.logFatal("Unable to import " + repository.getType() + " file: " + nameOrPath + "/" + filename); } addRepositoryFile(repositoryImport.getIdentifier(), file); @@ -116,11 +120,11 @@ private String fileIdentifier(String repositoryName, String filename) { private String getRepositoryCachePath(MTRepository repository) { return repository.getOrganization() + File.separator + repository.getRepoName() + File.separator - + repository.getTag(); + + repository.getTag(); } public void close() { - repositoryFilesInOrder = new ArrayList<>(); + repositoryFilesInOrder = new ArrayList<>(); repositoryFilesByIdentifier = new HashMap<>(); for (RepositoryImporter importer : importersByType.values()) { importer.close(); From 3e2bffc5fca65bb2648d22e0e1ae860ac5a43b03 Mon Sep 17 00:00:00 2001 From: Bob Garner Date: Tue, 29 Aug 2023 08:44:48 -0700 Subject: [PATCH 05/12] Added support for T tags on groups of attributes and relationships to reduce redundancy. --- .../org/entityc/compiler/EntityLanguage.g4 | 12 ++- .../java/org/entityc/compiler/ASTVisitor.java | 73 ++++++++++++++++++- .../org/entityc/compiler/EntityCompiler.java | 4 +- 3 files changed, 79 insertions(+), 10 deletions(-) diff --git a/src/main/antlr4/org/entityc/compiler/EntityLanguage.g4 b/src/main/antlr4/org/entityc/compiler/EntityLanguage.g4 index 6131001..41c97c0 100644 --- a/src/main/antlr4/org/entityc/compiler/EntityLanguage.g4 +++ b/src/main/antlr4/org/entityc/compiler/EntityLanguage.g4 @@ -364,7 +364,8 @@ attributes attributesBody : - ( attribute + ( tagStatement + | attribute )* ; @@ -411,7 +412,8 @@ relationships relationshipsBody : - ( relationshipStatement + ( tagStatement + | relationshipStatement )* ; @@ -835,7 +837,8 @@ domainAttributes domainAttributesBody : - ( domainAttributesRenameTo + ( tagStatement + | domainAttributesRenameTo | domainAttributesRenameAppendPrepend | domainAttributeReplaces | domainAttributeExclude @@ -901,7 +904,8 @@ domainRelationships domainRelationshipsBody : - ( domainRelationship + ( tagStatement + | domainRelationship )* ; diff --git a/src/main/java/org/entityc/compiler/ASTVisitor.java b/src/main/java/org/entityc/compiler/ASTVisitor.java index 8c7280c..050f573 100644 --- a/src/main/java/org/entityc/compiler/ASTVisitor.java +++ b/src/main/java/org/entityc/compiler/ASTVisitor.java @@ -113,6 +113,7 @@ public class ASTVisitor extends EntityLanguageBaseVisitor { private MTDEInterface currentDomainEntityInterface; private MTDEInterfaceOperation currentDomainEntityInterfaceOperation; private MTSpace foundSpace; + private List> inheritedTags; public MTSpace getFoundSpace() { return foundSpace; @@ -1309,6 +1310,19 @@ public MTTagSet visitViewTaggedListItem(EntityLanguageParser.ViewTaggedListItemC return tagSet; } + @Override + public Object visitRelationshipsBody(EntityLanguageParser.RelationshipsBodyContext ctx) { + if (ctx.tagStatement() != null) { + inheritedTags = tagStringsFromTagStatements(ctx.tagStatement()); + } + + Object object = super.visitRelationshipsBody(ctx); + + inheritedTags = null; + + return object; + } + @Override public MTRelationship visitRelationshipStatement(EntityLanguageParser.RelationshipStatementContext ctx) { HalfRelationshipPlurality toPlurality = HalfRelationshipPlurality.ONE; @@ -1350,6 +1364,9 @@ public MTRelationship visitRelationshipStatement(EntityLanguageParser.Relationsh toEntityName, optional, parent, reverseName, toEntityIdName, null); + if (inheritedTags != null) { + relationship.addTagsWithValues(inheritedTags); + } if (instantiation != null) { relationship.getTo().setTemplateInstantiation(instantiation); } @@ -1909,12 +1926,26 @@ public Object visitDomainVirtualAttribute(EntityLanguageParser.DomainVirtualAttr return null; } + @Override + public Object visitDomainAttributesBody(EntityLanguageParser.DomainAttributesBodyContext ctx) { + if (ctx.tagStatement() != null) { + inheritedTags = tagStringsFromTagStatements(ctx.tagStatement()); + } + Object object = super.visitDomainAttributesBody(ctx); + inheritedTags = null; + + return object; + } + @Override public Object visitDomainAttribute(EntityLanguageParser.DomainAttributeContext ctx) { String attributeName = ctx.id().getText(); if (currentDomainEntity != null) { - MTDEAttribute domainEntityAttribute = currentDomainEntity.addDomainAttributeWithName( + MTDEAttribute domainEntityAttribute = currentDomainEntity.addDomainAttributeWithName( attributeName); + if (inheritedTags != null) { + domainEntityAttribute.addTagsWithValues(inheritedTags); + } EntityLanguageParser.DomainAttributeBodyContext bodyContext = ctx.domainAttributeBody(); if (bodyContext != null) { if (bodyContext.descriptionStatement() != null) { @@ -1928,19 +1959,35 @@ public Object visitDomainAttribute(EntityLanguageParser.DomainAttributeContext c return null; } + @Override + public Object visitDomainRelationshipsBody(EntityLanguageParser.DomainRelationshipsBodyContext ctx) { + if (ctx.tagStatement() != null) { + inheritedTags = tagStringsFromTagStatements(ctx.tagStatement()); + } + + Object object = super.visitDomainRelationshipsBody(ctx); + + inheritedTags = null; + + return object; + } + @Override public Object visitDomainRelationship(EntityLanguageParser.DomainRelationshipContext ctx) { String relationshipName = ctx.id().getText(); if (currentDomainEntity != null) { - MTDERelationship domainEntityAttribute = currentDomainEntity.addDomainRelationshipWithName( + MTDERelationship domainEntityRelationship = currentDomainEntity.addDomainRelationshipWithName( relationshipName); + if (inheritedTags != null) { + domainEntityRelationship.addTagsWithValues(inheritedTags); + } EntityLanguageParser.DomainRelationshipBodyContext bodyContext = ctx.domainRelationshipBody(); if (bodyContext != null) { if (bodyContext.descriptionStatement() != null) { - setNodeDescription(domainEntityAttribute, bodyContext.descriptionStatement(), false); + setNodeDescription(domainEntityRelationship, bodyContext.descriptionStatement(), false); } if (bodyContext.tagStatement() != null) { - domainEntityAttribute.addTagsWithValues(tagStringsFromTagStatements(bodyContext.tagStatement())); + domainEntityRelationship.addTagsWithValues(tagStringsFromTagStatements(bodyContext.tagStatement())); } } } @@ -1980,6 +2027,20 @@ public Object visitDomainAttributeAdd(EntityLanguageParser.DomainAttributeAddCon return null; } + @Override + public Object visitAttributesBody(EntityLanguageParser.AttributesBodyContext ctx) { + + if (ctx.tagStatement() != null) { + inheritedTags = tagStringsFromTagStatements(ctx.tagStatement()); + } + + Object object = super.visitAttributesBody(ctx); + + inheritedTags = null; + + return object; + } + @Override public MTAttribute visitAttribute(EntityLanguageParser.AttributeContext ctx) { String attributeName = ctx.id(0).getText(); @@ -2065,6 +2126,10 @@ public MTAttribute visitAttribute(EntityLanguageParser.AttributeContext ctx) { } } + if (inheritedTags != null) { + attribute.addTagsWithValues(inheritedTags); + } + EntityLanguageParser.AttributeBodyContext bodyContext = ctx.attributeBody(); if (bodyContext != null) { if (bodyContext.descriptionStatement() != null) { diff --git a/src/main/java/org/entityc/compiler/EntityCompiler.java b/src/main/java/org/entityc/compiler/EntityCompiler.java index b7d5846..64b05e7 100644 --- a/src/main/java/org/entityc/compiler/EntityCompiler.java +++ b/src/main/java/org/entityc/compiler/EntityCompiler.java @@ -52,8 +52,8 @@ public class EntityCompiler { - public static final String COMPILER_VERSION = "0.16.0"; - public static final String LANGUAGE_VERSION = "0.13.0"; + public static final String COMPILER_VERSION = "0.17.0"; + public static final String LANGUAGE_VERSION = "0.14.0"; private static final Map defineValues = new HashMap<>(); private static final Set templateSearchPath = new HashSet<>(); private static CommandLine commandLine; From 38a26f2a3cc025fda42d844d95a27bd5315adf77 Mon Sep 17 00:00:00 2001 From: Bob Garner Date: Wed, 30 Aug 2023 19:57:02 -0700 Subject: [PATCH 06/12] Added support for relationship fields. --- .../org/entityc/compiler/EntityLanguage.g4 | 27 ++++++ .../java/org/entityc/compiler/ASTVisitor.java | 35 ++++---- .../org/entityc/compiler/EntityCompiler.java | 4 +- .../model/domain/MTDERelationship.java | 72 +++++++++++----- .../model/domain/MTDERelationshipField.java | 86 +++++++++++++++++++ 5 files changed, 184 insertions(+), 40 deletions(-) create mode 100644 src/main/java/org/entityc/compiler/model/domain/MTDERelationshipField.java diff --git a/src/main/antlr4/org/entityc/compiler/EntityLanguage.g4 b/src/main/antlr4/org/entityc/compiler/EntityLanguage.g4 index 41c97c0..44b8848 100644 --- a/src/main/antlr4/org/entityc/compiler/EntityLanguage.g4 +++ b/src/main/antlr4/org/entityc/compiler/EntityLanguage.g4 @@ -898,6 +898,32 @@ domainAttributeBody )* ; +/* +These are attributes of the "to" entity of a relationship. This allows +tagging of attributes with respect to its "path" from a relationship. +*/ +domainRelationshipAttributes + : ATTRIBUTES '{' domainRelationshipAttributesBody '}' + ; + +domainRelationshipAttributesBody + : + ( tagStatement + | domainRelationshipAttribute + )* + ; + +domainRelationshipAttribute + : id '{' domainRelationshipAttributeBody '}' + ; + +domainRelationshipAttributeBody + : + ( descriptionStatement + | tagStatement + )* + ; + domainRelationships : RELATIONSHIPS '{' domainRelationshipsBody '}' ; @@ -917,6 +943,7 @@ domainRelationshipBody : ( descriptionStatement | tagStatement + | domainRelationshipAttributes )* ; diff --git a/src/main/java/org/entityc/compiler/ASTVisitor.java b/src/main/java/org/entityc/compiler/ASTVisitor.java index 050f573..0f59d4f 100644 --- a/src/main/java/org/entityc/compiler/ASTVisitor.java +++ b/src/main/java/org/entityc/compiler/ASTVisitor.java @@ -22,21 +22,7 @@ import org.entityc.compiler.model.config.MTSpaceInclude; import org.entityc.compiler.model.config.MTTemplate; import org.entityc.compiler.model.config.MTTransform; -import org.entityc.compiler.model.domain.MTDApplyTemplate; -import org.entityc.compiler.model.domain.MTDEAttribute; -import org.entityc.compiler.model.domain.MTDEAttributeBitField; -import org.entityc.compiler.model.domain.MTDEInterface; -import org.entityc.compiler.model.domain.MTDEInterfaceOperation; -import org.entityc.compiler.model.domain.MTDEInterfaceOperationConfig; -import org.entityc.compiler.model.domain.MTDERelationship; -import org.entityc.compiler.model.domain.MTDEntity; -import org.entityc.compiler.model.domain.MTDEnum; -import org.entityc.compiler.model.domain.MTDEnumItem; -import org.entityc.compiler.model.domain.MTDModule; -import org.entityc.compiler.model.domain.MTDView; -import org.entityc.compiler.model.domain.MTDomain; -import org.entityc.compiler.model.domain.MTNaming; -import org.entityc.compiler.model.domain.MTNamingMethod; +import org.entityc.compiler.model.domain.*; import org.entityc.compiler.model.entity.HalfRelationshipPlurality; import org.entityc.compiler.model.entity.MTAttribute; import org.entityc.compiler.model.entity.MTAttributeConstraint; @@ -105,6 +91,7 @@ public class ASTVisitor extends EntityLanguageBaseVisitor { private MTAttribute currentAttribute; private MTDModule currentDomainModule; private MTDEntity currentDomainEntity; + private MTDERelationship currentDomainRelationship; private MTDEnum currentDomainEnum; private MTLanguage currentLanguage; private MTConfiguration currentConfiguration; @@ -1990,8 +1977,24 @@ public Object visitDomainRelationship(EntityLanguageParser.DomainRelationshipCon domainEntityRelationship.addTagsWithValues(tagStringsFromTagStatements(bodyContext.tagStatement())); } } + this.currentDomainRelationship = domainEntityRelationship; } - return null; + Object object = super.visitDomainRelationship(ctx); + + this.currentDomainRelationship = null; + + return object; + } + + @Override + public Object visitDomainRelationshipAttribute(EntityLanguageParser.DomainRelationshipAttributeContext ctx) { + String attributeName = ctx.id().getText(); + + MTDERelationshipField relationshipField = new MTDERelationshipField(ctx, currentDomainRelationship, attributeName); + currentDomainRelationship.addField(relationshipField); + Object object = super.visitDomainRelationshipAttribute(ctx); + + return object; } @Override diff --git a/src/main/java/org/entityc/compiler/EntityCompiler.java b/src/main/java/org/entityc/compiler/EntityCompiler.java index 64b05e7..e30c164 100644 --- a/src/main/java/org/entityc/compiler/EntityCompiler.java +++ b/src/main/java/org/entityc/compiler/EntityCompiler.java @@ -52,8 +52,8 @@ public class EntityCompiler { - public static final String COMPILER_VERSION = "0.17.0"; - public static final String LANGUAGE_VERSION = "0.14.0"; + public static final String COMPILER_VERSION = "0.18.0"; + public static final String LANGUAGE_VERSION = "0.15.0"; private static final Map defineValues = new HashMap<>(); private static final Set templateSearchPath = new HashSet<>(); private static CommandLine commandLine; diff --git a/src/main/java/org/entityc/compiler/model/domain/MTDERelationship.java b/src/main/java/org/entityc/compiler/model/domain/MTDERelationship.java index 33a74f6..2aa8c7f 100644 --- a/src/main/java/org/entityc/compiler/model/domain/MTDERelationship.java +++ b/src/main/java/org/entityc/compiler/model/domain/MTDERelationship.java @@ -18,31 +18,36 @@ import org.entityc.compiler.model.entity.MTRelationship; import org.entityc.compiler.model.visitor.MTVisitor; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + @ModelClass(type = ModelClassType.DOMAIN, description = "Represents a relationship in your model in the context of a domain.") public class MTDERelationship extends MTNode implements MTNamed, MTDomainBased, MTReferenceResolution { - private final String relationshipName; - private MTDomain domain; - private MTDEntity domainEntity; - private MTRelationship relationship; - private String explicitName; - private String withViewName; // to-entity should map to a specific view - private boolean withPrimaryKey; // to-entity should map as its primary key only - private MTDERelationshipHalf to; - private boolean resolvedReferences = false; + private final String relationshipName; + private MTDomain domain; + private MTDEntity domainEntity; + private MTRelationship relationship; + private String explicitName; + private String withViewName; // to-entity should map to a specific view + private boolean withPrimaryKey; // to-entity should map as its primary key only + private MTDERelationshipHalf to; + private boolean resolvedReferences = false; + private List fields; public MTDERelationship(ParserRuleContext ctx, MTDEntity domainEntity, String relationshipName) { super(ctx); - this.domain = domainEntity.getDomain(); - this.domainEntity = domainEntity; + this.domain = domainEntity.getDomain(); + this.domainEntity = domainEntity; this.relationshipName = relationshipName; } public MTDERelationship(ParserRuleContext ctx, MTDomain domain, MTRelationship relationship) { super(ctx); - this.domain = domain; - this.relationship = relationship; + this.domain = domain; + this.relationship = relationship; this.relationshipName = relationship.getName(); } @@ -77,7 +82,7 @@ public void setWithViewName(String withViewName) { @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "If this relationship was explicitly renamed within its domain, it will return that name. Otherwise " - + "it will return `null`.") + + "it will return `null`.") public String getExplicitName() { return explicitName; } @@ -108,6 +113,22 @@ public boolean isManyToMany() { return relationship != null && relationship.isManyToMany(); } + public void addField(MTDERelationshipField field) { + if (this.fields == null) { + this.fields = new ArrayList<>(); + } + this.fields.add(field); + } + + public boolean hasFields() { + return this.fields != null && this.fields.size() > 0; + } + @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, + description = "Returns all the declared fields of this relationship.") + public Collection getFields() { + return this.fields; + } + @Override public boolean resolveReferences(MTSpace space, int pass) { if (domain != null && domain.isSpecialized()) { @@ -126,12 +147,19 @@ public boolean resolveReferences(MTSpace space, int pass) { } if (relationship != null && to == null) { to = new MTDERelationshipHalf(relationship.getParserRuleContext(), domain, relationship.getTo(), - withViewName); + withViewName); to.setAsPrimaryKey(withPrimaryKey); if (to.resolveReferences(space, pass)) { anotherPass = true; } } + if (fields != null) { + for (MTDERelationshipField field : fields) { + if (field.resolveReferences(space, pass)) { + anotherPass = true; + } + } + } if (!anotherPass) { resolvedReferences = true; } @@ -146,21 +174,21 @@ public void accept(MTVisitor visitor) { @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "This returns the full name of this domain relationship which includes not only its domain based name " - + "but is also preceded with the domain's entity's full name. The delimiter can be provided which " - + "is used between all parts of the full name.") + + "but is also preceded with the domain's entity's full name. The delimiter can be provided which " + + "is used between all parts of the full name.") @Override public String getFullname( @ModelMethodParameter(description = "A delimiter to place between the segments of the domain namespace as well " - + "as between that namespace and the domain entity name and between the " - + "domain entity name and the domain relationship name.") - String delim) { + + "as between that namespace and the domain entity name and between the " + + "domain entity name and the domain relationship name.") + String delim) { return domainEntity.getFullname(delim) + delim + getName(); } @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "Returns the domain relationship name which is the result of applying any defined naming conventions " - + "or explicit renaming.") + + "or explicit renaming.") @Override public String getName() { if (explicitName != null) { @@ -230,7 +258,7 @@ public boolean isPrimaryParent() { description = "Returns whether this relationship's \"to\" entity is tagged with the specified tag.") public boolean hasToEntityTagged( @ModelMethodParameter(description = "The tag with which to check.") - String tag) { + String tag) { return to != null && to.getEntity().hasTag(tag); } } diff --git a/src/main/java/org/entityc/compiler/model/domain/MTDERelationshipField.java b/src/main/java/org/entityc/compiler/model/domain/MTDERelationshipField.java new file mode 100644 index 0000000..2266461 --- /dev/null +++ b/src/main/java/org/entityc/compiler/model/domain/MTDERelationshipField.java @@ -0,0 +1,86 @@ +package org.entityc.compiler.model.domain; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.entityc.compiler.doc.annotation.ModelClass; +import org.entityc.compiler.doc.annotation.ModelClassType; +import org.entityc.compiler.model.MTNode; +import org.entityc.compiler.model.MTReferenceResolution; +import org.entityc.compiler.model.config.MTSpace; +import org.entityc.compiler.model.entity.MTEntity; +import org.entityc.compiler.model.entity.MTRelationship; +import org.entityc.compiler.model.visitor.MTVisitor; +import org.entityc.compiler.util.ECLog; + +@ModelClass(type = ModelClassType.DOMAIN, + description = "Represents a field (attribute or relationship) associated with the __to__ entity of the relationship.") +public class MTDERelationshipField extends MTNode implements MTNamed, MTDomainBased, MTReferenceResolution { + + public MTDERelationshipField(ParserRuleContext ctx, MTDERelationship domainRelationship, String fieldName) { + super(ctx); + this.domainRelationship = domainRelationship; + this.fieldName = fieldName; + } + private MTDERelationship domainRelationship; + private MTDEAttribute fieldAttribute; + private MTDERelationship fieldRelationship; + + private String fieldName; + + public boolean fieldIsAttribute() { + return fieldAttribute != null; + } + + public boolean fieldIsRelationship() { + return fieldRelationship != null; + } + + public MTDEAttribute getAttribute() { + return fieldAttribute; + } + + @Override + public void accept(MTVisitor visitor) { + + } + + @Override + public boolean resolveReferences(MTSpace space, int pass) { + ECLog.logInfo("Resolving domain relationship field references..."); + if ( fieldIsAttribute() || fieldIsRelationship() ) { + return false; + } + MTRelationship relationship = domainRelationship.getRelationship(); + if (relationship == null) { + return true; + } + MTEntity entity = relationship.getTo() != null && relationship.getTo().getEntity() != null ? relationship.getTo().getEntity() : null; + if (entity == null) { + return true; + } + + if (entity.hasAttributeNamed(fieldName)) { + this.fieldAttribute = new MTDEAttribute(getParserRuleContext(), domainRelationship.getDomain(), entity.getName(), fieldName); + this.fieldAttribute.addTagsWithValues(this.getTagsWithValues()); // transfer the tags to it + } else if (entity.hasRelationshipNamed(fieldName)) { + ECLog.logFatal(getParserRuleContext(), "Domain relationship fields of type relationship currently not supported."); + } else { + ECLog.logFatal(getParserRuleContext(), "Domain relationship " + this.domainRelationship.getName() + " of entity " + entity.getName() + " does not have an attribute or relationship named: " + fieldName); + } + return false; + } + + @Override + public MTDomain getDomain() { + return this.domainRelationship.getDomain(); + } + + @Override + public String getFullname(String delim) { + return this.domainRelationship.getFullname(delim) + delim + this.fieldName; + } + + @Override + public String getName() { + return this.fieldName; + } +} From d2cdba9fcb44df6cb5353ca298c3c8e1cc2c1691 Mon Sep 17 00:00:00 2001 From: Bob Garner Date: Wed, 30 Aug 2023 19:59:41 -0700 Subject: [PATCH 07/12] Removed debug log statement. --- .../org/entityc/compiler/model/domain/MTDERelationshipField.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/entityc/compiler/model/domain/MTDERelationshipField.java b/src/main/java/org/entityc/compiler/model/domain/MTDERelationshipField.java index 2266461..c87d31c 100644 --- a/src/main/java/org/entityc/compiler/model/domain/MTDERelationshipField.java +++ b/src/main/java/org/entityc/compiler/model/domain/MTDERelationshipField.java @@ -45,7 +45,6 @@ public void accept(MTVisitor visitor) { @Override public boolean resolveReferences(MTSpace space, int pass) { - ECLog.logInfo("Resolving domain relationship field references..."); if ( fieldIsAttribute() || fieldIsRelationship() ) { return false; } From 533175af96e2ddccb037f1e763682f1e034553c5 Mon Sep 17 00:00:00 2001 From: Bob Garner Date: Thu, 2 Nov 2023 07:57:40 -0700 Subject: [PATCH 08/12] Added support for Released Transform. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will merge “object” and “version” tagged entities along with a “release” entity into a single Released entity. --- docs/emc/EMC_domain.md | 19 ++ docs/emc/EMC_entity.md | 46 ++++ docs/emc/EMC_foundation.md | 10 + .../java/org/entityc/compiler/ASTVisitor.java | 18 +- .../org/entityc/compiler/EntityCompiler.java | 9 +- .../compiler/model/domain/MTDEntity.java | 15 +- .../compiler/model/entity/MTAttribute.java | 3 + .../model/entity/MTCompositeEntity.java | 42 ++++ .../compiler/model/entity/MTEntity.java | 38 ++- .../entityc/compiler/model/entity/MTEnum.java | 4 + .../compiler/model/entity/MTRelationship.java | 30 ++- .../model/entity/MTSecondaryRelationship.java | 2 +- .../entityc/compiler/model/entity/MTType.java | 6 + .../compiler/model/foundation/MFArray.java | 9 +- .../compiler/model/visitor/MTBaseVisitor.java | 2 +- .../transform/MTVImplicitTransform.java | 30 ++- .../transform/MTVPostgresTransform.java | 4 +- .../transform/MTVReleasedTransform.java | 219 ++++++++++++++++++ .../compiler/transform/TransformManager.java | 2 +- .../template/tree/filter/FTJoinFilter.java | 2 + 20 files changed, 466 insertions(+), 44 deletions(-) create mode 100644 src/main/java/org/entityc/compiler/model/entity/MTCompositeEntity.java create mode 100644 src/main/java/org/entityc/compiler/transform/MTVReleasedTransform.java diff --git a/docs/emc/EMC_domain.md b/docs/emc/EMC_domain.md index 46ef9a8..3d00c61 100644 --- a/docs/emc/EMC_domain.md +++ b/docs/emc/EMC_domain.md @@ -11,6 +11,7 @@ Model classes that are domain specific are of this type. The classes are briefly |[`MTDEAttribute`](#class_MTDEAttribute)|Represents an attribute in your model in the context of a domain.| |[`MTDEAttributeConstraintExpression`](#class_MTDEAttributeConstraintExpression)|Represents a constraint on an attribute in the form of an expression.| |[`MTDERelationship`](#class_MTDERelationship)|Represents a relationship in your model in the context of a domain.| +|[`MTDERelationshipField`](#class_MTDERelationshipField)|Represents a field (attribute or relationship) associated with the __to__ entity of the relationship.| |[`MTDEntity`](#class_MTDEntity)|Represents an entity in your model in the context of a domain.| |[`MTDEnum`](#class_MTDEnum)|Represents an enum in the context of a domain.| |[`MTDEnumItem`](#class_MTDEnumItem)|Represents an enum item in the context of a domain.| @@ -236,6 +237,12 @@ If this relationship was explicitly renamed within its domain, it will return th
+#### `Collection` **`fields`** + +Returns all the declared fields of this relationship. + +
+ #### `String fullname(String delim)` This returns the full name of this domain relationship which includes not only its domain based name but is also preceded with the domain's entity's full name. The delimiter can be provided which is used between all parts of the full name. @@ -551,6 +558,18 @@ Returns the domain specific version of the specified relationship.
+#### `boolean` **`hasDeclaredDomainRelationships`** + +Indicates if any relationships were declared in this domain entity declaration. + +
+ +#### `boolean` **`hasParentRelationship`** + +Indicates whether this domain entity has a parent relationship. A parent relationship is one that has been declared as `parent` + +
+ #### `boolean` **`hasPrimaryParentRelationship`** Indicates whether this domain entity has a primary parent relationship. A primary parent relationship is one that has been declared as `parent` and **not** declared `optional`. diff --git a/docs/emc/EMC_entity.md b/docs/emc/EMC_entity.md index 32913eb..4209d1d 100644 --- a/docs/emc/EMC_entity.md +++ b/docs/emc/EMC_entity.md @@ -355,6 +355,16 @@ These methods relate to an entity.
+#### `void addRealm(String realm)` + +Adds the entity to a realm. + +| Parameter | Description | +|-----|-----| +|`String realm` | *no description* | + +
+ #### `boolean` **`isDeclaredAsPrimary`** Indicates whether this entity was **declared** `primary`. If the entity was **not** declared with the `primary` keyword then this will return false even if it is implied as primary. @@ -379,6 +389,16 @@ Indicates whether this entity was created by the compiler because it represents
+#### `boolean isInRealm(String realm)` + +Returns true if this entity is part of a realm. + +| Parameter | Description | +|-----|-----| +|`String realm` | *no description* | + +
+ #### `boolean` **`isPrimary`** Indicates whether this entity was declared `primary` or if it was inferred as primary. If an entity has a primary key it is inferred to be a primary entity. @@ -848,6 +868,16 @@ Indicates whether this entity has at least one relationship with the specified t
+#### `boolean hasRelationshipToEntityNamed(String toEntityName)` + +Indicates whether this entity has at least one relationship to a named other entity. + +| Parameter | Description | +|-----|-----| +|`String toEntityName` | The name of the other entity. | + +
+ #### `boolean hasRelationshipToEntityTagged(String tag)` Indicates whether the entity **to** which a relationship references is tagged with the specified tag. @@ -924,6 +954,16 @@ Indicates whether this was declared as `extern`.
+#### `MTEnumItem item(Long index)` + +Returns an item by its index. + +| Parameter | Description | +|-----|-----| +|`Long index` | *no description* | + +
+ #### `List` **`items`** Gets the enum items. @@ -1366,6 +1406,12 @@ Indicates whether this type is both an array type and also `byte` data type.
+#### `boolean` **`isDataType`** + +Indicates whether this type is the `data` data type. + +
+ #### `boolean` **`isDateType`** Indicates whether this type is the `date` data type. diff --git a/docs/emc/EMC_foundation.md b/docs/emc/EMC_foundation.md index 82ed67b..be6a70d 100644 --- a/docs/emc/EMC_foundation.md +++ b/docs/emc/EMC_foundation.md @@ -75,6 +75,16 @@ Returns the first item in the array.
+#### `Object get(Integer index)` + +Returns the specified item by its index into the array. + +| Parameter | Description | +|-----|-----| +|`Integer index` | The index into the array that points to the item to be returned. | + +
+ #### `Object get(Long index)` Returns the specified item by its index into the array. diff --git a/src/main/java/org/entityc/compiler/ASTVisitor.java b/src/main/java/org/entityc/compiler/ASTVisitor.java index 0f59d4f..1a2cd47 100644 --- a/src/main/java/org/entityc/compiler/ASTVisitor.java +++ b/src/main/java/org/entityc/compiler/ASTVisitor.java @@ -23,22 +23,7 @@ import org.entityc.compiler.model.config.MTTemplate; import org.entityc.compiler.model.config.MTTransform; import org.entityc.compiler.model.domain.*; -import org.entityc.compiler.model.entity.HalfRelationshipPlurality; -import org.entityc.compiler.model.entity.MTAttribute; -import org.entityc.compiler.model.entity.MTAttributeConstraint; -import org.entityc.compiler.model.entity.MTBitField; -import org.entityc.compiler.model.entity.MTEntity; -import org.entityc.compiler.model.entity.MTEntityTemplate; -import org.entityc.compiler.model.entity.MTEntityTemplateInstantiation; -import org.entityc.compiler.model.entity.MTEnum; -import org.entityc.compiler.model.entity.MTEnumItem; -import org.entityc.compiler.model.entity.MTNativeType; -import org.entityc.compiler.model.entity.MTPrimaryKey; -import org.entityc.compiler.model.entity.MTRelationship; -import org.entityc.compiler.model.entity.MTTagSet; -import org.entityc.compiler.model.entity.MTTypedef; -import org.entityc.compiler.model.entity.MTUnit; -import org.entityc.compiler.model.entity.MTView; +import org.entityc.compiler.model.entity.*; import org.entityc.compiler.model.expression.MTConstant; import org.entityc.compiler.model.expression.MTExpression; import org.entityc.compiler.model.expression.MTMethodCall; @@ -1652,6 +1637,7 @@ public Object visitDomainNaming(EntityLanguageParser.DomainNamingContext ctx) { } else if (namingClassContext.MODULE() != null) { classesWithNaming.add(MTModule.class); } else if (namingClassContext.ENTITY() != null) { + classesWithNaming.add(MTCompositeEntity.class); classesWithNaming.add(MTEntity.class); classesWithNaming.add(MTView.class); } else if (namingClassContext.ATTRIBUTE() != null) { diff --git a/src/main/java/org/entityc/compiler/EntityCompiler.java b/src/main/java/org/entityc/compiler/EntityCompiler.java index e30c164..15a2474 100644 --- a/src/main/java/org/entityc/compiler/EntityCompiler.java +++ b/src/main/java/org/entityc/compiler/EntityCompiler.java @@ -24,6 +24,8 @@ import org.entityc.compiler.repository.RepositoryFile; import org.entityc.compiler.repository.RepositoryImportManager; import org.entityc.compiler.transform.MTBaseTransform; +import org.entityc.compiler.transform.MTVImplicitTransform; +import org.entityc.compiler.transform.MTVReleasedTransform; import org.entityc.compiler.transform.TransformManager; import org.entityc.compiler.transform.template.FileTemplateTransform; import org.entityc.compiler.transform.template.TemplatePublishing; @@ -132,8 +134,9 @@ public static void RunTransforms(MTRoot root, MTConfiguration configuration) { root.resolveReferences(false); //model.processAssetAttributes(); root.getSpace().checkValidReferences(); + final String ImplicitTransformName = "Implicit"; - TransformManager.GetTransformByName("Implicit").start(); + TransformManager.GetTransformByName(ImplicitTransformName).start(null); for (MTTransform transformSpec : configuration.getTransforms()) { MTBaseTransform transform = TransformManager.GetTransformByName(transformSpec.getName()); @@ -143,8 +146,10 @@ public static void RunTransforms(MTRoot root, MTConfiguration configuration) { if (commandLine.verbose) { System.out.println("Running " + "transform" + " " + transform.getName()); } - transform.start(); + transform.start(null); } + MTBaseTransform implicitTransform = TransformManager.GetTransformByName(ImplicitTransformName); + ((MTVImplicitTransform)implicitTransform).start(MTVReleasedTransform.realm); root.resolveReferences(true); root.getSpace().checkValidReferences(); diff --git a/src/main/java/org/entityc/compiler/model/domain/MTDEntity.java b/src/main/java/org/entityc/compiler/model/domain/MTDEntity.java index e0c6360..0c19d91 100644 --- a/src/main/java/org/entityc/compiler/model/domain/MTDEntity.java +++ b/src/main/java/org/entityc/compiler/model/domain/MTDEntity.java @@ -104,6 +104,12 @@ public boolean hasDeclaredDomainAttributes() { return declaredDomainAttributes.size() > 0; } + @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, + description = "Indicates if any relationships were declared in this domain entity declaration.") + public boolean hasDeclaredDomainRelationships() { + return declaredDomainRelationships.size() > 0; + } + public void addAttribute(MTAttribute attribute) { if (entity != null && entity.hasAttributeNamed(attribute.getName())) { ECLog.logFatal(attribute, "The entity already has an attribute by the name: " + attribute.getName()); @@ -564,11 +570,18 @@ public MTDEntity primaryParentEntity() { @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "Returns the primary parent relationship of this domain entity. A primary parent " - + "relationship is one that has been declared as `parent` and **not** declared `optional`.") + + "relationship is one that has been declared as `parent` and **not** declared `optional`.") public MTDERelationship primaryParentRelationship() { return getDomainEntityRelationshipByName(entity.getPrimaryParentRelationship().getName(), true); } + @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, + description = "Indicates whether this domain entity has a parent relationship. A parent " + + "relationship is one that has been declared as `parent`") + public boolean hasParentRelationship() { + return entity != null && entity.hasParentRelationship(); + } + public MTDView getDomainEntityViewByName(String viewName, boolean createIfNeeded) { MTDView domainEntityView = domainViewMap.get(viewName); if (domainEntityView == null && domain.getParentDomain() != null) { diff --git a/src/main/java/org/entityc/compiler/model/entity/MTAttribute.java b/src/main/java/org/entityc/compiler/model/entity/MTAttribute.java index e96f308..7e5df55 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTAttribute.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTAttribute.java @@ -95,6 +95,9 @@ public MTAttribute(ParserRuleContext ctx, String entityName, String typeName, St protected MTAttribute(String secondaryName, MTAttribute primaryAttribute) { super(primaryAttribute.getParserRuleContext()); this.name = secondaryName; + this.description = primaryAttribute.getDescription(); + this.setSummary(primaryAttribute.getSummary());; + this.setDetail(primaryAttribute.getDetail());; this.entityName = primaryAttribute.entityName; this.entity = primaryAttribute.entity; this.unit = primaryAttribute.unit; diff --git a/src/main/java/org/entityc/compiler/model/entity/MTCompositeEntity.java b/src/main/java/org/entityc/compiler/model/entity/MTCompositeEntity.java new file mode 100644 index 0000000..ace4b1f --- /dev/null +++ b/src/main/java/org/entityc/compiler/model/entity/MTCompositeEntity.java @@ -0,0 +1,42 @@ +package org.entityc.compiler.model.entity; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.entityc.compiler.model.MTModule; +import org.entityc.compiler.util.ECLog; + +import java.util.HashMap; +import java.util.Map; + +public class MTCompositeEntity extends MTEntity { + + public static final String ObjectTag = "object"; + public static final String VersionTag = "version"; + public static final String ReleaseTag = "release"; + + Map constituentEntities = new HashMap<>(); + + public MTCompositeEntity(ParserRuleContext ctx, MTModule module, String name) { + super(ctx, module, name); + } + + private void addConstituentEntity(String tag, MTEntity entity) { + if (this.constituentEntities.containsKey(tag) ) { + if (!this.constituentEntities.get(tag).name.equals(entity.name)) { + ECLog.logFatal("This composite entity " + this.name + " is already associated to a different entity with the " + tag + " tag."); + } else { + return; + } + } + this.constituentEntities.put(tag, entity); + } + + public MTEntity getConstituentEntity(String tag) { + return constituentEntities.get(tag); + } + + public void addAttribute(String tag, MTAttribute attribute, MTEntity fromEntity) { + addConstituentEntity(tag, fromEntity); + MTAttribute constituentAttribute = MTAttribute.Copy(attribute, this); + super.addAttribute(constituentAttribute); + } +} diff --git a/src/main/java/org/entityc/compiler/model/entity/MTEntity.java b/src/main/java/org/entityc/compiler/model/entity/MTEntity.java index e457338..12cdba7 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTEntity.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTEntity.java @@ -21,13 +21,7 @@ import org.entityc.compiler.util.ECLog; import org.entityc.compiler.util.ECStringUtil; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Stack; -import java.util.Vector; +import java.util.*; import java.util.stream.Collectors; import static org.entityc.compiler.doc.annotation.ModelMethodCategory.ENTITY_TEMPLATE; @@ -59,6 +53,7 @@ public class MTEntity extends MTType implements MTReferenceResolution, MTNamed, private int largestFieldNumber = 0; private MTSpace space; private MTAttribute manyAttribute = null; // if the entity was created from a "many attributeName" + protected Set realms = new HashSet<>(); // a space entities can live in separate from the others - such as for composite entities public MTEntity(ParserRuleContext ctx, MTModule module, String name) { super(ctx); @@ -89,6 +84,19 @@ public String getName() { return name; } + @ModelMethod(category = ModelMethodCategory.ENTITY, + description = "Adds the entity to a realm.") + public void addRealm(String realm) { + ECLog.logInfo("Added entity: " + getName() + " to realm " + realm); + realms.add(realm); + } + + @ModelMethod(category = ModelMethodCategory.ENTITY, + description = "Returns true if this entity is part of a realm.") + public boolean isInRealm(String realm) { + return this.realms.contains(realm); + } + public static MTEntity AddImplicitManyToManyEntity(MTSpace space, MTEntity fromEntity, MTEntity toEntity) { MTEntity combinedEntity = CombineEntities(fromEntity, toEntity); MTEntity alreadyCreatedEntity = space.getEntityWithName(combinedEntity.getName()); @@ -929,7 +937,7 @@ public MTAttribute attributeTagged( description = "Indicates whether this entity has at least one relationship with the specified tag.") public boolean hasRelationshipTagged( @ModelMethodParameter(description = "The tag with which to search.") - String tag) { + String tag) { for (MTRelationship relationship : getRelationships()) { if (relationship.hasTag(tag)) { return true; @@ -938,6 +946,20 @@ public boolean hasRelationshipTagged( return false; } + @ModelMethod( + category = ModelMethodCategory.TAGGING, + description = "Indicates whether this entity has at least one relationship to a named other entity.") + public boolean hasRelationshipToEntityNamed( + @ModelMethodParameter(description = "The name of the other entity.") + String toEntityName) { + for (MTRelationship relationship : getRelationships()) { + if (relationship.getTo().getEntityName().equals(toEntityName)) { + return true; + } + } + return false; + } + @ModelMethod( category = ModelMethodCategory.TAGGING, description = "Returns a relationship of this entity that is tagged with the specified tag.") diff --git a/src/main/java/org/entityc/compiler/model/entity/MTEnum.java b/src/main/java/org/entityc/compiler/model/entity/MTEnum.java index 5b13f31..170a27c 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTEnum.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTEnum.java @@ -65,6 +65,10 @@ public int getItemCount() { return items.size(); } + @ModelMethod(category = ModelMethodCategory.ENUM, description = "Returns an item by its index.") + public MTEnumItem getItem(Long index) { + return getItem(index.intValue()); + } public MTEnumItem getItem(int index) { return items.get(index); } diff --git a/src/main/java/org/entityc/compiler/model/entity/MTRelationship.java b/src/main/java/org/entityc/compiler/model/entity/MTRelationship.java index e472e2c..2518e61 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTRelationship.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTRelationship.java @@ -18,6 +18,7 @@ import org.entityc.compiler.model.domain.MTNamed; import org.entityc.compiler.model.visitor.MTVisitor; import org.entityc.compiler.util.ECLog; +import org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.Copy; import java.util.List; @@ -62,11 +63,15 @@ public MTRelationship(ParserRuleContext ctx, this.templateArgName = templateArgName; } - protected MTRelationship(String secondaryName, MTRelationship primaryRelationship) { + protected MTRelationship(String secondaryName, MTRelationship primaryRelationship, MTRelationshipHalf fromHalf, MTRelationshipHalf toHalf) { super(primaryRelationship.getParserRuleContext()); this.name = secondaryName; - this.from = primaryRelationship.from; - this.to = primaryRelationship.to; + this.from = fromHalf; + if (toHalf != null) { + this.to = toHalf; + } else { + this.to = primaryRelationship.to; + } this.optional = primaryRelationship.optional; this.parent = primaryRelationship.parent; this.reverseName = primaryRelationship.reverseName; @@ -74,6 +79,23 @@ protected MTRelationship(String secondaryName, MTRelationship primaryRelationshi this.templateArgName = primaryRelationship.templateArgName; } + public static MTRelationship Copy(MTRelationship relationship, MTEntity newFromEntity, MTEntity newToEntity) { + + MTRelationshipHalf fromHalf = new MTRelationshipHalf(relationship.getParserRuleContext(), + relationship.getFrom().getPlurality(), newFromEntity.getName()); + fromHalf.setEntity(newFromEntity); + + MTRelationshipHalf toHalf = null; + if (newToEntity != null) { + toHalf = new MTRelationshipHalf(relationship.getParserRuleContext(), + relationship.getTo().getPlurality(), newToEntity.getName()); + toHalf.setEntity(newToEntity); + } + + MTRelationship copy = new MTRelationship(relationship.getName(), relationship, fromHalf, toHalf); + return copy; + } + @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "Indicates whether the relationship was created because although it was not declared it can be " + "implied based on relationships declared to this entity.") @@ -304,7 +326,7 @@ public boolean resolveReferences(MTSpace space, int pass) { } else { // good unnamed pairing - //System.out.println("unnamed Relationship \"" + getName() + "\" pairing between " + fromEntity.getName() + "." + this.getName() + " and " + toEntity.getName() + "." + fromRelationship.getName()); + System.out.println("unnamed Relationship \"" + getName() + "\" pairing between " + from.getEntityName() + "." + this.getName() + " and " + to.getEntityName() + "." + fromRelationship.getName()); this.reverseRelationship = fromRelationship; this.from.setPlurality(fromRelationship.to.getPlurality()); found = true; diff --git a/src/main/java/org/entityc/compiler/model/entity/MTSecondaryRelationship.java b/src/main/java/org/entityc/compiler/model/entity/MTSecondaryRelationship.java index f7587e7..10b5301 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTSecondaryRelationship.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTSecondaryRelationship.java @@ -15,7 +15,7 @@ public class MTSecondaryRelationship extends MTRelationship { private MTRelationship relationship; public MTSecondaryRelationship(String fullName, Stack path, MTRelationship relationship) { - super(fullName, relationship); + super(fullName, relationship, relationship.getFrom(), null); this.fullName = fullName; this.path = path; } diff --git a/src/main/java/org/entityc/compiler/model/entity/MTType.java b/src/main/java/org/entityc/compiler/model/entity/MTType.java index 6b8f8e6..5d2169e 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTType.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTType.java @@ -55,6 +55,12 @@ public boolean isDateType() { return isNativeDataType(MTNativeType.DataType.DATE); } + @ModelMethod(category = ModelMethodCategory.TYPE, + description = "Indicates whether this type is the `data` data type.") + public boolean isDataType() { + return isNativeDataType(MTNativeType.DataType.BYTE_ARRAY); + } + public void accept(MTVisitor visitor) { } diff --git a/src/main/java/org/entityc/compiler/model/foundation/MFArray.java b/src/main/java/org/entityc/compiler/model/foundation/MFArray.java index 7602105..891eaf1 100644 --- a/src/main/java/org/entityc/compiler/model/foundation/MFArray.java +++ b/src/main/java/org/entityc/compiler/model/foundation/MFArray.java @@ -106,10 +106,17 @@ public Object first() { @ModelMethod(description = "Returns the specified item by its index into the array.") public Object get( @ModelMethodParameter(description = "The index into the array that points to the item to be returned.") - Long index) { + Long index) { return array.get(index.intValue()); } + @ModelMethod(description = "Returns the specified item by its index into the array.") + public Object get( + @ModelMethodParameter(description = "The index into the array that points to the item to be returned.") + Integer index) { + return array.get(index); + } + @ModelMethod(description = "Returns the index into the array associated with the specified object. If the object is " + "not found, a -1 is returned.") diff --git a/src/main/java/org/entityc/compiler/model/visitor/MTBaseVisitor.java b/src/main/java/org/entityc/compiler/model/visitor/MTBaseVisitor.java index b9af97a..ce88916 100644 --- a/src/main/java/org/entityc/compiler/model/visitor/MTBaseVisitor.java +++ b/src/main/java/org/entityc/compiler/model/visitor/MTBaseVisitor.java @@ -26,7 +26,7 @@ public MTBaseVisitor(MTRoot root) { this.root = root; } - public void start() { + public void start(String realm) { //ECLog.logInfo("Starting to visit model: " + model.getName()); visit(this.root); } diff --git a/src/main/java/org/entityc/compiler/transform/MTVImplicitTransform.java b/src/main/java/org/entityc/compiler/transform/MTVImplicitTransform.java index 26366d8..2e05ec8 100644 --- a/src/main/java/org/entityc/compiler/transform/MTVImplicitTransform.java +++ b/src/main/java/org/entityc/compiler/transform/MTVImplicitTransform.java @@ -8,17 +8,13 @@ import org.entityc.compiler.model.MTRoot; import org.entityc.compiler.model.config.MTSpace; -import org.entityc.compiler.model.entity.FullRelationshipPlurality; -import org.entityc.compiler.model.entity.MTAttribute; -import org.entityc.compiler.model.entity.MTEntity; -import org.entityc.compiler.model.entity.MTEnum; -import org.entityc.compiler.model.entity.MTPrimaryKey; -import org.entityc.compiler.model.entity.MTRelationship; +import org.entityc.compiler.model.entity.*; import org.entityc.compiler.util.ECLog; // TODO: Create index from parent relationships public class MTVImplicitTransform extends MTBaseTransform { + private String realm = null; public MTVImplicitTransform(MTRoot root, String configurationName) { super("Implicit", root, configurationName); @@ -71,12 +67,26 @@ public void visitRelationship(MTRelationship relationship) { MTEntity toEntity = relationship.getTo().getEntity(); if (toEntity == null || fromEntity == null) { relationship.resolveReferences(root.getSpace(), 0); - toEntity = relationship.getTo().getEntity(); + toEntity = relationship.getTo().getEntity(); fromEntity = relationship.getFrom().getEntity(); if (toEntity == null) { ECLog.logFatal("The entity \"" + fromEntity.getName() + "\" has a relationship \"" + relationship.getName() + "\" but not to anything."); } } + + // if this is a realm based transform then make sure we are operating on entities from that realm. + if (realm != null) { + if (!(fromEntity instanceof MTCompositeEntity) && (toEntity instanceof MTCompositeEntity)) { + ECLog.logInfo("(wrong class) REALM " + realm + ": not processing fromEntity: " + fromEntity.getName() + " toEntity: " + toEntity.getName()); + return; + } + if (!fromEntity.isInRealm(realm) || !toEntity.isInRealm(realm)) { + ECLog.logInfo("(wrong realm) REALM " + realm + ": not processing fromEntity: " + fromEntity.getName() + " toEntity: " + toEntity.getName()); + return; + } + ECLog.logInfo("REALM " + realm + ": PROCESSING fromEntity: " + fromEntity.getName() + " toEntity: " + toEntity.getName()); + } + MTPrimaryKey toPrimaryKey = toEntity.getPrimaryKey(); if (toPrimaryKey == null) { return; @@ -107,6 +117,12 @@ public String[] requiredDomainNames() { return new String[]{"Database"}; } + @Override + public void start(String realm) { + this.realm = realm; + super.start(realm); + } + @Override public boolean canStart() { return hasRequiredDomains(); diff --git a/src/main/java/org/entityc/compiler/transform/MTVPostgresTransform.java b/src/main/java/org/entityc/compiler/transform/MTVPostgresTransform.java index e082bc7..d0c5747 100644 --- a/src/main/java/org/entityc/compiler/transform/MTVPostgresTransform.java +++ b/src/main/java/org/entityc/compiler/transform/MTVPostgresTransform.java @@ -62,9 +62,9 @@ public MTVPostgresTransform(MTRoot root, String configurationName) { } @Override - public void start() { + public void start(String realm) { - super.start(); + super.start(realm); MTTransform transform = getConfiguration().getTransformByName(getName()); String outputName = transform.getOutputNameByLocalName("primary"); diff --git a/src/main/java/org/entityc/compiler/transform/MTVReleasedTransform.java b/src/main/java/org/entityc/compiler/transform/MTVReleasedTransform.java new file mode 100644 index 0000000..1328e21 --- /dev/null +++ b/src/main/java/org/entityc/compiler/transform/MTVReleasedTransform.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2019-2023 The EntityC Project. All rights reserved. + * Use of this file is governed by the BSD 3-clause license that + * can be found in the LICENSE.md file in the project root. + */ + +package org.entityc.compiler.transform; + +import org.entityc.compiler.model.MTModule; +import org.entityc.compiler.model.MTRoot; +import org.entityc.compiler.model.config.MTSpace; +import org.entityc.compiler.model.config.MTTransform; +import org.entityc.compiler.model.domain.MTDEAttribute; +import org.entityc.compiler.model.domain.MTDERelationship; +import org.entityc.compiler.model.domain.MTDEntity; +import org.entityc.compiler.model.domain.MTDomain; +import org.entityc.compiler.model.entity.*; +import org.entityc.compiler.structure.sql.SSSourceFile; +import org.entityc.compiler.util.ECLog; +import org.entityc.compiler.util.ECStringUtil; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This transform + */ +public class MTVReleasedTransform extends MTBaseTransform { + private final MTDomain releasedDomain; + private String compositEntityNamePrefix = ""; + private SSSourceFile sourceFile; + + public static final String realm = "released"; + + public MTVReleasedTransform(MTRoot root, String configurationName) { + super("Released", root, configurationName); + releasedDomain = root.getSpace().getDomainWithName("Released"); + compositEntityNamePrefix = "Released"; + } + + @Override + public boolean canStart() { + return true; + } + + @Override + public void start(String ignore) { + + super.start(realm); + + MTTransform transform = getConfiguration().getTransformByName(getName()); + + MTSpace space = this.root.getSpace(); + + Map compositeEntityMap = new HashMap<>(); + + for (MTModule module : space.getModules()) { + //ECLog.logInfo("--------------------------------------------------------- MODULE: " + module.getName()); + if (module.isIncluded()) { + //ECLog.logInfo("Ignoring module: " + module.getName()); + continue; + } + // Find all the ones that are not involved in versioning and add them + // to our new "version-less" realm. + for (MTEntity entity : module.getEntities()) { + if (entity.hasTag("release:binder") + || entity.hasTag("release:object") + || entity.hasTag("release:version")) { + continue; + } + entity.addRealm(realm); + } + List compositeEntityList = new ArrayList<>(); + for (MTEntity entity : module.getEntities()) { + if (!entity.hasTag("release:binder") || entity.isIncluded() || entity.isExtern() || entity.isImplicit()) { + continue; + } + + MTRelationship topRelationship = null; + MTRelationship objectRelationship = null; + MTRelationship versionRelationship = null; + + for (MTRelationship relationship : entity.getRelationships()) { + MTEntity toEntity = relationship.getTo().getEntity(); + if (relationship.isParent() && toEntity.hasTag("release:top")) { + topRelationship = relationship; + } + else if (toEntity.hasTag("release:object")) { + objectRelationship = relationship; + } + else if (toEntity.hasTag("release:version")) { + versionRelationship = relationship; + } + } + if (topRelationship == null) { + ECLog.logFatal(entity, "Unable to find release top."); + } + if (objectRelationship == null) { + ECLog.logFatal(entity, "Unable to find release object."); + } + if (versionRelationship == null) { + ECLog.logFatal(entity, "Unable to find release version."); + } + + MTEntity releaseEntity = topRelationship.getTo().getEntity(); + MTEntity objectEntity = objectRelationship.getTo().getEntity(); + MTEntity versionEntity = versionRelationship.getTo().getEntity(); + + // Now create a new entity that unifies these three + + MTCompositeEntity compositeEntity = new MTCompositeEntity(objectEntity.getParserRuleContext(), objectEntity.getModule(), compositEntityNamePrefix + objectEntity.getName()); + compositeEntity.addRealm(realm); + + // + // Object Entity Primary Key + // + MTAttribute primaryKeyAttribute = new MTAttribute(objectEntity.getParserRuleContext(), + compositeEntity, objectEntity.getPrimaryKeyAttribute().getTypeName(), + ECStringUtil.Uncapitalize(compositEntityNamePrefix) + ECStringUtil.Capitalize(objectEntity.getPrimaryKeyAttribute().getName())); + MTPrimaryKey newPrimaryKey = new MTPrimaryKey(objectEntity.getPrimaryKey().getParserRuleContext()); + newPrimaryKey.addAttribute(primaryKeyAttribute); + compositeEntity.setPrimaryKey(newPrimaryKey); + + // + // Foreign from Release + // + MTAttribute releaseEntityForeignKey = MTAttribute.Copy(releaseEntity.getPrimaryKeyAttribute(), compositeEntity); + releaseEntityForeignKey.setPrimaryKey(false); + compositeEntity.addAttribute(MTCompositeEntity.ReleaseTag, releaseEntityForeignKey, releaseEntity); + + // + // Object Entity Attributes + // + for (MTAttribute attribute : objectEntity.getAttributes()) { + if (attribute.isModification() || versionEntity.hasAttributeNamed(attribute.getName())) { + continue; + } + MTAttribute compositAttribute = MTAttribute.Copy(attribute, compositeEntity); + compositeEntity.addAttribute(MTCompositeEntity.ObjectTag, compositAttribute, objectEntity); + } + + // + // Version Entity Attributes + // + for (MTAttribute attribute : versionEntity.getAttributes()) { + if (attribute.isCreation()) { + continue; + } + MTAttribute compositAttribute = MTAttribute.Copy(attribute, compositeEntity); + compositAttribute.setDescription(attribute.getDescription()); + compositeEntity.addAttribute(MTCompositeEntity.VersionTag, compositAttribute, versionEntity); + } + + compositeEntityList.add(compositeEntity); + compositeEntityMap.put(objectEntity.getName(), compositeEntity); + compositeEntityMap.put(versionEntity.getName(), compositeEntity); + + // Relationships are more complicated so we first need to process all + // the entities first, then do another pass so we can randomly reference the other + // entities. + } + //ECLog.logInfo("FOUND " + compositeEntityList.size() + " composite objects in module: " + module.getName()); + for (MTCompositeEntity compositeEntity : compositeEntityList) { + MTEntity objectEntity = compositeEntity.getConstituentEntity(MTCompositeEntity.ObjectTag); + MTEntity versionEntity = compositeEntity.getConstituentEntity(MTCompositeEntity.VersionTag); + //ECLog.logInfo("Object entity " + objectEntity.getName() + " has " + objectEntity.getRelationshipCount() + " relationships."); + for (MTRelationship relationship : objectEntity.getRelationships()) { + //ECLog.logInfo(">>>> relationship: " + relationship.getName()); + if (compositeEntity.hasRelationshipNamed(relationship.getName())) { + ECLog.logWarning("We have already copied relationship: " + relationship.getName()); + continue; + } + MTEntity toEntity = relationship.getTo().getEntity(); + // don't take relationships to version + if (toEntity.getName().equals(versionEntity.getName())) { + continue; + } + if (!compositeEntityMap.containsKey(toEntity.getName())) { + // we can copy the relationship exactly - just have to fix the "from" which is done + // in the Copy method. + MTRelationship newRelationship = MTRelationship.Copy(relationship, compositeEntity, null); + //ECLog.logInfo("Adding Composite Object Relationship to non-composite entity: " + newRelationship.getName()); + compositeEntity.addRelationship(newRelationship); + continue; + } + MTCompositeEntity toCompositeEntity = compositeEntityMap.get(toEntity.getName()); + MTRelationship newRelationship = MTRelationship.Copy(relationship, compositeEntity, toCompositeEntity); + compositeEntity.addRelationship(newRelationship); + //ECLog.logInfo("Adding Composite Object Relationship to Composite object: " + newRelationship.getName()); + } + //ECLog.logInfo("Version entity " + versionEntity.getName() + " has " + versionEntity.getRelationshipCount() + " relationships."); + for (MTRelationship relationship : versionEntity.getRelationships()) { + MTEntity toEntity = relationship.getTo().getEntity(); + // don't take relationships to object parent + if (relationship.isParent() && toEntity.getName().equals(objectEntity.getName())) { + continue; + } + if (!compositeEntityMap.containsKey(toEntity.getName())) { + // we can copy the relationship exactly - just have to fix the "from" which is done + // in the Copy method. + MTRelationship newRelationship = MTRelationship.Copy(relationship, compositeEntity, null); + //ECLog.logInfo("Adding Composite Version Relationship to non-composite entity: " + newRelationship.getName()); + compositeEntity.addRelationship(newRelationship); + continue; + } + MTCompositeEntity toCompositeEntity = compositeEntityMap.get(toEntity.getName()); + MTRelationship newRelationship = MTRelationship.Copy(relationship, compositeEntity, toCompositeEntity); + //ECLog.logInfo("Adding Composite Version Relationship to Composite object: " + newRelationship.getName()); + compositeEntity.addRelationship(newRelationship); + } + compositeEntity.getModule().addEntity(compositeEntity); + space.addEntity(compositeEntity); + } + } + + } +} diff --git a/src/main/java/org/entityc/compiler/transform/TransformManager.java b/src/main/java/org/entityc/compiler/transform/TransformManager.java index 938643b..4d2a7dc 100644 --- a/src/main/java/org/entityc/compiler/transform/TransformManager.java +++ b/src/main/java/org/entityc/compiler/transform/TransformManager.java @@ -6,7 +6,6 @@ package org.entityc.compiler.transform; -import org.entityc.compiler.EntityCompiler; import org.entityc.compiler.cmdline.CommandLine; import org.entityc.compiler.model.MTRoot; @@ -22,6 +21,7 @@ public static void LoadBuiltins(MTRoot model, String configurationName) { // Server AddTransform(new MTVImplicitTransform(model, configurationName)); AddTransform(new MTVPostgresTransform(model, configurationName)); + AddTransform(new MTVReleasedTransform(model, configurationName)); } public static void AddTransform(MTBaseTransform transform) { diff --git a/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTJoinFilter.java b/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTJoinFilter.java index f145f43..2b22677 100644 --- a/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTJoinFilter.java +++ b/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTJoinFilter.java @@ -10,6 +10,7 @@ import org.entityc.compiler.model.foundation.MFArray; import org.entityc.compiler.transform.template.tree.FTTransformSession; import org.entityc.compiler.transform.template.tree.expression.FTExpression; +import org.entityc.compiler.util.ECStringUtil; import java.util.List; import java.util.Map; @@ -32,6 +33,7 @@ public Object filter(ParserRuleContext ctx, FTTransformSession session, Object i String delim = " "; if (hasOptionValue(options, delimiterOption)) { delim = getOptionStringValue(options, delimiterOption); + delim = ECStringUtil.ProcessParserString(delim); } if (input instanceof String) { String inputString = (String) input; From f76cf791c93b9ba71696be417f3d6391a3c28289 Mon Sep 17 00:00:00 2001 From: Bob Garner Date: Fri, 17 Nov 2023 05:40:46 -0800 Subject: [PATCH 09/12] Added realm support and improved Released transform. --- docs/emc/EMC_config.md | 20 + .../org/entityc/compiler/EntityLanguage.g4 | 23 +- .../java/org/entityc/compiler/ASTVisitor.java | 836 ++++++++++-------- .../org/entityc/compiler/model/MTRealm.java | 24 + .../compiler/model/config/MTSpace.java | 20 +- .../compiler/model/domain/MTDomain.java | 2 +- .../model/entity/MTCompositeEntity.java | 35 +- .../compiler/model/entity/MTEntity.java | 8 +- .../compiler/model/entity/MTRelationship.java | 6 +- .../transform/MTVImplicitTransform.java | 6 +- .../transform/MTVReleasedTransform.java | 218 ++++- .../transform/template/tree/FTOutlet.java | 3 + .../tree/filter/FTFullnameFilter.java | 11 + .../template/tree/filter/FTReverseFilter.java | 7 +- 14 files changed, 837 insertions(+), 382 deletions(-) create mode 100644 src/main/java/org/entityc/compiler/model/MTRealm.java diff --git a/docs/emc/EMC_config.md b/docs/emc/EMC_config.md index 12e27bf..5c6238e 100644 --- a/docs/emc/EMC_config.md +++ b/docs/emc/EMC_config.md @@ -350,6 +350,16 @@ Indicates whether this space has a metadata name/value for the specified name.
+#### `boolean hasRealmWithName(String realm)` + +Returns true if there is a realm by this name. + +| Parameter | Description | +|-----|-----| +|`String realm` | *no description* | + +
+ #### `List` **`importEntityNames`** Returns the names of the entities that have been imported into this space. @@ -372,6 +382,16 @@ Spaces can define a dictionary of name/value pairs that provide some meta data a
+#### `MTRealm realmWithName(String realm)` + +Returns the realm object by its name. + +| Parameter | Description | +|-----|-----| +|`String realm` | *no description* | + +
+ #### `MTRepository repository(String name)` Returns the repository object by its name. diff --git a/src/main/antlr4/org/entityc/compiler/EntityLanguage.g4 b/src/main/antlr4/org/entityc/compiler/EntityLanguage.g4 index 44b8848..874276c 100644 --- a/src/main/antlr4/org/entityc/compiler/EntityLanguage.g4 +++ b/src/main/antlr4/org/entityc/compiler/EntityLanguage.g4 @@ -91,6 +91,7 @@ HUMAN : 'human' ; READABLE : 'readable' ; IDENTIFICATION : 'identification' ; +REALM : 'realm' ; DOMAIN : 'domain' ; ATTRIBUTES : 'attributes' ; REPLACES : 'replaces' ; @@ -189,7 +190,7 @@ ident | INTERFACE | OPERATION | QUERY | STATUS | CUSTOM | PARAM | TYPE | ENDPOINT | CONFIG | CONTEXT | ARGUMENT | HUMAN | READABLE | IDENTIFICATION | NAME | ORGANIZATION | REQUIRES | ROLE | READ | WRITE | WHEN | USER | ARRAY - | APPLY | DESCRIPTION | TAGS | METADATA | FORMATTING | FORMAT | COMMENTS + | APPLY | DESCRIPTION | TAGS | METADATA | FORMATTING | FORMAT | COMMENTS | REALM ; macro @@ -274,6 +275,7 @@ root | entity | enumStatement | domain + | realm | configuration | units | language @@ -585,6 +587,17 @@ bitCount : '(' INTEGER ')' ; +realm + : REALM id '{' realmBody '}' + ; + +realmBody + : + ( descriptionStatement + | tagStatement + | domain + )* + ; /* * DOMAIN @@ -755,7 +768,7 @@ domainApplyTemplateBody : ( descriptionStatement | tagStatement - | templateConfig + | transformConfig )* ; @@ -763,7 +776,7 @@ defaultTemplateConfig : DEFAULT CONFIG jsonObj ; -templateConfig +transformConfig : CONFIG jsonObj ; @@ -1247,7 +1260,7 @@ templateBody ( descriptionStatement | tagStatement | outputSpec - | templateConfig + | transformConfig )* ; @@ -1267,6 +1280,8 @@ transform transformBody : ( outputSpec + | transformConfig + | REALM id )* ; diff --git a/src/main/java/org/entityc/compiler/ASTVisitor.java b/src/main/java/org/entityc/compiler/ASTVisitor.java index 1a2cd47..776cb52 100644 --- a/src/main/java/org/entityc/compiler/ASTVisitor.java +++ b/src/main/java/org/entityc/compiler/ASTVisitor.java @@ -6,11 +6,7 @@ package org.entityc.compiler; -import org.entityc.compiler.model.MTCodeFormat; -import org.entityc.compiler.model.MTModule; -import org.entityc.compiler.model.MTNamespace; -import org.entityc.compiler.model.MTNode; -import org.entityc.compiler.model.MTRoot; +import org.entityc.compiler.model.*; import org.entityc.compiler.model.config.MTConfiguration; import org.entityc.compiler.model.config.MTDirectory; import org.entityc.compiler.model.config.MTProtoc; @@ -68,24 +64,25 @@ public class ASTVisitor extends EntityLanguageBaseVisitor { private final Map> abstractViewContexts = new HashMap<>(); - private final Stack spaceStack = new Stack<>(); - private MTRoot root; - private MTDomain currentDomain; - private MTModule currentModule; - private MTEntity currentEntity; - private MTAttribute currentAttribute; - private MTDModule currentDomainModule; - private MTDEntity currentDomainEntity; - private MTDERelationship currentDomainRelationship; - private MTDEnum currentDomainEnum; - private MTLanguage currentLanguage; - private MTConfiguration currentConfiguration; - private MTInterface currentInterface; - private MTRequest currentRequest; - private MTDEInterface currentDomainEntityInterface; - private MTDEInterfaceOperation currentDomainEntityInterfaceOperation; - private MTSpace foundSpace; - private List> inheritedTags; + private final Stack spaceStack = new Stack<>(); + private MTRoot root; + private MTRealm currentRealm; + private MTDomain currentDomain; + private MTModule currentModule; + private MTEntity currentEntity; + private MTAttribute currentAttribute; + private MTDModule currentDomainModule; + private MTDEntity currentDomainEntity; + private MTDERelationship currentDomainRelationship; + private MTDEnum currentDomainEnum; + private MTLanguage currentLanguage; + private MTConfiguration currentConfiguration; + private MTInterface currentInterface; + private MTRequest currentRequest; + private MTDEInterface currentDomainEntityInterface; + private MTDEInterfaceOperation currentDomainEntityInterfaceOperation; + private MTSpace foundSpace; + private List> inheritedTags; public MTSpace getFoundSpace() { return foundSpace; @@ -101,7 +98,8 @@ public MTRoot visitRoot(EntityLanguageParser.RootContext ctx, MTRoot root, MTSpa if (!hasCurrentSpace()) { if (space != null) { pushSpace(space); - } else if (root.getSpace() != null) { + } + else if (root.getSpace() != null) { pushSpace(root.getSpace()); } } @@ -139,6 +137,14 @@ public MTRoot visitRoot(EntityLanguageParser.RootContext ctx, MTRoot root, MTSpa currentSpace().addModule(module); } + for (EntityLanguageParser.RealmContext realmContext : ctx.realm()) { + if (!hasCurrentSpace()) { + ECLog.logFatal("Realm" + fatalMessage); + } + MTRealm realm = (MTRealm) visit(realmContext); + currentSpace().addRealm(realm); + } + for (EntityLanguageParser.DomainContext domainContext : ctx.domain()) { if (!hasCurrentSpace()) { ECLog.logFatal("Domain" + fatalMessage); @@ -201,18 +207,19 @@ public Object visitUnits(EntityLanguageParser.UnitsContext ctx) { ECLog.logInfo("READING UNITS..."); } for (EntityLanguageParser.UnitDefinitionContext unitDefinitionContext : ctx.unitsBody().unitDefinition()) { - String name = unitDefinitionContext.id(0).getText(); - String baseUnitName = unitDefinitionContext.EXTENDS() != null ? - unitDefinitionContext.id(1).getText() : - null; - EntityLanguageParser.UnitDefinitionBodyContext body = unitDefinitionContext.unitDefinitionBody(); - String abbr = null; - double multiplier = 1.0; + String name = unitDefinitionContext.id(0).getText(); + String baseUnitName = unitDefinitionContext.EXTENDS() != null ? + unitDefinitionContext.id(1).getText() : + null; + EntityLanguageParser.UnitDefinitionBodyContext body = unitDefinitionContext.unitDefinitionBody(); + String abbr = null; + double multiplier = 1.0; if (body != null) { for (EntityLanguageParser.UnitDefinitionFieldContext field : body.unitDefinitionField()) { if (field.ABBR() != null) { abbr = ECStringUtil.ProcessParserString(field.STRING().getText()); - } else if (field.MULTIPLIER() != null) { + } + else if (field.MULTIPLIER() != null) { multiplier = Double.valueOf(field.FLOAT().getText()); } } @@ -251,10 +258,10 @@ public MTInterface visitAbstractInterfaceStatement(EntityLanguageParser.Abstract @Override public MTTypedef visitTypedefStatement(EntityLanguageParser.TypedefStatementContext ctx) { - int bitWidth = ctx.INT32_TYPE() != null ? - 32 : - 64; - MTTypedef typedef = new MTTypedef(ctx, currentModule, bitWidth, ctx.id().getText()); + int bitWidth = ctx.INT32_TYPE() != null ? + 32 : + 64; + MTTypedef typedef = new MTTypedef(ctx, currentModule, bitWidth, ctx.id().getText()); if (ctx.typedefBody().descriptionStatement() != null) { setNodeDescription(typedef, ctx.typedefBody().descriptionStatement(), false); } @@ -296,8 +303,8 @@ public MTInterfaceOperation visitOperation(EntityLanguageParser.OperationContext @Override public MTOperationConfig visitOperationConfig(EntityLanguageParser.OperationConfigContext ctx) { - MTOperationConfig config = new MTOperationConfig(ctx); - EntityLanguageParser.OperationConfigBlockContext block = ctx.operationConfigBlock(); + MTOperationConfig config = new MTOperationConfig(ctx); + EntityLanguageParser.OperationConfigBlockContext block = ctx.operationConfigBlock(); for (EntityLanguageParser.OperationConfigContextContext contextContext : block.operationConfigContext()) { config.addArgument(visitOperationConfigContext(contextContext)); @@ -335,8 +342,8 @@ public MTRequest visitOperationRequest(EntityLanguageParser.OperationRequestCont @Override public MTResponse visitOperationResponse(EntityLanguageParser.OperationResponseContext ctx) { - MTResponse response = new MTResponse(ctx); - EntityLanguageParser.OperationResponseBlockContext block = ctx.operationResponseBlock(); + MTResponse response = new MTResponse(ctx); + EntityLanguageParser.OperationResponseBlockContext block = ctx.operationResponseBlock(); if (block.operationResponseStatus() != null) { for (EntityLanguageParser.OperationResponseStatusContext statusContext : block.operationResponseStatus()) { @@ -355,12 +362,12 @@ public MTResponse visitOperationResponse(EntityLanguageParser.OperationResponseC @Override public MTOperationConfigArgument visitOperationConfigContext(EntityLanguageParser.OperationConfigContextContext ctx) { MTOperationConfigArgument.ArgumentType contextType = MTOperationConfigArgument.ArgumentType.FromName( - ctx.operationConfigContextType().getText()); - MTOperationConfigArgument argument = new MTOperationConfigArgument(ctx, contextType, - ctx.id(0).getText(), - ctx.id().size() > 1 ? - ctx.id(1).getText() : - null, true); + ctx.operationConfigContextType().getText()); + MTOperationConfigArgument argument = new MTOperationConfigArgument(ctx, contextType, + ctx.id(0).getText(), + ctx.id().size() > 1 ? + ctx.id(1).getText() : + null, true); if (ctx.operationContextBlock().descriptionStatement() != null) { setNodeDescription(argument, ctx.operationContextBlock().descriptionStatement(), false); } @@ -370,12 +377,12 @@ public MTOperationConfigArgument visitOperationConfigContext(EntityLanguageParse @Override public MTOperationConfigArgument visitOperationConfigArgument(EntityLanguageParser.OperationConfigArgumentContext ctx) { MTOperationConfigArgument.ArgumentType argumentType = MTOperationConfigArgument.ArgumentType.FromName( - ctx.operationConfigArgumentType().getText()); - MTOperationConfigArgument argument = new MTOperationConfigArgument(ctx, argumentType, - ctx.id(0).getText(), - ctx.id().size() > 1 ? - ctx.id(1).getText() : - null, false); + ctx.operationConfigArgumentType().getText()); + MTOperationConfigArgument argument = new MTOperationConfigArgument(ctx, argumentType, + ctx.id(0).getText(), + ctx.id().size() > 1 ? + ctx.id(1).getText() : + null, false); if (ctx.operationArgumentBlock().descriptionStatement() != null) { setNodeDescription(argument, ctx.operationArgumentBlock().descriptionStatement(), false); } @@ -384,7 +391,7 @@ public MTOperationConfigArgument visitOperationConfigArgument(EntityLanguagePars @Override public MTRequestBody visitOperationRequestBody(EntityLanguageParser.OperationRequestBodyContext ctx) { - MTRequestBody body = new MTRequestBody(ctx); + MTRequestBody body = new MTRequestBody(ctx); EntityLanguageParser.OperationRequestBodyBlockContext block = ctx.operationRequestBodyBlock(); if (block.operationBodyContentType() != null && block.operationBodyContentType().size() > 0) { body.setContentType(ECStringUtil.ProcessParserString(block.operationBodyContentType(0).STRING().getText())); @@ -406,8 +413,8 @@ public MTRequestEndpoint visitOperationRequestEndpoint(EntityLanguageParser.Oper if (ctx.STRING() != null) { pathUrlString = ctx.STRING().getText(); } - MTRequestEndpoint path = new MTRequestEndpoint(ctx, currentRequest, - pathUrlString); + MTRequestEndpoint path = new MTRequestEndpoint(ctx, currentRequest, + pathUrlString); EntityLanguageParser.OperationRequestEndpointBlockContext block = ctx.operationRequestEndpointBlock(); if (block != null) { @@ -428,11 +435,12 @@ public MTResponseStatus visitOperationResponseStatus(EntityLanguageParser.Operat String statusText = null; if (ctx.id() != null) { statusText = ctx.id().getText(); - } else if (ctx.INTEGER() != null) { + } + else if (ctx.INTEGER() != null) { statusText = ctx.INTEGER().getText(); } - MTResponseStatus status = new MTResponseStatus(ctx, statusText); - EntityLanguageParser.OperationResponseStatusBlockContext block = ctx.operationResponseStatusBlock(); + MTResponseStatus status = new MTResponseStatus(ctx, statusText); + EntityLanguageParser.OperationResponseStatusBlockContext block = ctx.operationResponseStatusBlock(); if (block.descriptionStatement() != null) { setNodeDescription(status, block.descriptionStatement(), false); @@ -448,7 +456,7 @@ public MTResponseStatus visitOperationResponseStatus(EntityLanguageParser.Operat @Override public MTResponseBody visitOperationResponseBody(EntityLanguageParser.OperationResponseBodyContext ctx) { - MTResponseBody body = new MTResponseBody(ctx); + MTResponseBody body = new MTResponseBody(ctx); EntityLanguageParser.OperationResponseBodyBlockContext block = ctx.operationResponseBodyBlock(); if (block.operationBodyContentType() != null && block.operationBodyContentType().size() > 0) { body.setContentType(ECStringUtil.ProcessParserString(block.operationBodyContentType(0).STRING().getText())); @@ -465,17 +473,17 @@ public MTResponseBody visitOperationResponseBody(EntityLanguageParser.OperationR @Override public MTRequestEndpointParam visitOperationRequestEndpointParam(EntityLanguageParser.OperationRequestEndpointParamContext ctx) { - String paramName = ctx.id().getText(); - boolean query = ctx.QUERY() != null; - String typeName = ctx.type().getText(); - MTNativeType.DataType dataType = MTNativeType.DataType.FromName(typeName); + String paramName = ctx.id().getText(); + boolean query = ctx.QUERY() != null; + String typeName = ctx.type().getText(); + MTNativeType.DataType dataType = MTNativeType.DataType.FromName(typeName); if (dataType == null) { ECLog.logWarning(ctx.type(), "Operation parameters must be of a native type. Using int32."); dataType = MTNativeType.DataType.INT32; } MTRequestEndpointParam param = new MTRequestEndpointParam(ctx, query, new MTNativeType(ctx.type(), dataType), - paramName); + paramName); if (ctx.operationRequestEndpointParamBlock() != null && ctx.operationRequestEndpointParamBlock().descriptionStatement() != null) { @@ -493,21 +501,23 @@ public MTExpression visitExpression(EntityLanguageParser.ExpressionContext ctx) // Binary operator String opSymbol = ctx.bop.getText(); if (MTOperation.Operator.isValidOperator(opSymbol)) { - MTOperation.Operator operator = MTOperation.Operator.getOperatorBySymbol(opSymbol); - List operandExpressions = new ArrayList<>(3); + MTOperation.Operator operator = MTOperation.Operator.getOperatorBySymbol(opSymbol); + List operandExpressions = new ArrayList<>(3); if (ctx.ID() != null) { MTOperand operand = new MTOperand(ctx, MTOperand.Type.UNKNOWN, ctx.ID().getText()); if (operand != null) { operandExpressions.add(operand); } //ECLog.logInfo(">>>> With Operator: " + opSymbol + " and ID: " + ctx.ID().getText()); - } else if (ctx.methodCall() != null) { + } + else if (ctx.methodCall() != null) { MTExpression methodCall = visitMethodCall(ctx.methodCall()); if (methodCall != null) { operandExpressions.add(methodCall); } //ECLog.logInfo(">>>> With Operator: " + opSymbol + " and method call: " + ctx.methodCall().getText()); - } else { + } + else { //ECLog.logInfo(">>>> With Operator: " + opSymbol); } @@ -519,7 +529,8 @@ public MTExpression visitExpression(EntityLanguageParser.ExpressionContext ctx) MTExpression operandExpression = visitExpression(expressionContext); if (operandExpression != null) { operandExpressions.add(operandExpression); - } else { + } + else { ECLog.logFatal(expressionContext, "Unable to parse: " + expressionContext.getText()); } } @@ -529,17 +540,21 @@ public MTExpression visitExpression(EntityLanguageParser.ExpressionContext ctx) expression = new MTOperation(ctx, operator, operandExpressions); } - } else if (ctx.methodCall() != null) { + } + else if (ctx.methodCall() != null) { // Method call expression = visitMethodCall(ctx.methodCall()); - } else if (ctx.primary() != null) { + } + else if (ctx.primary() != null) { // Constant or a variable EntityLanguageParser.ConstantContext constantContext = ctx.primary().constant(); if (constantContext != null) { expression = visitConstant(ctx.primary().constant()); - } else if (ctx.primary().expression() != null) { + } + else if (ctx.primary().expression() != null) { expression = visitExpression(ctx.primary().expression()); - } else if (ctx.primary().ident() != null) { + } + else if (ctx.primary().ident() != null) { // could be either an entity attribute name or a config of an interface if (currentDomainEntityInterfaceOperation != null @@ -551,27 +566,30 @@ public MTExpression visitExpression(EntityLanguageParser.ExpressionContext ctx) return expression; } } - } else { + } + else { //ECLog.logInfo(ctx.primary(), "No domain operation context here: " + ctx.primary().ID().getText()); } // variable to an attribute name or other variable in the model if (currentDomainEntity == null) { expression = new MTOperand(ctx.primary(), MTOperand.Type.ATTRIBUTE, currentEntity.getName(), - ctx.primary().ident().getText()); + ctx.primary().ident().getText()); //ECLog.logFatal(ctx.primary(), "Attribute references can only be made in the context of an entity."); - } else { + } + else { expression = new MTOperand(ctx.primary(), MTOperand.Type.ATTRIBUTE, - currentDomainEntity.getEntityName(), ctx.primary().ident().getText()); + currentDomainEntity.getEntityName(), ctx.primary().ident().getText()); } } - } else if (ctx.prefix != null) { + } + else if (ctx.prefix != null) { String opSymbol = ctx.prefix.getText(); if (MTOperation.Operator.isValidOperator(opSymbol)) { if (ctx.expression().size() < 1) { ECLog.logFatal(ctx, "Unsupported expression: " + ctx.getText()); } MTOperation.Operator operator = MTOperation.Operator.getOperatorBySymbol(opSymbol); - List operands = new ArrayList<>(); + List operands = new ArrayList<>(); operands.add(visitExpression(ctx.expression().get(0))); expression = new MTOperation(ctx, operator, operands); } @@ -587,14 +605,18 @@ public MTConstant visitConstant(EntityLanguageParser.ConstantContext ctx) { MTConstant expression = null; if (ctx.STRING() != null) { expression = new MTConstant(ctx, ctx.STRING().getText()); - } else if (ctx.INTEGER() != null) { + } + else if (ctx.INTEGER() != null) { expression = new MTConstant(ctx, Long.valueOf(ctx.INTEGER().getText())); - } else if (ctx.FLOAT() != null) { + } + else if (ctx.FLOAT() != null) { expression = new MTConstant(ctx, Double.valueOf(ctx.FLOAT().getText())); - } else if (ctx.BOOLEAN != null) { + } + else if (ctx.BOOLEAN != null) { boolean value = ctx.BOOLEAN.getText().equals("true"); expression = new MTConstant(ctx, value); - } else { + } + else { ECLog.logFatal(ctx, "Unknown constant: " + ctx.getText()); } return expression; @@ -611,7 +633,8 @@ public MTMethodCall visitMethodCall(EntityLanguageParser.MethodCallContext ctx) MTExpression operandExpression = visitExpression(expressionContext); if (operandExpression != null) { methodCall.addArgument(operandExpression); - } else { + } + else { ECLog.logFatal(expressionContext, "Unable to parse: " + expressionContext.getText()); } } @@ -629,7 +652,8 @@ public String visitDefineVariableString(EntityLanguageParser.DefineVariableStrin ECLog.logFatal("Command line define variable \"" + ctx.id().getText() + "\" not set."); } path = idPath; - } else { + } + else { path = ECStringUtil.ProcessParserString(ctx.STRING().getText()); } return path; @@ -637,13 +661,13 @@ public String visitDefineVariableString(EntityLanguageParser.DefineVariableStrin @Override public Object visitRepository(EntityLanguageParser.RepositoryContext ctx) { - MTRepository repository = new MTRepository(ctx, ctx.id().getText()); + MTRepository repository = new MTRepository(ctx, ctx.id().getText()); EntityLanguageParser.RepositoryBodyContext repositoryBodyContext = ctx.repositoryBody(); List repositoryOrganizationContexts = repositoryBodyContext.repositoryOrganization(); if (repositoryOrganizationContexts != null && repositoryOrganizationContexts.size() > 0) { repository.setOrganization( - ECStringUtil.ProcessParserString(repositoryOrganizationContexts.get(0).STRING().getText())); + ECStringUtil.ProcessParserString(repositoryOrganizationContexts.get(0).STRING().getText())); } List repositoryNameContexts = repositoryBodyContext.repositoryName(); @@ -669,7 +693,7 @@ public Object visitRepository(EntityLanguageParser.RepositoryContext ctx) { MTRepositoryType type = MTRepositoryType.FromName(repositoryTypeContexts.get(0).id().getText()); if (type == null) { ECLog.logFatal(repositoryTypeContexts.get(0), - "Unknown repository type: " + repositoryTypeContexts.get(0).id().getText()); + "Unknown repository type: " + repositoryTypeContexts.get(0).id().getText()); } repository.setType(type); } @@ -683,8 +707,8 @@ public Object visitRepository(EntityLanguageParser.RepositoryContext ctx) { public MTSpace currentSpace() { return hasCurrentSpace() ? - spaceStack.peek() : - null; + spaceStack.peek() : + null; } private boolean hasCurrentSpace() { @@ -710,10 +734,11 @@ public MTSpace visitSpace(EntityLanguageParser.SpaceContext ctx) { int numNamespaces = body.spaceNamespace().size(); if (numNamespaces > 1) { ECLog.logError(body, "Only one namespace declaration is allowed."); - } else if (numNamespaces == 1) { + } + else if (numNamespaces == 1) { EntityLanguageParser.SpaceNamespaceContext ns = body.spaceNamespace(0); space.setNamespace( - new MTNamespace(ns, segmentsForPathID(ns.namespaceIdent().id()).toArray(new String[0]), false)); + new MTNamespace(ns, segmentsForPathID(ns.namespaceIdent().id()).toArray(new String[0]), false)); } // List importContexts = body.spaceImport(); @@ -762,9 +787,11 @@ public MTProtoc visitProtoc(EntityLanguageParser.ProtocContext ctx) { for (EntityLanguageParser.OutputSpecContext outputSpecContext : ctx.protocBody().outputSpec()) { if (outputSpecContext.id().size() == 1) { protoc.setSourceOutputName(outputSpecContext.id(0).getText()); - } else if (outputSpecContext.id(0).getText().equals("source")) { + } + else if (outputSpecContext.id(0).getText().equals("source")) { protoc.setSourceOutputName(outputSpecContext.id(1).getText()); - } else if (outputSpecContext.id(0).getText().equals("header")) { + } + else if (outputSpecContext.id(0).getText().equals("header")) { protoc.setHeaderOutputName(outputSpecContext.id(1).getText()); } } @@ -786,9 +813,9 @@ public MTProtoc visitProtoc(EntityLanguageParser.ProtocContext ctx) { public MTSpaceImport visitSpaceImport(EntityLanguageParser.SpaceImportContext ctx) { MTSpaceImport modelImport = new MTSpaceImport(); for (EntityLanguageParser.IdContext idContext : ctx.idList().id()) { - MTRepositoryImport repoImport = new MTRepositoryImport(ctx, false); - String filename = idContext.getText(); - String repositoryName = idText(ctx.id()); + MTRepositoryImport repoImport = new MTRepositoryImport(ctx, false); + String filename = idContext.getText(); + String repositoryName = idText(ctx.id()); repoImport.setFilename(filename); repoImport.setRepositoryName(repositoryName); modelImport.addImport(repoImport); @@ -802,9 +829,9 @@ public MTSpaceInclude visitSpaceInclude(EntityLanguageParser.SpaceIncludeContext MTSpaceInclude spaceInclude = new MTSpaceInclude(); for (EntityLanguageParser.IdContext idContext : ctx.idList().id()) { - MTRepositoryImport modelImport = new MTRepositoryImport(ctx, true); - String filename = idContext.getText(); - String repositoryName = idText(ctx.id()); + MTRepositoryImport modelImport = new MTRepositoryImport(ctx, true); + String filename = idContext.getText(); + String repositoryName = idText(ctx.id()); modelImport.setFilename(filename); modelImport.setRepositoryName(repositoryName); spaceInclude.addImport(modelImport); @@ -831,8 +858,8 @@ public MTSpaceInclude visitSpaceInclude(EntityLanguageParser.SpaceIncludeContext @Override public MTModule visitModule(EntityLanguageParser.ModuleContext ctx) { - String moduleName = ctx.id().getText(); - MTModule module = currentSpace().getModuleWithName(moduleName); + String moduleName = ctx.id().getText(); + MTModule module = currentSpace().getModuleWithName(moduleName); if (module == null) { module = new MTModule(ctx, currentSpace(), moduleName); } @@ -845,13 +872,13 @@ public MTModule visitModule(EntityLanguageParser.ModuleContext ctx) { } private void setNodeDescription - (MTNode node, - List statementContexts, - boolean append) { - StringBuilder mainBuilder = new StringBuilder(); - StringBuilder summaryBuilder = new StringBuilder(); - StringBuilder detailBuilder = new StringBuilder(); - Map builderMap = new HashMap<>(); + (MTNode node, + List statementContexts, + boolean append) { + StringBuilder mainBuilder = new StringBuilder(); + StringBuilder summaryBuilder = new StringBuilder(); + StringBuilder detailBuilder = new StringBuilder(); + Map builderMap = new HashMap<>(); builderMap.put("main", mainBuilder); builderMap.put("summary", summaryBuilder); builderMap.put("detail", detailBuilder); @@ -859,14 +886,15 @@ public MTModule visitModule(EntityLanguageParser.ModuleContext ctx) { List types = new ArrayList<>(); if (statementContext.id().size() == 0) { types.add("main"); // default when none specified - } else { + } + else { types = - statementContext.id().stream() - .map(EntityLanguageParser.IdContext::getText) - .collect(Collectors.toList()); + statementContext.id().stream() + .map(EntityLanguageParser.IdContext::getText) + .collect(Collectors.toList()); } String lineWithQuotes = statementContext.STRING().getSymbol().getText(); - String line = ECStringUtil.ProcessParserString(lineWithQuotes).trim(); + String line = ECStringUtil.ProcessParserString(lineWithQuotes).trim(); if (line.equals("")) { line = "\n\n"; @@ -876,8 +904,8 @@ public MTModule visitModule(EntityLanguageParser.ModuleContext ctx) { if (!builderMap.containsKey(type)) { ECLog.logFatal("Description type of \"" + type + "\" not supported."); } - StringBuilder builder = builderMap.get(type); - int builderLength = builder.length(); + StringBuilder builder = builderMap.get(type); + int builderLength = builder.length(); if (builderLength > 0) { char lastChar = builder.charAt(builderLength - 1); if (lastChar != '\n' && line.charAt(0) != '\n') { @@ -892,7 +920,8 @@ public MTModule visitModule(EntityLanguageParser.ModuleContext ctx) { mainString = mainString.replace("\\\"", "\""); if (append) { node.appendDescription(mainString); - } else { + } + else { node.setDescription(mainString); } } @@ -901,7 +930,8 @@ public MTModule visitModule(EntityLanguageParser.ModuleContext ctx) { summaryString = summaryString.replace("\\\"", "\""); if (append) { node.appendSummary(summaryString); - } else { + } + else { node.setSummary(summaryString); } } @@ -910,7 +940,8 @@ public MTModule visitModule(EntityLanguageParser.ModuleContext ctx) { detailString = detailString.replace("\\\"", "\""); if (append) { node.appendDetail(detailString); - } else { + } + else { node.setDetail(detailString); } } @@ -933,8 +964,8 @@ private List> tagStringsFromTagStatements(List templateArgs = new ArrayList<>(); - String entityName = null; + List templateArgs = new ArrayList<>(); + String entityName = null; EntityLanguageParser.EntityTemplateDeclContext templateDeclContext = ctx.entityDecl().entityTemplateDecl(); currentDomainEntity = null; @@ -944,8 +975,9 @@ public MTEntity visitEntity(EntityLanguageParser.EntityContext ctx) { templateArgs.add(templateDeclContext.id(i).getText()); } currentEntity = new MTEntityTemplate(ctx, currentModule, entityName, templateArgs); - } else { - entityName = ctx.entityDecl().entityName().id().getText(); + } + else { + entityName = ctx.entityDecl().entityName().id().getText(); currentEntity = new MTEntity(ctx, currentModule, entityName); } @@ -954,7 +986,8 @@ public MTEntity visitEntity(EntityLanguageParser.EntityContext ctx) { if (ctx.entityDecl().PRIMARY() != null) { currentEntity.setDeclaredAsPrimary(true); - } else if (ctx.entityDecl().SECONDARY() != null) { + } + else if (ctx.entityDecl().SECONDARY() != null) { currentEntity.setDeclaredAsSecondary(true); } @@ -984,17 +1017,18 @@ public MTEntity visitEntity(EntityLanguageParser.EntityContext ctx) { if (primaryKeyAttributes.size() > 0) { if (currentEntity.isDeclaredAsSecondary()) { ECLog.logError(ctx.entityDecl().entityName().id(), - "A secondary entity \"" + currentEntity.getName() + "\" cannot declare a primary key!"); + "A secondary entity \"" + currentEntity.getName() + "\" cannot declare a primary key!"); } MTPrimaryKey primaryKey = new MTPrimaryKey(ctx); for (MTAttribute attribute : primaryKeyAttributes) { primaryKey.addAttribute(attribute); } currentEntity.setPrimaryKey(primaryKey); - } else { + } + else { if (currentEntity.isDeclaredAsPrimary() && !currentEntity.isTransient()) { ECLog.logError(ctx.entityDecl().entityName().id(), - "A primary entity \"" + currentEntity.getName() + "\" must declare a primary key!"); + "A primary entity \"" + currentEntity.getName() + "\" must declare a primary key!"); } } @@ -1041,8 +1075,8 @@ public MTEntity visitEntity(EntityLanguageParser.EntityContext ctx) { @Override public MTEnum visitEnumStatement(EntityLanguageParser.EnumStatementContext ctx) { - String enumName = ctx.id().getText(); - boolean extern = ctx.EXTERN() != null; + String enumName = ctx.id().getText(); + boolean extern = ctx.EXTERN() != null; if (extern) { MTEnum existingEnum = currentSpace().getEnumWithName(enumName); if (existingEnum != null) { @@ -1056,8 +1090,8 @@ public MTEnum visitEnumStatement(EntityLanguageParser.EnumStatementContext ctx) } mtEnum.addTagsWithValues(tagStringsFromTagStatements(ctx.tagStatement())); for (EntityLanguageParser.EnumItemContext ic : ctx.enumItem()) { - String itemName = ic.id().getText(); - Integer itemNumber = Integer.valueOf(ic.INTEGER().getSymbol().getText()); + String itemName = ic.id().getText(); + Integer itemNumber = Integer.valueOf(ic.INTEGER().getSymbol().getText()); MTEnumItem mtEnumItem = mtEnum.addItem(ic, itemName, itemNumber); if (ic.enumItemBody() != null && ic.enumItemBody().tagStatement() != null) { mtEnumItem.addTagsWithValues(tagStringsFromTagStatements(ic.enumItemBody().tagStatement())); @@ -1080,10 +1114,10 @@ public MTEnum visitEnumStatement(EntityLanguageParser.EnumStatementContext ctx) @Override public MTDView visitView(EntityLanguageParser.ViewContext ctx) { - String currentEntityName = currentDomainEntity != null ? - currentDomainEntity.getEntityName() : - null; - MTDView domainView = new MTDView(ctx, currentDomain, currentEntityName, ctx.id().getText()); + String currentEntityName = currentDomainEntity != null ? + currentDomainEntity.getEntityName() : + null; + MTDView domainView = new MTDView(ctx, currentDomain, currentEntityName, ctx.id().getText()); // , ctx.DEFAULT() != null if (ctx.viewBlock() != null) { EntityLanguageParser.ViewBlockContext viewBlockContext = ctx.viewBlock(); @@ -1096,7 +1130,7 @@ public MTDView visitView(EntityLanguageParser.ViewContext ctx) { if (viewBlockContext.viewAttributes() != null && viewBlockContext.viewAttributes().size() > 0) { if (viewBlockContext.viewAttributes().size() > 1) { ECLog.logFatal(viewBlockContext.viewAttributes(1), - "Only specify one attributes section of a view."); + "Only specify one attributes section of a view."); } // INCLUDE EntityLanguageParser.ViewAttributesContext attributesContext = viewBlockContext.viewAttributes(0); @@ -1107,21 +1141,27 @@ public MTDView visitView(EntityLanguageParser.ViewContext ctx) { for (MTTagSet tagSet : visitViewTaggedList(vaiContext.viewTaggedList())) { if (secondaryEntities) { domainView.addIncludedAttributeSecondaryEntityTagSet(tagSet); - } else { + } + else { domainView.addIncludedAttributeTagSet(tagSet); } } - } else if (vaiContext.ARRAY() != null) { + } + else if (vaiContext.ARRAY() != null) { domainView.setIncludedArrayAttributes(true); - } else if (vaiContext.CREATION() != null) { + } + else if (vaiContext.CREATION() != null) { domainView.setIncludedCreationAttributes(true); - } else if (vaiContext.MODIFICATION() != null) { + } + else if (vaiContext.MODIFICATION() != null) { domainView.setIncludedModificationAttributes(true); - } else if (vaiContext.viewIdentifierList() != null && !vaiContext.viewIdentifierList().isEmpty()) { + } + else if (vaiContext.viewIdentifierList() != null && !vaiContext.viewIdentifierList().isEmpty()) { for (EntityLanguageParser.IdContext attrName : vaiContext.viewIdentifierList().id()) { domainView.addIncludedAttributeName(attrName.getText()); } - } else { + } + else { domainView.setIncludedAllAttributes(true); } } @@ -1133,21 +1173,27 @@ public MTDView visitView(EntityLanguageParser.ViewContext ctx) { for (MTTagSet tagSet : visitViewTaggedList(vaeContext.viewTaggedList())) { if (secondaryEntities) { domainView.addExcludedAttributeSecondaryEntityTagSet(tagSet); - } else { + } + else { domainView.addExcludedAttributeTagSet(tagSet); } } - } else if (vaeContext.ARRAY() != null) { + } + else if (vaeContext.ARRAY() != null) { domainView.setExcludedArrayAttributes(true); - } else if (vaeContext.CREATION() != null) { + } + else if (vaeContext.CREATION() != null) { domainView.setExcludedCreationAttributes(true); - } else if (vaeContext.MODIFICATION() != null) { + } + else if (vaeContext.MODIFICATION() != null) { domainView.setExcludedModificationAttributes(true); - } else if (vaeContext.viewIdentifierList() != null && !vaeContext.viewIdentifierList().isEmpty()) { + } + else if (vaeContext.viewIdentifierList() != null && !vaeContext.viewIdentifierList().isEmpty()) { for (EntityLanguageParser.IdContext attrName : vaeContext.viewIdentifierList().id()) { domainView.addExcludedAttributeName(attrName.getText()); } - } else { + } + else { domainView.setExcludedAllAttributes(true); } } @@ -1156,50 +1202,55 @@ public MTDView visitView(EntityLanguageParser.ViewContext ctx) { if (viewBlockContext.viewRelationships() != null && viewBlockContext.viewRelationships().size() > 0) { if (viewBlockContext.viewRelationships().size() > 1) { ECLog.logFatal(viewBlockContext.viewRelationships(1), - "Only specify one relationships section of a view."); + "Only specify one relationships section of a view."); } // INCLUDE EntityLanguageParser.ViewRelationshipsContext relationshipsContext = viewBlockContext.viewRelationships( - 0); + 0); for (EntityLanguageParser.ViewRelationshipIncludeContext vriContext : relationshipsContext.viewRelationshipsBlock().viewRelationshipInclude()) { - boolean hasAs = vriContext.AS() != null; - boolean hasWithView = vriContext.WITH() != null && vriContext.VIEW() != null; - boolean entityRef = vriContext.ENTITY() != null; - int usedIdCount = (hasAs ? - 1 : - 0) + (hasWithView ? - 1 : - 0); + boolean hasAs = vriContext.AS() != null; + boolean hasWithView = vriContext.WITH() != null && vriContext.VIEW() != null; + boolean entityRef = vriContext.ENTITY() != null; + int usedIdCount = (hasAs ? + 1 : + 0) + (hasWithView ? + 1 : + 0); boolean hasEntityOrRelationshipId = vriContext.id().size() > usedIdCount; - int viewIdIndex = hasEntityOrRelationshipId ? - 1 : - 0; - String relationshipOrEntityName = hasEntityOrRelationshipId ? - vriContext.id(0).getText() : - null; + int viewIdIndex = hasEntityOrRelationshipId ? + 1 : + 0; + String relationshipOrEntityName = hasEntityOrRelationshipId ? + vriContext.id(0).getText() : + null; if (vriContext.TAGGED() != null) { for (MTTagSet tagSet : visitViewTaggedList(vriContext.viewTaggedList())) { domainView.addIncludedRelationshipTagSet(tagSet); } - } else if (!hasEntityOrRelationshipId) { + } + else if (!hasEntityOrRelationshipId) { if (vriContext.PARENT() != null) { domainView.setIncludedParentRelationships(true); - } else if (vriContext.TOONE() != null) { + } + else if (vriContext.TOONE() != null) { domainView.setIncludedOneRelationships(true); - } else if (vriContext.TOMANY() != null) { + } + else if (vriContext.TOMANY() != null) { domainView.setIncludedManyRelationships(true); } - } else { + } + else { if (entityRef) { domainView.addIncludedRelationshipEntityName(relationshipOrEntityName); if (vriContext.AS() != null) { domainView.renameRelationshipOfEntityName(relationshipOrEntityName, - vriContext.id(1).getText()); + vriContext.id(1).getText()); viewIdIndex++; } - } else { + } + else { domainView.addIncludedRelationshipName(relationshipOrEntityName); if (vriContext.AS() != null) { domainView.renameRelationship(relationshipOrEntityName, vriContext.id(1).getText()); @@ -1212,17 +1263,22 @@ public MTDView visitView(EntityLanguageParser.ViewContext ctx) { String viewName = vriContext.id(viewIdIndex).getText(); if (relationshipOrEntityName == null) { domainView.setRelationshipWithViewName(viewName); - } else if (entityRef) { + } + else if (entityRef) { domainView.setViewNameForRelationshipEntityName(relationshipOrEntityName, viewName); - } else { + } + else { domainView.setViewNameForRelationshipName(relationshipOrEntityName, viewName); } - } else if (vriContext.PRIMARYKEY() != null) { + } + else if (vriContext.PRIMARYKEY() != null) { if (relationshipOrEntityName == null) { domainView.setRelationshipWithPrimaryKey(true); - } else if (entityRef) { + } + else if (entityRef) { domainView.setPrimaryKeyForRelationshipEntityName(relationshipOrEntityName); - } else { + } + else { domainView.setPrimaryKeyForRelationshipName(relationshipOrEntityName); } } @@ -1235,27 +1291,34 @@ public MTDView visitView(EntityLanguageParser.ViewContext ctx) { for (MTTagSet tagSet : visitViewTaggedList(vreContext.viewTaggedList())) { domainView.addExcludedRelationshipTagSet(tagSet); } - } else if (!hasEntityOrRelationshipId) { + } + else if (!hasEntityOrRelationshipId) { if (vreContext.PARENT() != null) { domainView.setExcludedParentRelationships(true); - } else if (vreContext.TOONE() != null) { + } + else if (vreContext.TOONE() != null) { domainView.setExcludedOneRelationships(true); - } else if (vreContext.TOMANY() != null) { + } + else if (vreContext.TOMANY() != null) { domainView.setExcludedManyRelationships(true); - } else { + } + else { domainView.setExcludedAllRelationships(true); } - } else if (vreContext.TOONE() != null || vreContext.TOMANY() != null - || vreContext.PARENT() != null) { + } + else if (vreContext.TOONE() != null || vreContext.TOMANY() != null + || vreContext.PARENT() != null) { boolean entityRef = vreContext.ENTITY() != null; String relationshipOrEntityName = vreContext.id().getText(); if (entityRef) { domainView.addExcludedRelationshipEntityName(relationshipOrEntityName); - } else { + } + else { domainView.addExcludedRelationshipName(relationshipOrEntityName); } - } else { + } + else { domainView.setExcludedAllRelationships(true); } } @@ -1301,13 +1364,13 @@ public MTRelationship visitRelationshipStatement(EntityLanguageParser.Relationsh if (ctx.MANY() != null) { toPlurality = HalfRelationshipPlurality.MANY; } - String fromEntityName = currentEntity.getName(); - String toEntityName = null; - String relationshipName = null; - MTEntityTemplateInstantiation instantiation = null; + String fromEntityName = currentEntity.getName(); + String toEntityName = null; + String relationshipName = null; + MTEntityTemplateInstantiation instantiation = null; if (ctx.relationshipTemplateAs() != null) { instantiation = new MTEntityTemplateInstantiation(ctx.relationshipTemplateAs(), - ctx.relationshipTemplateAs().id().getText()); + ctx.relationshipTemplateAs().id().getText()); for (EntityLanguageParser.RelationshipTemplateArgContext argContext : ctx.relationshipTemplateAs().relationshipTemplateArg()) { instantiation.addTemplateArgEntityName(argContext.id().getText(), argContext.UNIQUE() != null); } @@ -1315,13 +1378,14 @@ public MTRelationship visitRelationshipStatement(EntityLanguageParser.Relationsh toEntityName = ctx.id(0).getText(); if (ctx.id().size() == 1) { relationshipName = ECStringUtil.Uncapitalize(toEntityName); - } else { + } + else { relationshipName = ctx.id(1).getText(); } - boolean optional = ctx.OPTIONAL() != null; - boolean parent = ctx.PARENT() != null; - String reverseName = null; + boolean optional = ctx.OPTIONAL() != null; + boolean parent = ctx.PARENT() != null; + String reverseName = null; if (ctx.relationshipReverseName() != null && ctx.relationshipReverseName().id() != null) { reverseName = ctx.relationshipReverseName().id().getText(); @@ -1333,8 +1397,8 @@ public MTRelationship visitRelationshipStatement(EntityLanguageParser.Relationsh } MTRelationship relationship = new MTRelationship(ctx, relationshipName, fromEntityName, toPlurality, - toEntityName, optional, parent, reverseName, toEntityIdName, - null); + toEntityName, optional, parent, reverseName, toEntityIdName, + null); if (inheritedTags != null) { relationship.addTagsWithValues(inheritedTags); @@ -1353,21 +1417,21 @@ public MTRelationship visitRelationshipStatement(EntityLanguageParser.Relationsh @Override public MTAttributeConstraint visitAttributeConstraint(EntityLanguageParser.AttributeConstraintContext ctx) { - String constraintName = ctx.id().getText(); - EntityLanguageParser.AttributeConstraintBodyContext block = ctx.attributeConstraintBody(); + String constraintName = ctx.id().getText(); + EntityLanguageParser.AttributeConstraintBodyContext block = ctx.attributeConstraintBody(); if (block == null || block.expression().size() == 0) { ECLog.logFatal("Attribute constraints must have an expression. Constraint " + currentEntity.getName() + "." - + currentAttribute.getName() + "." + constraintName + " does not."); + + currentAttribute.getName() + "." + constraintName + " does not."); } if (ctx.attributeConstraintBody().expression().size() > 1) { ECLog.logFatal( - "Attribute constraints can only have one expression. Constraint " + currentEntity.getName() + "." + "Attribute constraints can only have one expression. Constraint " + currentEntity.getName() + "." + currentAttribute.getName() + "." + constraintName + " is specified with " + ctx.attributeConstraintBody().expression().size() + " expressions: " + ctx.attributeConstraintBody().expression().toString()); } MTAttributeConstraint constraint = new MTAttributeConstraint(ctx, currentAttribute, constraintName, - visitExpression(block.expression(0))); + visitExpression(block.expression(0))); if (block.descriptionStatement() != null) { setNodeDescription(constraint, block.descriptionStatement(), false); @@ -1382,21 +1446,29 @@ public MTAttributeConstraint visitAttributeConstraint(EntityLanguageParser.Attri @Override public MTDomain visitDomain(EntityLanguageParser.DomainContext ctx) { - String name = ctx.ID(0).getText(); - boolean extending = ctx.EXTENDS() != null; - boolean specializing = !extending && (ctx.ID().size() > 1); - String extendingDomainName = extending ? - ctx.ID(1).getText() : - null; - String specializingName = specializing ? - ctx.ID(1).getText() : - null; - + String name = ctx.ID(0).getText(); + boolean extending = ctx.EXTENDS() != null; + boolean specializing = !extending && (ctx.ID().size() > 1); + String extendingDomainName = extending ? + ctx.ID(1).getText() : + null; + String specializingName = specializing ? + ctx.ID(1).getText() : + null; + + if (currentRealm != null) { + ECLog.logInfo("Visiting domain: " + name + " in realm: " + currentRealm.getName()); + if (!specializing) { + ECLog.logFatal("Only specialized domains can be defined in a realm. Domain: " + name + " realm: " + currentRealm.getName()); + } + } if (currentSpace().getDomainWithName(name) != null) { currentDomain = currentSpace().getDomainWithName(name); - } else { + } + else { currentDomain = new MTDomain(ctx, currentSpace(), name, extendingDomainName); } + if (specializingName != null) { currentDomain.addSpecializedAsName(specializingName); } @@ -1446,11 +1518,12 @@ public MTDomain visitDomain(EntityLanguageParser.DomainContext ctx) { int numNamespaces = block.domainNamespace().size(); if (numNamespaces > 1) { ECLog.logError(block, "Only one namespace declaration is allowed."); - } else if (numNamespaces == 1) { + } + else if (numNamespaces == 1) { EntityLanguageParser.DomainNamespaceContext ns = block.domainNamespace(0); currentDomain.setNamespace( - new MTNamespace(ns, segmentsForPathID(ns.namespaceIdent().id()).toArray(new String[0]), - ns.SPACE() != null)); + new MTNamespace(ns, segmentsForPathID(ns.namespaceIdent().id()).toArray(new String[0]), + ns.SPACE() != null)); } if (block.domainFlattenSecondaryEntities() != null @@ -1478,9 +1551,9 @@ private List segmentsForPathID(List node @Override public MTDApplyTemplate visitDomainApplyTemplate(EntityLanguageParser.DomainApplyTemplateContext ctx) { - MTDApplyTemplate applyTemplate = new MTDApplyTemplate(ctx, currentDomain, - ctx.id().getText()); - EntityLanguageParser.DomainApplyTemplateBodyContext body = ctx.domainApplyTemplateBody(); + MTDApplyTemplate applyTemplate = new MTDApplyTemplate(ctx, currentDomain, + ctx.id().getText()); + EntityLanguageParser.DomainApplyTemplateBodyContext body = ctx.domainApplyTemplateBody(); if (body != null) { if (body.descriptionStatement() != null) { setNodeDescription(applyTemplate, body.descriptionStatement(), false); @@ -1488,8 +1561,8 @@ public MTDApplyTemplate visitDomainApplyTemplate(EntityLanguageParser.DomainAppl if (body.tagStatement() != null) { applyTemplate.addTagsWithValues(tagStringsFromTagStatements(body.tagStatement())); } - if (body.templateConfig() != null && body.templateConfig().size() > 0) { - EntityLanguageParser.TemplateConfigContext configContext = body.templateConfig().get(0); + if (body.transformConfig() != null && body.transformConfig().size() > 0) { + EntityLanguageParser.TransformConfigContext configContext = body.transformConfig().get(0); applyTemplate.setConfig(visitJsonObj(configContext.jsonObj())); } } @@ -1500,19 +1573,24 @@ public MTDApplyTemplate visitDomainApplyTemplate(EntityLanguageParser.DomainAppl public JsonObject visitJsonObj(EntityLanguageParser.JsonObjContext ctx) { JsonObjectBuilder builder = Json.createObjectBuilder(); for (EntityLanguageParser.JsonPairContext context : ctx.jsonPair()) { - String name = ECStringUtil.ProcessParserString(context.STRING().getText()); + String name = ECStringUtil.ProcessParserString(context.STRING().getText()); Object value = visitJsonValue(context.jsonValue()); if (value instanceof JsonArray) { builder.add(name, (JsonArray) value); - } else if (value instanceof JsonObject) { + } + else if (value instanceof JsonObject) { builder.add(name, (JsonObject) value); - } else if (value instanceof JsonValue) { + } + else if (value instanceof JsonValue) { builder.add(name, (JsonValue) value); - } else if (value instanceof Long) { + } + else if (value instanceof Long) { builder.add(name, ((Long) value).longValue()); - } else if (value instanceof Double) { + } + else if (value instanceof Double) { builder.add(name, ((Double) value).doubleValue()); - } else if (value instanceof String) { + } + else if (value instanceof String) { builder.add(name, (String) value); } } @@ -1523,19 +1601,26 @@ public JsonObject visitJsonObj(EntityLanguageParser.JsonObjContext ctx) { public Object visitJsonValue(EntityLanguageParser.JsonValueContext ctx) { if (ctx.jsonArr() != null) { return visitJsonArr(ctx.jsonArr()); - } else if (ctx.jsonObj() != null) { + } + else if (ctx.jsonObj() != null) { return visitJsonObj(ctx.jsonObj()); - } else if (ctx.STRING() != null) { + } + else if (ctx.STRING() != null) { return ECStringUtil.ProcessParserString(ctx.STRING().getText()); - } else if (ctx.FLOAT() != null) { + } + else if (ctx.FLOAT() != null) { return Double.valueOf(ctx.FLOAT().getText()); - } else if (ctx.INTEGER() != null) { + } + else if (ctx.INTEGER() != null) { return Long.valueOf(ctx.INTEGER().getText()); - } else if (ctx.getText().equals("true")) { + } + else if (ctx.getText().equals("true")) { return JsonValue.TRUE; - } else if (ctx.getText().equals("false")) { + } + else if (ctx.getText().equals("false")) { return JsonValue.FALSE; - } else if (ctx.getText().equals("null")) { + } + else if (ctx.getText().equals("null")) { return JsonValue.NULL; } ECLog.logFatal(ctx, "Specified Json value is not supported: " + ctx.getText()); @@ -1545,20 +1630,25 @@ public Object visitJsonValue(EntityLanguageParser.JsonValueContext ctx) { @Override public Object visitDomainTagging(EntityLanguageParser.DomainTaggingContext ctx) { for (EntityLanguageParser.DomainTaggingTagContext taggingTagContext : ctx.domainTaggingTag()) { - MTTagDef tagDef = visitDomainTaggingTag(taggingTagContext); - String context = ctx.id().getText(); + MTTagDef tagDef = visitDomainTaggingTag(taggingTagContext); + String context = ctx.id().getText(); MTTagContext tagContext = null; if (context.equals("entity")) { tagContext = MTTagContext.ENTITY; - } else if (context.equals("attribute")) { + } + else if (context.equals("attribute")) { tagContext = MTTagContext.ATTRIBUTE; - } else if (context.equals("relationship")) { + } + else if (context.equals("relationship")) { tagContext = MTTagContext.RELATIONSHIP; - } else if (context.equals("domain")) { + } + else if (context.equals("domain")) { tagContext = MTTagContext.DOMAIN; - } else if (context.equals("enum")) { + } + else if (context.equals("enum")) { tagContext = MTTagContext.ENUM; - } else if (context.equals("enum_item")) { + } + else if (context.equals("enum_item")) { tagContext = MTTagContext.ENUM_ITEM; } tagDef.setTagContext(tagContext); @@ -1580,12 +1670,12 @@ public MTTagDef visitDomainTaggingTag(EntityLanguageParser.DomainTaggingTagConte if (!ctx.domainTaggingTagValue().isEmpty()) { if (ctx.domainTaggingTagValue().size() > 1) { ECLog.logFatal(ctx.domainTaggingTagValue(1), - "A tag definition can only have at most one value definition."); + "A tag definition can only have at most one value definition."); } EntityLanguageParser.DomainTaggingTagValueContext valueContext = ctx.domainTaggingTagValue(0); - MTNativeType.DataType dataType = MTNativeType.DataType.FromName( - valueContext.domainTaggingTagValueType().getText()); - MTTagValueDef tagValueDef = new MTTagValueDef(valueContext, dataType); + MTNativeType.DataType dataType = MTNativeType.DataType.FromName( + valueContext.domainTaggingTagValueType().getText()); + MTTagValueDef tagValueDef = new MTTagValueDef(valueContext, dataType); if (valueContext.descriptionStatement() != null) { setNodeDescription(tagValueDef, valueContext.descriptionStatement(), false); } @@ -1600,11 +1690,11 @@ public MTTagDef visitDomainTaggingTag(EntityLanguageParser.DomainTaggingTagConte @Override public Object visitDomainNaming(EntityLanguageParser.DomainNamingContext ctx) { - MTNamingMethod method = null; - String prefix = null; - String suffix = null; - String primaryKeyName = null; - Boolean withUnits = null; + MTNamingMethod method = null; + String prefix = null; + String suffix = null; + String primaryKeyName = null; + Boolean withUnits = null; for (EntityLanguageParser.DomainNamingMethodContext methodContext : ctx.domainNamingBody().domainNamingMethod()) { method = MTNamingMethod.fromName(methodContext.ID().getSymbol().getText()); @@ -1634,23 +1724,31 @@ public Object visitDomainNaming(EntityLanguageParser.DomainNamingContext ctx) { for (EntityLanguageParser.NamingClassContext namingClassContext : ctx.namingClass()) { if (namingClassContext.SPACE() != null) { classesWithNaming.add(MTSpace.class); - } else if (namingClassContext.MODULE() != null) { + } + else if (namingClassContext.MODULE() != null) { classesWithNaming.add(MTModule.class); - } else if (namingClassContext.ENTITY() != null) { + } + else if (namingClassContext.ENTITY() != null) { classesWithNaming.add(MTCompositeEntity.class); classesWithNaming.add(MTEntity.class); classesWithNaming.add(MTView.class); - } else if (namingClassContext.ATTRIBUTE() != null) { + } + else if (namingClassContext.ATTRIBUTE() != null) { classesWithNaming.add(MTAttribute.class); - } else if (namingClassContext.RELATIONSHIP() != null) { + } + else if (namingClassContext.RELATIONSHIP() != null) { classesWithNaming.add(MTRelationship.class); - } else if (namingClassContext.ENUM() != null) { + } + else if (namingClassContext.ENUM() != null) { classesWithNaming.add(MTEnum.class); - } else if (namingClassContext.ENUMITEM() != null) { + } + else if (namingClassContext.ENUMITEM() != null) { classesWithNaming.add(MTEnumItem.class); - } else if (namingClassContext.TYPEDEF() != null) { + } + else if (namingClassContext.TYPEDEF() != null) { classesWithNaming.add(MTTypedef.class); - } else { + } + else { ECLog.logError("That naming class is not supported: " + namingClassContext.getText()); } } @@ -1693,7 +1791,7 @@ public MTDModule visitDomainModule(EntityLanguageParser.DomainModuleContext ctx) ECLog.logFatal("Domain module can only have one applied template."); } MTDApplyTemplate applyTemplate = visitDomainModuleApplyTemplate( - block.domainModuleApplyTemplate().get(0)); + block.domainModuleApplyTemplate().get(0)); currentDomainModule.setApplyTemplate(applyTemplate); } } @@ -1757,8 +1855,8 @@ public Object visitDomainEntity(EntityLanguageParser.DomainEntityContext ctx) { public Object visitDomainEnum(EntityLanguageParser.DomainEnumContext ctx) { MTNamingMethod method = null; - String prefix = null; - String suffix = null; + String prefix = null; + String suffix = null; String currentDomainEnumName = ctx.ID().getText(); this.currentDomainEnum = new MTDEnum(ctx, this.currentDomain, currentDomainEnumName); @@ -1777,19 +1875,20 @@ public Object visitDomainEnum(EntityLanguageParser.DomainEnumContext ctx) { } if (block.domainEnumItemRenameTo() != null) { - for(EntityLanguageParser.DomainEnumItemRenameToContext renameToContext : block.domainEnumItemRenameTo()) { + for (EntityLanguageParser.DomainEnumItemRenameToContext renameToContext : block.domainEnumItemRenameTo()) { MTDEnumItem domainEnumItem = currentDomainEnum.getDomainEnumItem(renameToContext.id(0).getText(), true); domainEnumItem.setExplicitName(renameToContext.id(1).getText()); } } for (EntityLanguageParser.DomainEnumItemContext itemContext : block.domainEnumItem()) { - String itemName = itemContext.ID().getText(); + String itemName = itemContext.ID().getText(); MTDEnumItem mtdEnumItem = null; if (currentDomainEnum.getEnum() != null) { MTEnumItem enumItem = currentDomainEnum.getEnum().getItemByName(itemName); mtdEnumItem = currentDomainEnum.getDomainEnumItem(enumItem, true); - } else { + } + else { mtdEnumItem = currentDomainEnum.getDomainEnumItem(itemName, true); } @@ -1848,7 +1947,7 @@ public MTDEInterface visitDomainInterfaceStatement(EntityLanguageParser.DomainIn public MTDEInterfaceOperation visitDomainOperation(EntityLanguageParser.DomainOperationContext ctx) { currentDomainEntityInterfaceOperation = new MTDEInterfaceOperation(ctx, currentDomainEntityInterface, - ctx.id(0).getText(), ctx.id(1).getText()); + ctx.id(0).getText(), ctx.id(1).getText()); if (ctx.EXTENDS() != null) { EntityLanguageParser.ExtendingOperationBodyContext body = ctx.extendingOperationBody(); @@ -1858,14 +1957,14 @@ public MTDEInterfaceOperation visitDomainOperation(EntityLanguageParser.DomainOp } if (body.extendingOperationConfig() != null && body.extendingOperationConfig().size() > 0) { currentDomainEntityInterfaceOperation.setExtendingOperationConfig( - visitExtendingOperationConfig(body.extendingOperationConfig(0))); + visitExtendingOperationConfig(body.extendingOperationConfig(0))); } if (body.operationRequest() != null && body.operationRequest().size() > 0) { currentDomainEntityInterfaceOperation.setRequest(visitOperationRequest(body.operationRequest(0))); } if (body.operationResponse() != null && body.operationResponse().size() > 0) { currentDomainEntityInterfaceOperation.setResponse( - visitOperationResponse(body.operationResponse(0))); + visitOperationResponse(body.operationResponse(0))); } visitExtendingOperationBody(body); @@ -1878,12 +1977,12 @@ public MTDEInterfaceOperation visitDomainOperation(EntityLanguageParser.DomainOp @Override public MTDEInterfaceOperationConfig visitExtendingOperationConfig - (EntityLanguageParser.ExtendingOperationConfigContext ctx) { + (EntityLanguageParser.ExtendingOperationConfigContext ctx) { MTDEInterfaceOperationConfig extendingConfig = new MTDEInterfaceOperationConfig(ctx, ctx.id() != null ? - ctx.id().getText() : - null, - currentDomainEntityInterface.getInterfaceName(), - currentDomainEntityInterfaceOperation.getExtendedOperationName()); + ctx.id().getText() : + null, + currentDomainEntityInterface.getInterfaceName(), + currentDomainEntityInterfaceOperation.getExtendedOperationName()); for (EntityLanguageParser.ExtendingOperationAssignmentContext assignmentContext : ctx.extendingOperationConfigBlock().extendingOperationAssignment()) { extendingConfig.addConfigAssignment(assignmentContext.id(0).getText(), assignmentContext.id(1).getText()); } @@ -1915,11 +2014,11 @@ public Object visitDomainAttribute(EntityLanguageParser.DomainAttributeContext c String attributeName = ctx.id().getText(); if (currentDomainEntity != null) { MTDEAttribute domainEntityAttribute = currentDomainEntity.addDomainAttributeWithName( - attributeName); + attributeName); if (inheritedTags != null) { domainEntityAttribute.addTagsWithValues(inheritedTags); } - EntityLanguageParser.DomainAttributeBodyContext bodyContext = ctx.domainAttributeBody(); + EntityLanguageParser.DomainAttributeBodyContext bodyContext = ctx.domainAttributeBody(); if (bodyContext != null) { if (bodyContext.descriptionStatement() != null) { setNodeDescription(domainEntityAttribute, bodyContext.descriptionStatement(), false); @@ -1950,11 +2049,11 @@ public Object visitDomainRelationship(EntityLanguageParser.DomainRelationshipCon String relationshipName = ctx.id().getText(); if (currentDomainEntity != null) { MTDERelationship domainEntityRelationship = currentDomainEntity.addDomainRelationshipWithName( - relationshipName); + relationshipName); if (inheritedTags != null) { domainEntityRelationship.addTagsWithValues(inheritedTags); } - EntityLanguageParser.DomainRelationshipBodyContext bodyContext = ctx.domainRelationshipBody(); + EntityLanguageParser.DomainRelationshipBodyContext bodyContext = ctx.domainRelationshipBody(); if (bodyContext != null) { if (bodyContext.descriptionStatement() != null) { setNodeDescription(domainEntityRelationship, bodyContext.descriptionStatement(), false); @@ -1985,13 +2084,14 @@ public Object visitDomainRelationshipAttribute(EntityLanguageParser.DomainRelati @Override public Object visitDomainAttributesRenameTo(EntityLanguageParser.DomainAttributesRenameToContext ctx) { - String attributeName = ctx.id(0).getText(); + String attributeName = ctx.id(0).getText(); String renamedAttributeName = ctx.id(1).getText(); if (currentDomainEntity == null) { currentDomain.setExplicitAttributeName(attributeName, renamedAttributeName); - } else { + } + else { currentDomainEntity.getDomainAttributeByName(attributeName, true).setExplicitAttributeName( - renamedAttributeName); + renamedAttributeName); } return null; } @@ -2007,8 +2107,8 @@ public Object visitDomainAttributeExclude(EntityLanguageParser.DomainAttributeEx @Override public Object visitDomainAttributeAdd(EntityLanguageParser.DomainAttributeAddContext ctx) { - String attributeName = ctx.attribute().id(0).getText(); - MTAttribute attribute = visitAttribute(ctx.attribute()); + String attributeName = ctx.attribute().id(0).getText(); + MTAttribute attribute = visitAttribute(ctx.attribute()); ECLog.logInfo(ctx, "Adding domain entity attribute: " + attribute.getName()); if (currentDomainEntity != null) { currentDomainEntity.addAttribute(attribute); @@ -2042,7 +2142,8 @@ public MTAttribute visitAttribute(EntityLanguageParser.AttributeContext ctx) { if (ctx.type() != null) { if (ctx.type().BYTE_TYPE() != null) { typeName = ctx.type().BYTE_TYPE().getText(); - } else { + } + else { typeName = ctx.type().getText(); } } @@ -2060,24 +2161,25 @@ public MTAttribute visitAttribute(EntityLanguageParser.AttributeContext ctx) { unitName = ctx.id(1).getText(); } - MTEntity entity = currentDomainEntity != null ? - currentDomainEntity.getEntity() : - currentEntity; + MTEntity entity = currentDomainEntity != null ? + currentDomainEntity.getEntity() : + currentEntity; MTAttribute attribute = new MTAttribute(ctx, entity, typeName, attributeName, unitName, arraySize); this.currentAttribute = attribute; - int indexOfDefaultValueId = unitName == null ? - 1 : - 2; - MTConstant defaultValue = null; + int indexOfDefaultValueId = unitName == null ? + 1 : + 2; + MTConstant defaultValue = null; if (ctx.constant() != null) { defaultValue = visitConstant(ctx.constant()); - } else if (ctx.id().size() > indexOfDefaultValueId) { + } + else if (ctx.id().size() > indexOfDefaultValueId) { EntityLanguageParser.IdContext enumItemContext = ctx.id(indexOfDefaultValueId); - String enumItemName = enumItemContext.getText(); + String enumItemName = enumItemContext.getText(); if (attribute.getTypeName() == null) { ECLog.logFatal(enumItemContext, - "The default value can only be an enum item if the attribute type is an enum."); + "The default value can only be an enum item if the attribute type is an enum."); } defaultValue = new MTConstant(enumItemContext, attribute.getTypeName(), enumItemName); } @@ -2129,7 +2231,7 @@ public MTAttribute visitAttribute(EntityLanguageParser.AttributeContext ctx) { } if (bodyContext.contentType() != null && bodyContext.contentType().size() > 0) { attribute.setContentType( - ECStringUtil.ProcessParserString(bodyContext.contentType(0).STRING().getSymbol().getText())); + ECStringUtil.ProcessParserString(bodyContext.contentType(0).STRING().getSymbol().getText())); } if (bodyContext.bitfield() != null && bodyContext.bitfield().size() > 0) { for (EntityLanguageParser.BitfieldContext bitfieldContext : bodyContext.bitfield()) { @@ -2148,7 +2250,7 @@ public MTAttribute visitAttribute(EntityLanguageParser.AttributeContext ctx) { @Override public Object visitDomainAttributesRenameAppendPrepend - (EntityLanguageParser.DomainAttributesRenameAppendPrependContext ctx) { + (EntityLanguageParser.DomainAttributesRenameAppendPrependContext ctx) { return null; } @@ -2156,8 +2258,8 @@ public MTAttribute visitAttribute(EntityLanguageParser.AttributeContext ctx) { public Object visitDomainAttributeReplaces(EntityLanguageParser.DomainAttributeReplacesContext ctx) { String replacingAttributeName = ctx.id(0).getText(); - String typeName = ctx.type().getText(); - MTUnit unit = null; + String typeName = ctx.type().getText(); + MTUnit unit = null; if (ctx.id().size() > 1) { String unitName = ctx.id(1).getText(); @@ -2169,7 +2271,7 @@ public Object visitDomainAttributeReplaces(EntityLanguageParser.DomainAttributeR MTNativeType.DataType dataType = MTNativeType.DataType.FromName(typeName); MTAttribute attribute = new MTAttribute(ctx, currentDomainEntity.getEntityName(), typeName, - replacingAttributeName); + replacingAttributeName); if (unit != null) { attribute.setUnit(unit); } @@ -2180,7 +2282,8 @@ public Object visitDomainAttributeReplaces(EntityLanguageParser.DomainAttributeR if (dataType != null) { if (dataType == MTNativeType.DataType.INT32) { numberOfBits = 32; - } else if (dataType == MTNativeType.DataType.INT64) { + } + else if (dataType == MTNativeType.DataType.INT64) { numberOfBits = 64; } } @@ -2190,11 +2293,11 @@ public Object visitDomainAttributeReplaces(EntityLanguageParser.DomainAttributeR } for (EntityLanguageParser.BitfieldContext bitfieldContext : ctx.replacesBody().bitfield()) { - MTBitField bitField = visitBitfield(bitfieldContext); + MTBitField bitField = visitBitfield(bitfieldContext); MTDEAttributeBitField domainAttributeBitField = new MTDEAttributeBitField(bitfieldContext, domainAttribute, - bitField.getHigh(), - bitField.getLow(), - bitField.getName()); + bitField.getHigh(), + bitField.getLow(), + bitField.getName()); domainAttribute.addReplacedBitField(domainAttributeBitField); } // TODO: check for overlapping bit fields - display error if so @@ -2207,12 +2310,13 @@ public MTBitField visitBitfield(EntityLanguageParser.BitfieldContext ctx) { String name = null; if (ctx.UNUSED() != null) { name = ctx.UNUSED().getText(); - } else { + } + else { name = ctx.id().getText(); } EntityLanguageParser.BitCountContext bitCountContext = ctx.bitCount(); MTBitField bitField = new MTBitField(ctx, Integer.valueOf(bitCountContext.INTEGER().getText()), - name); + name); if (ctx.UNUSED() != null) { bitField.setUnused(true); } @@ -2229,15 +2333,20 @@ public JsonArray visitJsonArr(EntityLanguageParser.JsonArrContext ctx) { Object value = visitJsonValue(context); if (value instanceof JsonArray) { builder.add((JsonArray) value); - } else if (value instanceof JsonObject) { + } + else if (value instanceof JsonObject) { builder.add((JsonObject) value); - } else if (value instanceof JsonValue) { + } + else if (value instanceof JsonValue) { builder.add((JsonValue) value); - } else if (value instanceof Long) { + } + else if (value instanceof Long) { builder.add(((Long) value).longValue()); - } else if (value instanceof Double) { + } + else if (value instanceof Double) { builder.add(((Double) value).doubleValue()); - } else if (value instanceof String) { + } + else if (value instanceof String) { builder.add((String) value); } } @@ -2246,16 +2355,16 @@ public JsonArray visitJsonArr(EntityLanguageParser.JsonArrContext ctx) { @Override public MTDApplyTemplate visitDomainEntityApplyTemplate(EntityLanguageParser.DomainEntityApplyTemplateContext - ctx) { - MTDApplyTemplate applyTemplate = new MTDApplyTemplate(ctx, - currentDomainEntity, - ctx.id().getText()); - EntityLanguageParser.DomainApplyTemplateBodyContext body = ctx.domainApplyTemplateBody(); + ctx) { + MTDApplyTemplate applyTemplate = new MTDApplyTemplate(ctx, + currentDomainEntity, + ctx.id().getText()); + EntityLanguageParser.DomainApplyTemplateBodyContext body = ctx.domainApplyTemplateBody(); if (ctx.domainApplyTemplateBody().descriptionStatement() != null) { setNodeDescription(applyTemplate, ctx.domainApplyTemplateBody().descriptionStatement(), false); } - if (body.templateConfig() != null && body.templateConfig().size() > 0) { - EntityLanguageParser.TemplateConfigContext configContext = body.templateConfig().get(0); + if (body.transformConfig() != null && body.transformConfig().size() > 0) { + EntityLanguageParser.TransformConfigContext configContext = body.transformConfig().get(0); applyTemplate.setConfig(visitJsonObj(configContext.jsonObj())); } return applyTemplate; @@ -2263,16 +2372,16 @@ public MTDApplyTemplate visitDomainEntityApplyTemplate(EntityLanguageParser.Doma @Override public MTDApplyTemplate visitDomainModuleApplyTemplate(EntityLanguageParser.DomainModuleApplyTemplateContext - ctx) { - MTDApplyTemplate applyTemplate = new MTDApplyTemplate(ctx, - currentDomainModule, - ctx.id().getText()); - EntityLanguageParser.DomainApplyTemplateBodyContext body = ctx.domainApplyTemplateBody(); + ctx) { + MTDApplyTemplate applyTemplate = new MTDApplyTemplate(ctx, + currentDomainModule, + ctx.id().getText()); + EntityLanguageParser.DomainApplyTemplateBodyContext body = ctx.domainApplyTemplateBody(); if (ctx.domainApplyTemplateBody().descriptionStatement() != null) { setNodeDescription(applyTemplate, ctx.domainApplyTemplateBody().descriptionStatement(), false); } - if (body.templateConfig() != null && body.templateConfig().size() > 0) { - EntityLanguageParser.TemplateConfigContext configContext = body.templateConfig().get(0); + if (body.transformConfig() != null && body.transformConfig().size() > 0) { + EntityLanguageParser.TransformConfigContext configContext = body.transformConfig().get(0); applyTemplate.setConfig(visitJsonObj(configContext.jsonObj())); } return applyTemplate; @@ -2280,7 +2389,7 @@ public MTDApplyTemplate visitDomainModuleApplyTemplate(EntityLanguageParser.Doma @Override public MTDirectory visitDirectory(EntityLanguageParser.DirectoryContext ctx) { - MTDirectory output = new MTDirectory(ctx, ctx.id().getText()); + MTDirectory output = new MTDirectory(ctx, ctx.id().getText()); EntityLanguageParser.OutputBodyContext body = ctx.outputBody(); if (body.descriptionStatement() != null) { setNodeDescription(output, body.descriptionStatement(), false); @@ -2297,11 +2406,12 @@ public MTDirectory visitDirectory(EntityLanguageParser.DirectoryContext ctx) { private String idText(EntityLanguageParser.IdContext idNode) { if (idNode.macro() != null) { - String macroName = idNode.macro().ident(0).getText(); + String macroName = idNode.macro().ident(0).getText(); String defaultValue = null; if (idNode.macro().ident().size() > 1) { defaultValue = idNode.macro().ident(1).getText(); - } else if (idNode.macro().STRING() != null) { + } + else if (idNode.macro().STRING() != null) { defaultValue = ECStringUtil.ProcessParserString(idNode.macro().STRING().getText()); } String value = EntityCompiler.GetDefineValue(macroName, defaultValue); @@ -2339,7 +2449,7 @@ public Object visitTemplates(EntityLanguageParser.TemplatesContext ctx) { @Override public MTRepositoryImport visitTemplatesImport(EntityLanguageParser.TemplatesImportContext ctx) { - String repositoryName = ctx.id().getText(); + String repositoryName = ctx.id().getText(); MTRepositoryImport repositoryImport = new MTRepositoryImport(ctx, false); repositoryImport.setRepositoryName(repositoryName); return repositoryImport; @@ -2362,18 +2472,20 @@ public MTTemplate visitTemplate(EntityLanguageParser.TemplateContext ctx) { for (EntityLanguageParser.OutputSpecContext specContext : body.outputSpec()) { if (specContext.id().size() == 2) { template.addNamedOutput(specContext.id(0).getText(), specContext.id(1).getText()); - } else if (specContext.id().size() == 1) { + } + else if (specContext.id().size() == 1) { template.addNamedOutput(specContext.PRIMARY().getText(), specContext.id(0).getText()); - } else { + } + else { ECLog.logFatal(ctx, "Template output spec requires 2 arguments."); } } if (body.descriptionStatement() != null) { setNodeDescription(template, body.descriptionStatement(), false); } - if (body.templateConfig() != null) { - if (body.templateConfig() != null && body.templateConfig().size() > 0) { - EntityLanguageParser.TemplateConfigContext configContext = body.templateConfig().get(0); + if (body.transformConfig() != null) { + if (body.transformConfig() != null && body.transformConfig().size() > 0) { + EntityLanguageParser.TransformConfigContext configContext = body.transformConfig().get(0); template.setConfig(visitJsonObj(configContext.jsonObj())); } } @@ -2385,15 +2497,27 @@ public MTTemplate visitTemplate(EntityLanguageParser.TemplateContext ctx) { @Override public MTTransform visitTransform(EntityLanguageParser.TransformContext ctx) { MTTransform transform = new MTTransform(ctx, currentConfiguration, ctx.id().getText()); + EntityLanguageParser.TransformBodyContext body = ctx.transformBody(); + if (body == null) { + ECLog.logFatal(ctx, "Invalid transform definition."); + } for (EntityLanguageParser.OutputSpecContext specContext : ctx.transformBody().outputSpec()) { if (specContext.id().size() == 2) { transform.addNamedOutput(specContext.id(0).getText(), specContext.id(1).getText()); - } else if (specContext.id().size() == 1) { + } + else if (specContext.id().size() == 1) { transform.addNamedOutput(specContext.PRIMARY().getText(), specContext.id(0).getText()); - } else { + } + else { ECLog.logFatal(ctx, "Transform output spec requires 2 arguments."); } } + if (body.transformConfig() != null) { + if (body.transformConfig() != null && body.transformConfig().size() > 0) { + EntityLanguageParser.TransformConfigContext configContext = body.transformConfig().get(0); + transform.setConfig(visitJsonObj(configContext.jsonObj())); + } + } currentConfiguration.addTransform(transform); return transform; } @@ -2418,7 +2542,8 @@ public Object visitLanguageType(EntityLanguageParser.LanguageTypeContext ctx) { String mappedToTypeName = null; if (ctx.STRING() != null) { mappedToTypeName = ECStringUtil.ProcessParserString(ctx.STRING().getText()); - } else { + } + else { mappedToTypeName = ctx.id().getText(); } currentLanguage.addType(ctx.type().getText(), mappedToTypeName, ctx.REF() != null, ctx.NULLABLE() != null); @@ -2431,9 +2556,11 @@ public Object visitLanguageComments(EntityLanguageParser.LanguageCommentsContext String commentText = ECStringUtil.ProcessParserString(body.STRING().getText()); if (body.LINE() != null) { currentLanguage.setLineComment(commentText); - } else if (body.BLOCK_START() != null) { + } + else if (body.BLOCK_START() != null) { currentLanguage.setBlockCommentStart(commentText); - } else if (body.BLOCK_END() != null) { + } + else if (body.BLOCK_END() != null) { currentLanguage.setBlockCommentEnd(commentText); } } @@ -2443,8 +2570,8 @@ public Object visitLanguageComments(EntityLanguageParser.LanguageCommentsContext @Override public Object visitLanguageOperators(EntityLanguageParser.LanguageOperatorsContext ctx) { for (EntityLanguageParser.OperatorsBodyContext body : ctx.operatorsBody()) { - String operatorName = body.id().getText(); - List symbols = new ArrayList<>(); + String operatorName = body.id().getText(); + List symbols = new ArrayList<>(); for (TerminalNode symbolString : body.STRING()) { symbols.add(ECStringUtil.ProcessParserString(symbolString.getText())); } @@ -2456,15 +2583,15 @@ public Object visitLanguageOperators(EntityLanguageParser.LanguageOperatorsConte @Override public Object visitLanguageFunctions(EntityLanguageParser.LanguageFunctionsContext ctx) { for (EntityLanguageParser.FunctionsBodyContext body : ctx.functionsBody()) { - String name = body.id(0).getText(); - String mapping = ECStringUtil.ProcessParserString(body.STRING().getText()); + String name = body.id(0).getText(); + String mapping = ECStringUtil.ProcessParserString(body.STRING().getText()); MTLanguageFunction function = new MTLanguageFunction(body, currentLanguage, name, mapping); for (int i = 0; i < body.type().size(); i++) { - String typeStr = body.type(i).getText(); - String argName = body.id(i + 1).getText(); - MTNativeType.DataType argType = MTNativeType.DataType.FromName(typeStr); - MTLanguageFunctionArgument arg = new MTLanguageFunctionArgument(body.id(i + 1), function, argType, - argName); + String typeStr = body.type(i).getText(); + String argName = body.id(i + 1).getText(); + MTNativeType.DataType argType = MTNativeType.DataType.FromName(typeStr); + MTLanguageFunctionArgument arg = new MTLanguageFunctionArgument(body.id(i + 1), function, argType, + argName); function.addArg(arg); } currentLanguage.addFunction(function); @@ -2476,7 +2603,7 @@ public Object visitLanguageFunctions(EntityLanguageParser.LanguageFunctionsConte public Object visitVersion(EntityLanguageParser.VersionContext ctx) { Integer[] parts = new Integer[]{0, 0, 0}; - int partIndex = 0; + int partIndex = 0; String versionString = ctx.VERSIONNUM().getText(); for (String partStr : versionString.split(".")) { parts[partIndex++] = Integer.valueOf(partStr); @@ -2490,10 +2617,27 @@ public Object visitVersion(EntityLanguageParser.VersionContext ctx) { @Override public Object visitFormatStatement(EntityLanguageParser.FormatStatementContext ctx) { - String formatName = ctx.id().getText(); - JsonObject settings = visitJsonObj(ctx.jsonObj()); + String formatName = ctx.id().getText(); + JsonObject settings = visitJsonObj(ctx.jsonObj()); MTCodeFormat codeFormat = new MTCodeFormat(ctx, formatName, settings); root.addCodeFormat(codeFormat); return super.visitFormatStatement(ctx); } + + @Override + public Object visitRealm(EntityLanguageParser.RealmContext ctx) { + EntityLanguageParser.RealmBodyContext bodyContext = ctx.realmBody(); + String realmName = ctx.id().getText(); + MTRealm realm = null; + if (currentSpace().hasRealmWithName(realmName)) { + realm = currentSpace().getRealmWithName(realmName); + } else { + realm = new MTRealm(realmName); + } + this.currentRealm = realm; + visit(bodyContext); + this.currentRealm = null; + + return realm; + } } diff --git a/src/main/java/org/entityc/compiler/model/MTRealm.java b/src/main/java/org/entityc/compiler/model/MTRealm.java new file mode 100644 index 0000000..66cdf61 --- /dev/null +++ b/src/main/java/org/entityc/compiler/model/MTRealm.java @@ -0,0 +1,24 @@ +package org.entityc.compiler.model; + +import org.entityc.compiler.model.domain.MTNamed; +import org.entityc.compiler.model.entity.MTTemplateSupport; +import org.entityc.compiler.model.visitor.MTVisitor; + +public class MTRealm extends MTNode implements MTTemplateSupport, MTNamed { + + private final String name; + + public MTRealm(String name) { + this.name = name; + } + + @Override + public void accept(MTVisitor visitor) { + + } + + @Override + public String getName() { + return this.name; + } +} diff --git a/src/main/java/org/entityc/compiler/model/config/MTSpace.java b/src/main/java/org/entityc/compiler/model/config/MTSpace.java index c6a35ab..31c3dd5 100644 --- a/src/main/java/org/entityc/compiler/model/config/MTSpace.java +++ b/src/main/java/org/entityc/compiler/model/config/MTSpace.java @@ -13,10 +13,7 @@ import org.entityc.compiler.doc.annotation.ModelMethod; import org.entityc.compiler.doc.annotation.ModelMethodCategory; import org.entityc.compiler.doc.annotation.ModelMethodParameter; -import org.entityc.compiler.model.MTModule; -import org.entityc.compiler.model.MTNamespace; -import org.entityc.compiler.model.MTNode; -import org.entityc.compiler.model.MTReferenceResolution; +import org.entityc.compiler.model.*; import org.entityc.compiler.model.domain.MTDomain; import org.entityc.compiler.model.domain.MTNamed; import org.entityc.compiler.model.entity.MTEntity; @@ -46,6 +43,7 @@ + "list of modules or entities in your model.") public class MTSpace extends MTNode implements MTReferenceResolution, MTTemplateSupport, MTNamed { + private final Map realmMap = new HashMap<>(); private final Map moduleMap = new HashMap<>(); private final Map entityMap = new HashMap<>(); private final Map entityTemplateMap = new HashMap<>(); @@ -132,6 +130,20 @@ public MTRepository getRepository( return repositoryMap.get(name); } + public void addRealm(MTRealm realm) { + realmMap.put(realm.getName(), realm); + } + + @ModelMethod(category = ModelMethodCategory.CONFIGURATION, description = "Returns the realm object by its name.") + public MTRealm getRealmWithName(String realm) { + return realmMap.get(realm); + } + + @ModelMethod(category = ModelMethodCategory.CONFIGURATION, description = "Returns true if there is a realm by this name.") + public boolean hasRealmWithName(String realm) { + return realmMap.containsKey(realm); + } + public void addModule(MTModule module) { module.setIncluded(includeMode); moduleMap.put(module.getName(), module); diff --git a/src/main/java/org/entityc/compiler/model/domain/MTDomain.java b/src/main/java/org/entityc/compiler/model/domain/MTDomain.java index 45b4e55..1ee3f32 100644 --- a/src/main/java/org/entityc/compiler/model/domain/MTDomain.java +++ b/src/main/java/org/entityc/compiler/model/domain/MTDomain.java @@ -365,7 +365,7 @@ public void accept(MTVisitor visitor) { public void checkValidReferences(MTSpace space) { for (MTDEntity domainEntity : domainEntities) { if (domainEntity.getEntity() == null) { - ECLog.logFatal(domainEntity, "Could not find entity: " + domainEntity.getEntityName()); + //ECLog.logFatal(domainEntity, "Could not find entity: " + domainEntity.getEntityName()); } } } diff --git a/src/main/java/org/entityc/compiler/model/entity/MTCompositeEntity.java b/src/main/java/org/entityc/compiler/model/entity/MTCompositeEntity.java index ace4b1f..41a441f 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTCompositeEntity.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTCompositeEntity.java @@ -12,6 +12,7 @@ public class MTCompositeEntity extends MTEntity { public static final String ObjectTag = "object"; public static final String VersionTag = "version"; public static final String ReleaseTag = "release"; + public static final String BinderTag = "binder"; Map constituentEntities = new HashMap<>(); @@ -19,7 +20,7 @@ public MTCompositeEntity(ParserRuleContext ctx, MTModule module, String name) { super(ctx, module, name); } - private void addConstituentEntity(String tag, MTEntity entity) { + public void addConstituentEntity(String tag, MTEntity entity) { if (this.constituentEntities.containsKey(tag) ) { if (!this.constituentEntities.get(tag).name.equals(entity.name)) { ECLog.logFatal("This composite entity " + this.name + " is already associated to a different entity with the " + tag + " tag."); @@ -34,6 +35,38 @@ public MTEntity getConstituentEntity(String tag) { return constituentEntities.get(tag); } + public boolean hasConstituentEntity(String tag) { + return constituentEntities.containsKey(tag); + } + + public MTEntity getAnyConstituentEntity(String tag) { + MTEntity constituentEntity = constituentEntities.get(tag); + if (constituentEntity != null) { + return constituentEntity; + } + ECLog.logInfo("getAnyConstituentEntity(" + tag + ") Checking relationships for " + getName() + "..."); + for (MTRelationship relationship : getRelationships()) { + MTEntity toEntity = relationship.getTo().getEntity(); + if (toEntity.hasTag("release:top") && tag.equals(ReleaseTag)) { + return toEntity; + } + if (toEntity == null || !toEntity.isCompositeEntity()) { + ECLog.logInfo(" Relationship " + relationship.getName() + " to entity " + toEntity.getName() + " is not to a composite entity."); + continue; + } + MTEntity compositeToEntity = ((MTCompositeEntity)toEntity).getAnyConstituentEntity(tag); + if (compositeToEntity != null) { + return compositeToEntity; + } + } + ECLog.logInfo(" Unable to find child constituent entity!"); + return null; + } + + public boolean hasAnyConstituentEntity(String tag) { + return getAnyConstituentEntity(tag) != null; + } + public void addAttribute(String tag, MTAttribute attribute, MTEntity fromEntity) { addConstituentEntity(tag, fromEntity); MTAttribute constituentAttribute = MTAttribute.Copy(attribute, this); diff --git a/src/main/java/org/entityc/compiler/model/entity/MTEntity.java b/src/main/java/org/entityc/compiler/model/entity/MTEntity.java index 12cdba7..3502b80 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTEntity.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTEntity.java @@ -87,7 +87,7 @@ public String getName() { @ModelMethod(category = ModelMethodCategory.ENTITY, description = "Adds the entity to a realm.") public void addRealm(String realm) { - ECLog.logInfo("Added entity: " + getName() + " to realm " + realm); + //ECLog.logInfo("Added entity: " + getName() + " to realm " + realm); realms.add(realm); } @@ -97,6 +97,12 @@ public boolean isInRealm(String realm) { return this.realms.contains(realm); } + @ModelMethod(category = ModelMethodCategory.ENTITY, + description = "Returns true if this entity is a composite entity.") + public boolean isCompositeEntity() { + return this instanceof MTCompositeEntity; + } + public static MTEntity AddImplicitManyToManyEntity(MTSpace space, MTEntity fromEntity, MTEntity toEntity) { MTEntity combinedEntity = CombineEntities(fromEntity, toEntity); MTEntity alreadyCreatedEntity = space.getEntityWithName(combinedEntity.getName()); diff --git a/src/main/java/org/entityc/compiler/model/entity/MTRelationship.java b/src/main/java/org/entityc/compiler/model/entity/MTRelationship.java index 2518e61..fadea51 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTRelationship.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTRelationship.java @@ -79,6 +79,10 @@ protected MTRelationship(String secondaryName, MTRelationship primaryRelationshi this.templateArgName = primaryRelationship.templateArgName; } + @Override + public String toString() { + return getFrom().getEntityName() + "." + getName() + " -(" + to.getPlurality().toString() + ")-> " + getTo().getEntityName(); + } public static MTRelationship Copy(MTRelationship relationship, MTEntity newFromEntity, MTEntity newToEntity) { MTRelationshipHalf fromHalf = new MTRelationshipHalf(relationship.getParserRuleContext(), @@ -326,7 +330,7 @@ public boolean resolveReferences(MTSpace space, int pass) { } else { // good unnamed pairing - System.out.println("unnamed Relationship \"" + getName() + "\" pairing between " + from.getEntityName() + "." + this.getName() + " and " + to.getEntityName() + "." + fromRelationship.getName()); + //System.out.println("unnamed Relationship \"" + getName() + "\" pairing between " + from.getEntityName() + "." + this.getName() + " and " + to.getEntityName() + "." + fromRelationship.getName()); this.reverseRelationship = fromRelationship; this.from.setPlurality(fromRelationship.to.getPlurality()); found = true; diff --git a/src/main/java/org/entityc/compiler/transform/MTVImplicitTransform.java b/src/main/java/org/entityc/compiler/transform/MTVImplicitTransform.java index 2e05ec8..b44157e 100644 --- a/src/main/java/org/entityc/compiler/transform/MTVImplicitTransform.java +++ b/src/main/java/org/entityc/compiler/transform/MTVImplicitTransform.java @@ -77,14 +77,14 @@ public void visitRelationship(MTRelationship relationship) { // if this is a realm based transform then make sure we are operating on entities from that realm. if (realm != null) { if (!(fromEntity instanceof MTCompositeEntity) && (toEntity instanceof MTCompositeEntity)) { - ECLog.logInfo("(wrong class) REALM " + realm + ": not processing fromEntity: " + fromEntity.getName() + " toEntity: " + toEntity.getName()); + //ECLog.logInfo("(wrong class) REALM " + realm + ": not processing fromEntity: " + fromEntity.getName() + " toEntity: " + toEntity.getName()); return; } if (!fromEntity.isInRealm(realm) || !toEntity.isInRealm(realm)) { - ECLog.logInfo("(wrong realm) REALM " + realm + ": not processing fromEntity: " + fromEntity.getName() + " toEntity: " + toEntity.getName()); + //ECLog.logInfo("(wrong realm) REALM " + realm + ": not processing fromEntity: " + fromEntity.getName() + " toEntity: " + toEntity.getName()); return; } - ECLog.logInfo("REALM " + realm + ": PROCESSING fromEntity: " + fromEntity.getName() + " toEntity: " + toEntity.getName()); + //ECLog.logInfo("REALM " + realm + ": PROCESSING fromEntity: " + fromEntity.getName() + " toEntity: " + toEntity.getName()); } MTPrimaryKey toPrimaryKey = toEntity.getPrimaryKey(); diff --git a/src/main/java/org/entityc/compiler/transform/MTVReleasedTransform.java b/src/main/java/org/entityc/compiler/transform/MTVReleasedTransform.java index 1328e21..53720ca 100644 --- a/src/main/java/org/entityc/compiler/transform/MTVReleasedTransform.java +++ b/src/main/java/org/entityc/compiler/transform/MTVReleasedTransform.java @@ -32,7 +32,7 @@ public class MTVReleasedTransform extends MTBaseTransform { private String compositEntityNamePrefix = ""; private SSSourceFile sourceFile; - public static final String realm = "released"; + public static final String realm = "Released"; public MTVReleasedTransform(MTRoot root, String configurationName) { super("Released", root, configurationName); @@ -54,7 +54,10 @@ public void start(String ignore) { MTSpace space = this.root.getSpace(); - Map compositeEntityMap = new HashMap<>(); + Map nonCompositeEntityMap = new HashMap<>(); + Map compositeEntityConstituentMap = new HashMap<>(); + Map releasedRelatedEntityMap = new HashMap<>(); + Map releasedVarientOfEntityMap = new HashMap<>(); for (MTModule module : space.getModules()) { //ECLog.logInfo("--------------------------------------------------------- MODULE: " + module.getName()); @@ -74,7 +77,8 @@ public void start(String ignore) { } List compositeEntityList = new ArrayList<>(); for (MTEntity entity : module.getEntities()) { - if (!entity.hasTag("release:binder") || entity.isIncluded() || entity.isExtern() || entity.isImplicit()) { + if (entity.isIncluded() || entity.isExtern() || entity.isImplicit() || entity.isTransient() + || !entity.hasTag("release:binder")) { continue; } @@ -108,17 +112,29 @@ else if (toEntity.hasTag("release:version")) { MTEntity objectEntity = objectRelationship.getTo().getEntity(); MTEntity versionEntity = versionRelationship.getTo().getEntity(); + // keep track of ones related to the Released entities + releasedRelatedEntityMap.put(entity.getName(), entity); // binder + releasedRelatedEntityMap.put(releaseEntity.getName(), releaseEntity); + releasedRelatedEntityMap.put(objectEntity.getName(), objectEntity); + releasedRelatedEntityMap.put(versionEntity.getName(), versionEntity); + // Now create a new entity that unifies these three - MTCompositeEntity compositeEntity = new MTCompositeEntity(objectEntity.getParserRuleContext(), objectEntity.getModule(), compositEntityNamePrefix + objectEntity.getName()); + MTCompositeEntity compositeEntity = new MTCompositeEntity(objectEntity.getParserRuleContext(), + objectEntity.getModule(), + compositEntityNamePrefix + objectEntity.getName()); compositeEntity.addRealm(realm); + releasedRelatedEntityMap.put(compositeEntity.getName(), compositeEntity); + releasedVarientOfEntityMap.put(objectEntity.getName(), compositeEntity); + + compositeEntity.addConstituentEntity(MTCompositeEntity.BinderTag, entity); // // Object Entity Primary Key // MTAttribute primaryKeyAttribute = new MTAttribute(objectEntity.getParserRuleContext(), compositeEntity, objectEntity.getPrimaryKeyAttribute().getTypeName(), - ECStringUtil.Uncapitalize(compositEntityNamePrefix) + ECStringUtil.Capitalize(objectEntity.getPrimaryKeyAttribute().getName())); + objectEntity.getPrimaryKeyAttribute().getName()); MTPrimaryKey newPrimaryKey = new MTPrimaryKey(objectEntity.getPrimaryKey().getParserRuleContext()); newPrimaryKey.addAttribute(primaryKeyAttribute); compositeEntity.setPrimaryKey(newPrimaryKey); @@ -126,10 +142,15 @@ else if (toEntity.hasTag("release:version")) { // // Foreign from Release // - MTAttribute releaseEntityForeignKey = MTAttribute.Copy(releaseEntity.getPrimaryKeyAttribute(), compositeEntity); - releaseEntityForeignKey.setPrimaryKey(false); - compositeEntity.addAttribute(MTCompositeEntity.ReleaseTag, releaseEntityForeignKey, releaseEntity); - + MTRelationship releaseFKRelationship = new MTRelationship( + topRelationship.getParserRuleContext(), + ECStringUtil.Uncapitalize(releaseEntity.getName()), + compositeEntity.getName(), + HalfRelationshipPlurality.ONE, + releaseEntity.getName(), true, true, null, null, null); + releaseFKRelationship.addTag("ignore"); + compositeEntity.addRelationship(releaseFKRelationship); + compositeEntity.addConstituentEntity(MTCompositeEntity.ReleaseTag, releaseEntity); // // Object Entity Attributes // @@ -154,8 +175,17 @@ else if (toEntity.hasTag("release:version")) { } compositeEntityList.add(compositeEntity); - compositeEntityMap.put(objectEntity.getName(), compositeEntity); - compositeEntityMap.put(versionEntity.getName(), compositeEntity); + compositeEntityConstituentMap.put(objectEntity.getName(), compositeEntity); + compositeEntityConstituentMap.put(versionEntity.getName(), compositeEntity); + + // create a one to many relationship on the release entity to this composite entity + MTRelationship releaseRelationship = new MTRelationship( + topRelationship.getParserRuleContext(), + ECStringUtil.Uncapitalize(compositEntityNamePrefix) + ECStringUtil.Capitalize(ECStringUtil.Pluralize(objectRelationship.getName())), + releaseEntity.getName(), + HalfRelationshipPlurality.MANY, + compositeEntity.getName(), true, false, null, null, null); + releaseEntity.addRelationship(releaseRelationship); // Relationships are more complicated so we first need to process all // the entities first, then do another pass so we can randomly reference the other @@ -177,7 +207,7 @@ else if (toEntity.hasTag("release:version")) { if (toEntity.getName().equals(versionEntity.getName())) { continue; } - if (!compositeEntityMap.containsKey(toEntity.getName())) { + if (!compositeEntityConstituentMap.containsKey(toEntity.getName())) { // we can copy the relationship exactly - just have to fix the "from" which is done // in the Copy method. MTRelationship newRelationship = MTRelationship.Copy(relationship, compositeEntity, null); @@ -185,19 +215,23 @@ else if (toEntity.hasTag("release:version")) { compositeEntity.addRelationship(newRelationship); continue; } - MTCompositeEntity toCompositeEntity = compositeEntityMap.get(toEntity.getName()); + MTCompositeEntity toCompositeEntity = compositeEntityConstituentMap.get(toEntity.getName()); MTRelationship newRelationship = MTRelationship.Copy(relationship, compositeEntity, toCompositeEntity); compositeEntity.addRelationship(newRelationship); //ECLog.logInfo("Adding Composite Object Relationship to Composite object: " + newRelationship.getName()); } - //ECLog.logInfo("Version entity " + versionEntity.getName() + " has " + versionEntity.getRelationshipCount() + " relationships."); + //ECLog.logInfo("Entity " + compositeEntity.getName() + " has Version entity " + versionEntity.getName() + " has " + versionEntity.getRelationshipCount() + " relationships."); for (MTRelationship relationship : versionEntity.getRelationships()) { MTEntity toEntity = relationship.getTo().getEntity(); + if (toEntity == null) { + ECLog.logWarning("Relationship " + versionEntity.getName() + "." + relationship.getName() + " does NOT have a \"to\" entity!"); + continue; + } // don't take relationships to object parent if (relationship.isParent() && toEntity.getName().equals(objectEntity.getName())) { continue; } - if (!compositeEntityMap.containsKey(toEntity.getName())) { + if (!compositeEntityConstituentMap.containsKey(toEntity.getName())) { // we can copy the relationship exactly - just have to fix the "from" which is done // in the Copy method. MTRelationship newRelationship = MTRelationship.Copy(relationship, compositeEntity, null); @@ -205,7 +239,7 @@ else if (toEntity.hasTag("release:version")) { compositeEntity.addRelationship(newRelationship); continue; } - MTCompositeEntity toCompositeEntity = compositeEntityMap.get(toEntity.getName()); + MTCompositeEntity toCompositeEntity = compositeEntityConstituentMap.get(toEntity.getName()); MTRelationship newRelationship = MTRelationship.Copy(relationship, compositeEntity, toCompositeEntity); //ECLog.logInfo("Adding Composite Version Relationship to Composite object: " + newRelationship.getName()); compositeEntity.addRelationship(newRelationship); @@ -213,7 +247,159 @@ else if (toEntity.hasTag("release:version")) { compositeEntity.getModule().addEntity(compositeEntity); space.addEntity(compositeEntity); } + } + // ------------------------------------------------ + // It turns out that for any entity related to a + // Released entity we also need to create a Released + // version of it so it. + // ------------------------------------------------ + boolean foundReleasedRelated = false; + do { + foundReleasedRelated = false; + for (MTModule module : space.getModules()) { + + if (module.isIncluded()) { + continue; + } + + for (MTEntity entity : module.getEntities()) { + if (entity.isIncluded() || entity.isExtern() || entity.isImplicit() + || entity.isSecondary() || entity.isTransient()) { + continue; + } + if (entity.isCompositeEntity() || releasedVarientOfEntityMap.containsKey(entity.getName())) { + continue; // we have already determined this is release related + } + + if (entity.hasTagPrefixed("release:")) { + continue; + } + MTEntity releaseEntity = null; + boolean isRelatedToReleased = false; + for (MTRelationship relationship : entity.getRelationships()) { + MTEntity toEntity = relationship.getTo().getEntity(); + if (releasedVarientOfEntityMap.containsKey(toEntity.getName()) ) { + //ECLog.logInfo("----- is related to released via relationship: " + entity.getName() + "." + relationship.getName() + " toEntity = " + toEntity.getName()); + MTEntity relatedEntity = releasedVarientOfEntityMap.get(toEntity.getName()); + if (relatedEntity.isCompositeEntity()) { + releaseEntity = ((MTCompositeEntity) relatedEntity).getConstituentEntity(MTCompositeEntity.ReleaseTag); + isRelatedToReleased = true; + break; + } + } + } + + if (!isRelatedToReleased) { + continue; + } + + // + // Create the Released entity + // + foundReleasedRelated = true; + MTCompositeEntity releasedEntity = new MTCompositeEntity(entity.getParserRuleContext(), entity.getModule(), compositEntityNamePrefix + entity.getName()); + releasedVarientOfEntityMap.put(entity.getName(), releasedEntity); + releasedEntity.addConstituentEntity(MTCompositeEntity.ObjectTag, entity); + compositeEntityConstituentMap.put(entity.getName(), releasedEntity); + releasedEntity.addRealm(realm); + ECLog.logInfo("Creating Released Entity related to object/revision pair: " + releasedEntity.getName()); + + // + // copy primary key + // + MTAttribute primaryKeyAttribute = new MTAttribute(entity.getParserRuleContext(), + releasedEntity, entity.getPrimaryKeyAttribute().getTypeName(), + entity.getPrimaryKeyAttribute().getName()); + MTPrimaryKey newPrimaryKey = new MTPrimaryKey(entity.getPrimaryKey().getParserRuleContext()); + newPrimaryKey.addAttribute(primaryKeyAttribute); + releasedEntity.setPrimaryKey(newPrimaryKey); + + // + // Create relationship from this Released entity back to the "release" entity + // + MTRelationship releaseFKRelationship = new MTRelationship( + releasedEntity.getParserRuleContext(), + ECStringUtil.Uncapitalize(releaseEntity.getName()), + releasedEntity.getName(), + HalfRelationshipPlurality.ONE, + releaseEntity.getName(), true, true, null, null, null); + releaseFKRelationship.addTag("ignore"); + releasedEntity.addRelationship(releaseFKRelationship); + releasedEntity.addConstituentEntity(MTCompositeEntity.ReleaseTag, releaseEntity); + + // create a one to many relationship on the release entity to this composite entity + MTRelationship releaseRelationship = new MTRelationship( + releasedEntity.getParserRuleContext(), + ECStringUtil.Uncapitalize(compositEntityNamePrefix) + ECStringUtil.Capitalize(ECStringUtil.Pluralize(entity.getName())), + releaseEntity.getName(), + HalfRelationshipPlurality.MANY, + releasedEntity.getName(), true, false, null, null, null); + releaseEntity.addRelationship(releaseRelationship); + + // + // copy attributes + // + for (MTAttribute attribute : entity.getAttributes()) { + MTAttribute releasedAttribute = MTAttribute.Copy(attribute, releasedEntity); + releasedEntity.addAttribute(releasedAttribute); + } + + // + // copy relationships but change TO relationship to the Released version + // + for (MTRelationship relationship : entity.getRelationships()) { + MTEntity toEntity = relationship.getTo().getEntity(); + + //ECLog.logInfo("CHECKING relationships for: " + entity.getName() + " relationship to entity: " + toEntity.getName()); + MTCompositeEntity toCompositeEntity = compositeEntityConstituentMap.get(toEntity.getName()); + if (toCompositeEntity != null && toCompositeEntity.isCompositeEntity() && !((MTCompositeEntity)releasedEntity).hasConstituentEntity(MTCompositeEntity.ReleaseTag)) { + //ECLog.logInfo("COPYING CONSTITUENT ENTITY (" + MTCompositeEntity.ReleaseTag + ") "+ toCompositeEntity.getConstituentEntity(MTCompositeEntity.ReleaseTag).getName() + " to Composite Entity: " + toCompositeEntity.getName()); + MTEntity toEntityReleaseEntity = toCompositeEntity.getConstituentEntity(MTCompositeEntity.ReleaseTag); + releasedEntity.addConstituentEntity(MTCompositeEntity.ReleaseTag, toEntityReleaseEntity); +// compositeEntityConstituentMap.put(toEntityReleaseEntity.getName(), releasedEntity); + } + + if (!compositeEntityConstituentMap.containsKey(toEntity.getName())) { + // we can copy the relationship exactly - just have to fix the "from" which is done + // in the Copy method. + MTRelationship newRelationship = MTRelationship.Copy(relationship, releasedEntity, null); + //ECLog.logInfo("Adding Composite Object Relationship to non-composite entity: " + newRelationship.getName()); + releasedEntity.addRelationship(newRelationship); + continue; + } + if (compositeEntityConstituentMap.containsKey(toEntity.getName())) { + MTEntity releasedToEntity = compositeEntityConstituentMap.get(toEntity.getName()); + releasedToEntity.addRealm(realm); + //ECLog.logInfo("Adding REALM " + realm + " to release entity: " + releasedToEntity.getName()); + MTRelationship releasedRelationship = MTRelationship.Copy(relationship, releasedEntity, releasedToEntity); + releasedEntity.addRelationship(releasedRelationship); + } + } + releasedRelatedEntityMap.put(releasedEntity.getName(), releasedEntity); + releasedEntity.getModule().addEntity(releasedEntity); + space.addEntity(releasedEntity); + } + } + } + while (foundReleasedRelated); +// for (MTModule module : space.getModules()) { +// +// if (module.isIncluded()) { +// continue; +// } +// +// for (MTEntity entity : module.getEntities()) { +// if (entity.isIncluded() || entity.isExtern() || entity.isImplicit() +// || entity.isSecondary()) { +// continue; +// } +// if (releasedRelatedEntityMap.containsKey(entity.getName())) { +// continue; // we have already determined this is release related +// } +// //ECLog.logInfo("FOUND NON-RELEASED ENTITY: " + entity.getName()); +// } +// } } } diff --git a/src/main/java/org/entityc/compiler/transform/template/tree/FTOutlet.java b/src/main/java/org/entityc/compiler/transform/template/tree/FTOutlet.java index c053a52..0d97a31 100644 --- a/src/main/java/org/entityc/compiler/transform/template/tree/FTOutlet.java +++ b/src/main/java/org/entityc/compiler/transform/template/tree/FTOutlet.java @@ -68,6 +68,9 @@ public void transform(FTTransformSession session) { session.setValue("__outlet", this); session.setValue("__author", author); author.transformFromOutlet(session); + if (session.isPendingReturn()) { + session.setPendingReturn(false); // now clear it + } session.removeValue("__outlet"); session.removeValue("__author"); if (author.getScope() == FTPublishScope.Author) { diff --git a/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTFullnameFilter.java b/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTFullnameFilter.java index 27c03a2..cf7b5e7 100644 --- a/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTFullnameFilter.java +++ b/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTFullnameFilter.java @@ -8,6 +8,8 @@ import org.antlr.v4.runtime.ParserRuleContext; import org.entityc.compiler.model.domain.MTDomainBased; +import org.entityc.compiler.model.entity.MTAttribute; +import org.entityc.compiler.model.entity.MTRelationship; import org.entityc.compiler.transform.template.tree.FTTransformSession; import org.entityc.compiler.transform.template.tree.expression.FTConstant; import org.entityc.compiler.transform.template.tree.expression.FTExpression; @@ -27,6 +29,10 @@ public FTFullnameFilter() { + "This can be useful for construction a Java import statement, for instance."); addSingleInputType(MTDomainBased.class, "Any class that is with respect to a domain (such as MTDEntity)."); + addSingleInputType(MTAttribute.class, + "An attribute."); + addSingleInputType(MTRelationship.class, + "A relationship."); addFilterParam(delimiterParam); } @@ -45,7 +51,12 @@ public Object filter(ParserRuleContext ctx, FTTransformSession session, Object i } if (input instanceof MTDomainBased) { return ((MTDomainBased) input).getFullname(delim); + } else if (input instanceof MTAttribute) { + return ((MTAttribute) input).getEntityName() + delim + ((MTAttribute) input).getName(); + } else if (input instanceof MTRelationship) { + return ((MTRelationship) input).getFrom().getEntityName() + delim + ((MTRelationship) input).getName(); } + return null; } } diff --git a/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTReverseFilter.java b/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTReverseFilter.java index 8c8f54d..771889d 100644 --- a/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTReverseFilter.java +++ b/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTReverseFilter.java @@ -11,11 +11,7 @@ import org.entityc.compiler.model.domain.MTDEAttribute; import org.entityc.compiler.model.domain.MTDERelationship; import org.entityc.compiler.model.domain.MTDEntity; -import org.entityc.compiler.model.entity.MTAttribute; -import org.entityc.compiler.model.entity.MTEntity; -import org.entityc.compiler.model.entity.MTEnum; -import org.entityc.compiler.model.entity.MTEnumItem; -import org.entityc.compiler.model.entity.MTRelationship; +import org.entityc.compiler.model.entity.*; import org.entityc.compiler.model.foundation.MFObject; import org.entityc.compiler.transform.template.tree.FTTemplate; import org.entityc.compiler.transform.template.tree.FTTransformSession; @@ -36,6 +32,7 @@ public FTReverseFilter() { this.addCollectionInputType(MTAttribute.class); this.addCollectionInputType(MTDEAttribute.class); this.addCollectionInputType(MTEntity.class); + this.addCollectionInputType(MTCompositeEntity.class); this.addCollectionInputType(MTDEntity.class); this.addCollectionInputType(MTModule.class); this.addCollectionInputType(MTEnum.class); From f2b9ca62744296804e81ce2cb5dbdcabbd40ffd1 Mon Sep 17 00:00:00 2001 From: Bob Garner Date: Thu, 23 Nov 2023 07:09:12 -0800 Subject: [PATCH 10/12] Fixed some issues with Released transform. --- .../model/domain/MTDERelationshipHalf.java | 2 + .../compiler/model/domain/MTDEntity.java | 5 + .../model/entity/MTCompositeEntity.java | 17 +- .../compiler/model/entity/MTEntity.java | 17 +- .../compiler/model/entity/MTRelationship.java | 135 ++++---- .../model/entity/MTRelationshipHalf.java | 11 +- .../transform/MTVImplicitTransform.java | 6 +- .../transform/MTVReleasedTransform.java | 192 +++++++---- .../entityc/compiler/EntityCompilerTest.java | 6 + .../CompilerDocs/CompilerDocsExpected.txt | 312 ++++++++++++++++++ .../ReleasedTransform/ReleasedTemplate.eml | 73 ++++ .../ReleasedTransform/ReleasedTransform.edl | 124 +++++++ .../ReleasedTransformExpected.txt | 77 +++++ 13 files changed, 834 insertions(+), 143 deletions(-) create mode 100644 test/resources/compiler/main/ReleasedTransform/ReleasedTemplate.eml create mode 100644 test/resources/compiler/main/ReleasedTransform/ReleasedTransform.edl create mode 100644 test/resources/compiler/main/ReleasedTransform/ReleasedTransformExpected.txt diff --git a/src/main/java/org/entityc/compiler/model/domain/MTDERelationshipHalf.java b/src/main/java/org/entityc/compiler/model/domain/MTDERelationshipHalf.java index 759ad70..bc88b8c 100644 --- a/src/main/java/org/entityc/compiler/model/domain/MTDERelationshipHalf.java +++ b/src/main/java/org/entityc/compiler/model/domain/MTDERelationshipHalf.java @@ -11,8 +11,10 @@ import org.entityc.compiler.model.MTReferenceResolution; import org.entityc.compiler.model.config.MTSpace; import org.entityc.compiler.model.entity.HalfRelationshipPlurality; +import org.entityc.compiler.model.entity.MTEntity; import org.entityc.compiler.model.entity.MTRelationshipHalf; import org.entityc.compiler.model.visitor.MTVisitor; +import org.entityc.compiler.util.ECLog; public class MTDERelationshipHalf extends MTNode implements MTDomainBased, MTReferenceResolution { diff --git a/src/main/java/org/entityc/compiler/model/domain/MTDEntity.java b/src/main/java/org/entityc/compiler/model/domain/MTDEntity.java index 0c19d91..49c4f7f 100644 --- a/src/main/java/org/entityc/compiler/model/domain/MTDEntity.java +++ b/src/main/java/org/entityc/compiler/model/domain/MTDEntity.java @@ -885,4 +885,9 @@ public MTSpace getSpace() { } return null; } + + @Override + public String toString() { + return domain.getName() + "." + entityName; + } } diff --git a/src/main/java/org/entityc/compiler/model/entity/MTCompositeEntity.java b/src/main/java/org/entityc/compiler/model/entity/MTCompositeEntity.java index 41a441f..4c65160 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTCompositeEntity.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTCompositeEntity.java @@ -5,6 +5,7 @@ import org.entityc.compiler.util.ECLog; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; public class MTCompositeEntity extends MTEntity { @@ -39,7 +40,7 @@ public boolean hasConstituentEntity(String tag) { return constituentEntities.containsKey(tag); } - public MTEntity getAnyConstituentEntity(String tag) { + public MTEntity getAnyConstituentEntity(String tag, HashSet history) { MTEntity constituentEntity = constituentEntities.get(tag); if (constituentEntity != null) { return constituentEntity; @@ -47,6 +48,9 @@ public MTEntity getAnyConstituentEntity(String tag) { ECLog.logInfo("getAnyConstituentEntity(" + tag + ") Checking relationships for " + getName() + "..."); for (MTRelationship relationship : getRelationships()) { MTEntity toEntity = relationship.getTo().getEntity(); + if (history.contains(toEntity.getName())) { + continue; // break infinite recursion + } if (toEntity.hasTag("release:top") && tag.equals(ReleaseTag)) { return toEntity; } @@ -54,7 +58,8 @@ public MTEntity getAnyConstituentEntity(String tag) { ECLog.logInfo(" Relationship " + relationship.getName() + " to entity " + toEntity.getName() + " is not to a composite entity."); continue; } - MTEntity compositeToEntity = ((MTCompositeEntity)toEntity).getAnyConstituentEntity(tag); + history.add(toEntity.getName()); + MTEntity compositeToEntity = ((MTCompositeEntity)toEntity).getAnyConstituentEntity(tag, history); if (compositeToEntity != null) { return compositeToEntity; } @@ -63,8 +68,12 @@ public MTEntity getAnyConstituentEntity(String tag) { return null; } - public boolean hasAnyConstituentEntity(String tag) { - return getAnyConstituentEntity(tag) != null; + public MTEntity getAnyConstituentEntity(String tag) { + return getAnyConstituentEntity(tag, new HashSet()); + } + + public boolean hasAnyConstituentEntity(String tag) { + return getAnyConstituentEntity(tag, new HashSet()) != null; } public void addAttribute(String tag, MTAttribute attribute, MTEntity fromEntity) { diff --git a/src/main/java/org/entityc/compiler/model/entity/MTEntity.java b/src/main/java/org/entityc/compiler/model/entity/MTEntity.java index 3502b80..cdf0fc1 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTEntity.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTEntity.java @@ -841,7 +841,7 @@ public void addUniqueness(MTUniqueness uniqueness) { description = "Returns a list of relationships from this entity to a specified entity.") public List getRelationshipsWithToEntity( @ModelMethodParameter(description = "The entity that the relationships are **to**.") - MTEntity toEntity) { + MTEntity toEntity) { List matchingRelationships = new ArrayList<>(); for (MTRelationship relationship : relationships) { if (relationship.getTo().getEntityName().equals(toEntity.getName())) { @@ -851,6 +851,21 @@ public List getRelationshipsWithToEntity( return matchingRelationships; } + @ModelMethod( + category = ModelMethodCategory.RELATIONSHIP, + description = "Returns the first relationships from this entity to a specified entity. This method should be used when only one is expected.") + public MTRelationship getRelationshipWithToEntity( + @ModelMethodParameter(description = "The entity that the relationships are **to**.") + MTEntity toEntity) { + List matchingRelationships = new ArrayList<>(); + for (MTRelationship relationship : relationships) { + if (relationship.getTo().getEntityName().equals(toEntity.getName())) { + return relationship; + } + } + return null; + } + @ModelMethod( category = ModelMethodCategory.RELATIONSHIP, description = diff --git a/src/main/java/org/entityc/compiler/model/entity/MTRelationship.java b/src/main/java/org/entityc/compiler/model/entity/MTRelationship.java index fadea51..23e99cd 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTRelationship.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTRelationship.java @@ -29,17 +29,17 @@ public class MTRelationship extends MTNode implements MTReferenceResolution, MTT public static final String INTERNAL_MANY_TO_MANY_TAG = "internal:many-to-many"; - private final String name; + private final String name; private final MTRelationshipHalf to; private final MTRelationshipHalf from; - private final boolean optional; - private final boolean parent; - private final String reverseName; - private final String toEntityIdName; - private final String templateArgName; - private boolean implicit; - private MTRelationship reverseRelationship; - private MTAttribute effectiveAttribute; + private final boolean optional; + private final boolean parent; + private final String reverseName; + private final String toEntityIdName; + private final String templateArgName; + private boolean implicit; + private MTRelationship reverseRelationship; + private MTAttribute effectiveAttribute; public MTRelationship(ParserRuleContext ctx, String name, @@ -51,38 +51,46 @@ public MTRelationship(ParserRuleContext ctx, String reverseName, String toEntityIdName, String templateArgName - ) { + ) { super(ctx); - this.name = name; - this.from = new MTRelationshipHalf(ctx, fromEntityName); - this.to = new MTRelationshipHalf(ctx, toPlurality, toEntityName); - this.optional = optional; - this.parent = parent; - this.reverseName = reverseName; - this.toEntityIdName = toEntityIdName; + this.name = name; + this.from = new MTRelationshipHalf(ctx, fromEntityName); + this.to = new MTRelationshipHalf(ctx, toPlurality, toEntityName); + this.optional = optional; + this.parent = parent; + this.reverseName = reverseName; + this.toEntityIdName = toEntityIdName; this.templateArgName = templateArgName; +// if (name.equals("gearCompany")) { +// ECLog.logInfo("Created gearCompany relationship"); +// } } protected MTRelationship(String secondaryName, MTRelationship primaryRelationship, MTRelationshipHalf fromHalf, MTRelationshipHalf toHalf) { super(primaryRelationship.getParserRuleContext()); - this.name = secondaryName; - this.from = fromHalf; + this.name = secondaryName; + this.from = fromHalf; if (toHalf != null) { this.to = toHalf; - } else { + } + else { this.to = primaryRelationship.to; } - this.optional = primaryRelationship.optional; - this.parent = primaryRelationship.parent; - this.reverseName = primaryRelationship.reverseName; - this.toEntityIdName = primaryRelationship.toEntityIdName; + this.optional = primaryRelationship.optional; + this.parent = primaryRelationship.parent; + this.reverseName = primaryRelationship.reverseName; + this.toEntityIdName = primaryRelationship.toEntityIdName; this.templateArgName = primaryRelationship.templateArgName; +// if (name.equals("gearCompany")) { +// ECLog.logInfo("Created gearCompany relationship"); +// } } @Override public String toString() { return getFrom().getEntityName() + "." + getName() + " -(" + to.getPlurality().toString() + ")-> " + getTo().getEntityName(); } + public static MTRelationship Copy(MTRelationship relationship, MTEntity newFromEntity, MTEntity newToEntity) { MTRelationshipHalf fromHalf = new MTRelationshipHalf(relationship.getParserRuleContext(), @@ -102,7 +110,7 @@ public static MTRelationship Copy(MTRelationship relationship, MTEntity newFromE @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "Indicates whether the relationship was created because although it was not declared it can be " - + "implied based on relationships declared to this entity.") + + "implied based on relationships declared to this entity.") public boolean isImplicit() { return implicit; } @@ -113,14 +121,14 @@ public void setImplicit(boolean implicit) { @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "When a relationship is defined as part of an entity template, it has a template argument that " - + "will be used when an entity is created from it. This will return the name of that argument.") + + "will be used when an entity is created from it. This will return the name of that argument.") public String getTemplateArgName() { return templateArgName; } @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "Returns the \"to\" part of the relationship. This part tells you about the entity to which this " - + "relationship is bound.") + + "relationship is bound.") public MTRelationshipHalf getTo() { return to; } @@ -128,21 +136,21 @@ public MTRelationshipHalf getTo() { @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "Returns the \"from\" part of the relationship which references the entity in which this relationship " - + "is defined.") + + "is defined.") public MTRelationshipHalf getFrom() { return from; } @ModelMethod(category = ModelMethodCategory.ATTRIBUTE, description = "Returns the effective attribute associated with this relationship. The effective attribute " - + "can help you persist the relationship in a database.") + + "can help you persist the relationship in a database.") public MTAttribute getEffectiveAttribute() { if (effectiveAttribute == null && to.getEntity() != null && from.getEntity() != null ) { if (to.getPlurality() == HalfRelationshipPlurality.ONE) { MTAttribute primarykeyAttribute = to.getEntity().getPrimaryKey().getAttributes().get(0); - String typeName = INT64.getName(); + String typeName = INT64.getName(); if (primarykeyAttribute.getType().isNativeType()) { typeName = ((MTNativeType) (primarykeyAttribute.getType())).getDataType().getName(); } @@ -161,23 +169,23 @@ else if (to.getPlurality() == HalfRelationshipPlurality.MANY && !isParent()) { @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "Indicates whether this relationship was defined with the `parent` keyword. Relationships defined " - + "this way are ones that imply that this entity considers its identity as being the combination " - + "of its parent entity and itself.") + + "this way are ones that imply that this entity considers its identity as being the combination " + + "of its parent entity and itself.") public boolean isParent() { return parent; } @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "Indicates whether this relationship was defined with the `parent` keyword and **not** with " - + "the `optional` keyword. Within the set of relationships of an entity, only one relationship " - + "should be defined this way.") + + "the `optional` keyword. Within the set of relationships of an entity, only one relationship " + + "should be defined this way.") public boolean isPrimaryParent() { return isParent() && !isOptional(); } @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "Indicates whether this relationship was defined with the `optional` keyword, indicating that " - + "relationships to the other entity is not required.") + + "relationships to the other entity is not required.") public boolean isOptional() { return optional; } @@ -188,7 +196,7 @@ public void setToPlurality(HalfRelationshipPlurality toPlurality) { @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "Returns the relationship from the perspective \"to\" entity to this entity, that is, the " - + "reverse relationship.") + + "reverse relationship.") public MTRelationship getReverseRelationship() { return reverseRelationship; } @@ -196,8 +204,8 @@ public MTRelationship getReverseRelationship() { @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "Indicates whether this relationship is a one-to-many; where in a one-to-many relationship an object " - + "of this entity can have multiple relationships with objects of another entity but not the other way " - + "around.") + + "of this entity can have multiple relationships with objects of another entity but not the other way " + + "around.") public boolean isOneToMany() { return getFullRelationshipPlurality() == FullRelationshipPlurality.ONE_TO_MANY; } @@ -222,7 +230,7 @@ public FullRelationshipPlurality getFullRelationshipPlurality() { @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, description = "Indicates whether this relationship is a many-to-many; where in a many-to-many relationship multiple " - + "objects of this entity can have multiple relationships with objects of another entity.") + + "objects of this entity can have multiple relationships with objects of another entity.") public boolean isManyToMany() { return getFullRelationshipPlurality() == FullRelationshipPlurality.MANY_TO_MANY; } @@ -231,7 +239,7 @@ public boolean isManyToMany() { description = "Gets the entity on the other side of an implicit many-to-many entity.") public MTEntity getImplicitToEntity() { - for(MTRelationship mmRel : to.getEntity().implicitRelationships) { + for (MTRelationship mmRel : to.getEntity().implicitRelationships) { if (!mmRel.to.getEntityName().equals(from.getEntityName())) { return mmRel.to.getEntity(); } @@ -246,7 +254,7 @@ public void accept(MTVisitor visitor) { @Override public boolean resolveReferences(MTSpace space, int pass) { - this.from.setEntity(space.getEntityWithName(from.getEntityName())); + this.from.resolveReferences(space, pass); if (this.to.getEntity() == null) { if (this.to.getTemplateInstantiation() != null) { @@ -254,41 +262,38 @@ public boolean resolveReferences(MTSpace space, int pass) { this.to.getTemplateInstantiation().getEntityTemplateName()); if (template == null) { ECLog.logFatal(this.to.getTemplateInstantiation(), "Unable to find entity template with name: " - + this.to.getTemplateInstantiation().getEntityTemplateName()); + + this.to.getTemplateInstantiation().getEntityTemplateName()); } this.to.setEntity( template.makeEntity(from.getEntity(), to.getEntityName(), this.to.getTemplateInstantiation(), - space)); + space)); } else { - this.to.setEntity(space.getEntityWithName(to.getEntityName())); + this.to.resolveReferences(space, pass); } } if (this.from.getEntityName() == null) { - System.err.println("ERROR: Could not resolve from entity: " + this.from.getEntityName()); + ECLog.logError("Could not resolve from entity: " + this.from.getEntityName()); return false; } if (this.to.getEntityName() == null) { - System.err.println("ERROR: Could not resolve to entity: " + this.to.getEntityName()); + ECLog.logError("Could not resolve to entity: " + this.to.getEntityName()); return false; } // find a list of possble relationships between entities - if (to.getEntity() == null) { - MTEntity toEntity = space.getEntityWithName(to.getEntityName()); - if (toEntity == null) { - if (pass > 7) { - ECLog.logFatal(this, "Unable to find entity named: " + to.getEntityName()); - } - return false; + boolean anotherPass = this.to.resolveReferences(space, pass); + if (anotherPass) { + if (pass > 7) { + ECLog.logFatal(this, "Unable to find entity named: " + to.getEntityName()); } - to.setEntity(toEntity); + return false; } List possibleFromRelationships = to.getEntity().findPossibleRelationshipsWithEntity( from.getEntity()); - boolean found = false; + boolean found = false; boolean duplicates = false; if (pass == 0) { @@ -300,7 +305,7 @@ public boolean resolveReferences(MTSpace space, int pass) { duplicates = true; ECLog.logError( "Found duplicate reverse named relationship matches for: " + from.getEntityName() + " > " - + getReverseName() + " < " + to.getEntityName()); + + getReverseName() + " < " + to.getEntityName()); break; } else { @@ -323,9 +328,9 @@ public boolean resolveReferences(MTSpace space, int pass) { if (found) { duplicates = true; ECLog.logWarning(fromRelationship, - "Found duplicate relationship matches between " + from.getEntity().getName() - + "." + this.getName() + " and " + to.getEntity().getName() + "." - + fromRelationship.getName()); + "Found duplicate relationship matches between " + from.getEntity().getName() + + "." + this.getName() + " and " + to.getEntity().getName() + "." + + fromRelationship.getName()); break; } else { @@ -345,9 +350,9 @@ public boolean resolveReferences(MTSpace space, int pass) { return false; } - if (!found && !alreadyProcessed) { - //System.out.println("Could not find reverse relationship between " + fromEntityName + " and " + toEntityName); - } +// if (!found && !alreadyProcessed) { +// ECLog.logWarning("Could not find reverse relationship between " + from.getEntityName() + " and " + to.getEntityName() + " for relationship: " + getName()); +// } } return false; @@ -367,8 +372,8 @@ public String getName() { public MTRelationship makeCopyFromEntityName(String fromEntityNameOfCopy) { MTRelationship copy = new MTRelationship(null, name, fromEntityNameOfCopy, from.getPlurality(), - to.getEntityName(), optional, parent, reverseName, toEntityIdName, - templateArgName); + to.getEntityName(), optional, parent, reverseName, toEntityIdName, + templateArgName); return copy; } @@ -381,7 +386,7 @@ public String getToEntityIdName() { description = "Indicates whether the \"to\" entity of this relationship has been tagged with the specified tag.") public boolean hasToEntityTagged( @ModelMethodParameter(description = "The tag with which to search.") - String tag) { + String tag) { return to != null && to.getEntity().hasTag(tag); } } diff --git a/src/main/java/org/entityc/compiler/model/entity/MTRelationshipHalf.java b/src/main/java/org/entityc/compiler/model/entity/MTRelationshipHalf.java index a156d2a..0e0b25c 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTRelationshipHalf.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTRelationshipHalf.java @@ -8,6 +8,7 @@ import org.antlr.v4.runtime.ParserRuleContext; import org.entityc.compiler.model.MTNode; +import org.entityc.compiler.model.config.MTSpace; import org.entityc.compiler.model.visitor.MTVisitor; public class MTRelationshipHalf extends MTNode { @@ -28,7 +29,15 @@ public MTRelationshipHalf(ParserRuleContext ctx, HalfRelationshipPlurality plura this.entityName = entityName; } - public HalfRelationshipPlurality getPlurality() { + public boolean resolveReferences(MTSpace space, int pass) { + if (this.entity != null) { + return false; + } + this.entity = space.getEntityWithName(entityName); + return this.entity == null; + } + + public HalfRelationshipPlurality getPlurality() { return plurality; } diff --git a/src/main/java/org/entityc/compiler/transform/MTVImplicitTransform.java b/src/main/java/org/entityc/compiler/transform/MTVImplicitTransform.java index b44157e..4fab275 100644 --- a/src/main/java/org/entityc/compiler/transform/MTVImplicitTransform.java +++ b/src/main/java/org/entityc/compiler/transform/MTVImplicitTransform.java @@ -77,16 +77,16 @@ public void visitRelationship(MTRelationship relationship) { // if this is a realm based transform then make sure we are operating on entities from that realm. if (realm != null) { if (!(fromEntity instanceof MTCompositeEntity) && (toEntity instanceof MTCompositeEntity)) { - //ECLog.logInfo("(wrong class) REALM " + realm + ": not processing fromEntity: " + fromEntity.getName() + " toEntity: " + toEntity.getName()); return; } if (!fromEntity.isInRealm(realm) || !toEntity.isInRealm(realm)) { - //ECLog.logInfo("(wrong realm) REALM " + realm + ": not processing fromEntity: " + fromEntity.getName() + " toEntity: " + toEntity.getName()); return; } - //ECLog.logInfo("REALM " + realm + ": PROCESSING fromEntity: " + fromEntity.getName() + " toEntity: " + toEntity.getName()); } + // + // The "to" entity must have a primary key for this part of the transform. + // MTPrimaryKey toPrimaryKey = toEntity.getPrimaryKey(); if (toPrimaryKey == null) { return; diff --git a/src/main/java/org/entityc/compiler/transform/MTVReleasedTransform.java b/src/main/java/org/entityc/compiler/transform/MTVReleasedTransform.java index 53720ca..a548d26 100644 --- a/src/main/java/org/entityc/compiler/transform/MTVReleasedTransform.java +++ b/src/main/java/org/entityc/compiler/transform/MTVReleasedTransform.java @@ -59,14 +59,19 @@ public void start(String ignore) { Map releasedRelatedEntityMap = new HashMap<>(); Map releasedVarientOfEntityMap = new HashMap<>(); + List relationshipsToResolve = new ArrayList<>(); + List compositeEntityList = new ArrayList<>(); + for (MTModule module : space.getModules()) { //ECLog.logInfo("--------------------------------------------------------- MODULE: " + module.getName()); if (module.isIncluded()) { //ECLog.logInfo("Ignoring module: " + module.getName()); continue; } + // // Find all the ones that are not involved in versioning and add them // to our new "version-less" realm. + // for (MTEntity entity : module.getEntities()) { if (entity.hasTag("release:binder") || entity.hasTag("release:object") @@ -75,7 +80,11 @@ public void start(String ignore) { } entity.addRealm(realm); } - List compositeEntityList = new ArrayList<>(); + // + // Go through all the entities, find the ones that have both an object and version, + // create a new composite entity and then copy over the attributes (we will copy the + // relationships in another pass). + // for (MTEntity entity : module.getEntities()) { if (entity.isIncluded() || entity.isExtern() || entity.isImplicit() || entity.isTransient() || !entity.hasTag("release:binder")) { @@ -118,8 +127,9 @@ else if (toEntity.hasTag("release:version")) { releasedRelatedEntityMap.put(objectEntity.getName(), objectEntity); releasedRelatedEntityMap.put(versionEntity.getName(), versionEntity); + // // Now create a new entity that unifies these three - + // MTCompositeEntity compositeEntity = new MTCompositeEntity(objectEntity.getParserRuleContext(), objectEntity.getModule(), compositEntityNamePrefix + objectEntity.getName()); @@ -151,6 +161,7 @@ else if (toEntity.hasTag("release:version")) { releaseFKRelationship.addTag("ignore"); compositeEntity.addRelationship(releaseFKRelationship); compositeEntity.addConstituentEntity(MTCompositeEntity.ReleaseTag, releaseEntity); + relationshipsToResolve.add(releaseFKRelationship); // // Object Entity Attributes // @@ -175,6 +186,7 @@ else if (toEntity.hasTag("release:version")) { } compositeEntityList.add(compositeEntity); + //ECLog.logInfo("Creating Composite Entity: " + compositeEntity.getName()); compositeEntityConstituentMap.put(objectEntity.getName(), compositeEntity); compositeEntityConstituentMap.put(versionEntity.getName(), compositeEntity); @@ -186,75 +198,22 @@ else if (toEntity.hasTag("release:version")) { HalfRelationshipPlurality.MANY, compositeEntity.getName(), true, false, null, null, null); releaseEntity.addRelationship(releaseRelationship); + relationshipsToResolve.add(releaseRelationship); // Relationships are more complicated so we first need to process all // the entities first, then do another pass so we can randomly reference the other // entities. } - //ECLog.logInfo("FOUND " + compositeEntityList.size() + " composite objects in module: " + module.getName()); - for (MTCompositeEntity compositeEntity : compositeEntityList) { - MTEntity objectEntity = compositeEntity.getConstituentEntity(MTCompositeEntity.ObjectTag); - MTEntity versionEntity = compositeEntity.getConstituentEntity(MTCompositeEntity.VersionTag); - //ECLog.logInfo("Object entity " + objectEntity.getName() + " has " + objectEntity.getRelationshipCount() + " relationships."); - for (MTRelationship relationship : objectEntity.getRelationships()) { - //ECLog.logInfo(">>>> relationship: " + relationship.getName()); - if (compositeEntity.hasRelationshipNamed(relationship.getName())) { - ECLog.logWarning("We have already copied relationship: " + relationship.getName()); - continue; - } - MTEntity toEntity = relationship.getTo().getEntity(); - // don't take relationships to version - if (toEntity.getName().equals(versionEntity.getName())) { - continue; - } - if (!compositeEntityConstituentMap.containsKey(toEntity.getName())) { - // we can copy the relationship exactly - just have to fix the "from" which is done - // in the Copy method. - MTRelationship newRelationship = MTRelationship.Copy(relationship, compositeEntity, null); - //ECLog.logInfo("Adding Composite Object Relationship to non-composite entity: " + newRelationship.getName()); - compositeEntity.addRelationship(newRelationship); - continue; - } - MTCompositeEntity toCompositeEntity = compositeEntityConstituentMap.get(toEntity.getName()); - MTRelationship newRelationship = MTRelationship.Copy(relationship, compositeEntity, toCompositeEntity); - compositeEntity.addRelationship(newRelationship); - //ECLog.logInfo("Adding Composite Object Relationship to Composite object: " + newRelationship.getName()); - } - //ECLog.logInfo("Entity " + compositeEntity.getName() + " has Version entity " + versionEntity.getName() + " has " + versionEntity.getRelationshipCount() + " relationships."); - for (MTRelationship relationship : versionEntity.getRelationships()) { - MTEntity toEntity = relationship.getTo().getEntity(); - if (toEntity == null) { - ECLog.logWarning("Relationship " + versionEntity.getName() + "." + relationship.getName() + " does NOT have a \"to\" entity!"); - continue; - } - // don't take relationships to object parent - if (relationship.isParent() && toEntity.getName().equals(objectEntity.getName())) { - continue; - } - if (!compositeEntityConstituentMap.containsKey(toEntity.getName())) { - // we can copy the relationship exactly - just have to fix the "from" which is done - // in the Copy method. - MTRelationship newRelationship = MTRelationship.Copy(relationship, compositeEntity, null); - //ECLog.logInfo("Adding Composite Version Relationship to non-composite entity: " + newRelationship.getName()); - compositeEntity.addRelationship(newRelationship); - continue; - } - MTCompositeEntity toCompositeEntity = compositeEntityConstituentMap.get(toEntity.getName()); - MTRelationship newRelationship = MTRelationship.Copy(relationship, compositeEntity, toCompositeEntity); - //ECLog.logInfo("Adding Composite Version Relationship to Composite object: " + newRelationship.getName()); - compositeEntity.addRelationship(newRelationship); - } - compositeEntity.getModule().addEntity(compositeEntity); - space.addEntity(compositeEntity); - } - } - // ------------------------------------------------ - // It turns out that for any entity related to a - // Released entity we also need to create a Released - // version of it so it. - // ------------------------------------------------ - boolean foundReleasedRelated = false; + //ECLog.logInfo("FOUND " + compositeEntityList.size() + " composite entities"); + + // + // Now we need to see all the other entities related to the object or version entities and convert them also + // to composite entities (even though they don't have version entities) so that we don't have non-composite + // entities making reference to composite entities. + // + boolean foundReleasedRelated; + int newReleasedEntities = 0; do { foundReleasedRelated = false; for (MTModule module : space.getModules()) { @@ -263,6 +222,7 @@ else if (toEntity.hasTag("release:version")) { continue; } + // TODO: we need to also check relationships from composite to not-fully-composite since it may be assumed for (MTEntity entity : module.getEntities()) { if (entity.isIncluded() || entity.isExtern() || entity.isImplicit() || entity.isSecondary() || entity.isTransient()) { @@ -276,11 +236,15 @@ else if (toEntity.hasTag("release:version")) { continue; } + // + // Determine if this entity has a relationship with a "Released" entity and if so, get the + // top Release entity. + // MTEntity releaseEntity = null; boolean isRelatedToReleased = false; for (MTRelationship relationship : entity.getRelationships()) { MTEntity toEntity = relationship.getTo().getEntity(); - if (releasedVarientOfEntityMap.containsKey(toEntity.getName()) ) { + if (releasedVarientOfEntityMap.containsKey(toEntity.getName())) { //ECLog.logInfo("----- is related to released via relationship: " + entity.getName() + "." + relationship.getName() + " toEntity = " + toEntity.getName()); MTEntity relatedEntity = releasedVarientOfEntityMap.get(toEntity.getName()); if (relatedEntity.isCompositeEntity()) { @@ -291,12 +255,16 @@ else if (toEntity.hasTag("release:version")) { } } + // + // If it is not related to a released entity then skip the rest. + // if (!isRelatedToReleased) { continue; } // - // Create the Released entity + // Create the Released "composite" entity. Even though it will be created as a composite entity, it will only have + // the object and release constituents. // foundReleasedRelated = true; MTCompositeEntity releasedEntity = new MTCompositeEntity(entity.getParserRuleContext(), entity.getModule(), compositEntityNamePrefix + entity.getName()); @@ -304,7 +272,9 @@ else if (toEntity.hasTag("release:version")) { releasedEntity.addConstituentEntity(MTCompositeEntity.ObjectTag, entity); compositeEntityConstituentMap.put(entity.getName(), releasedEntity); releasedEntity.addRealm(realm); - ECLog.logInfo("Creating Released Entity related to object/revision pair: " + releasedEntity.getName()); + compositeEntityList.add(releasedEntity); + //ECLog.logInfo("Creating Released Entity: " + releasedEntity.getName() + " related to object: " + entity.getName()); + newReleasedEntities++; // // copy primary key @@ -316,6 +286,7 @@ else if (toEntity.hasTag("release:version")) { newPrimaryKey.addAttribute(primaryKeyAttribute); releasedEntity.setPrimaryKey(newPrimaryKey); + // // Create relationship from this Released entity back to the "release" entity // @@ -328,6 +299,7 @@ else if (toEntity.hasTag("release:version")) { releaseFKRelationship.addTag("ignore"); releasedEntity.addRelationship(releaseFKRelationship); releasedEntity.addConstituentEntity(MTCompositeEntity.ReleaseTag, releaseEntity); + relationshipsToResolve.add(releaseFKRelationship); // create a one to many relationship on the release entity to this composite entity MTRelationship releaseRelationship = new MTRelationship( @@ -337,6 +309,7 @@ else if (toEntity.hasTag("release:version")) { HalfRelationshipPlurality.MANY, releasedEntity.getName(), true, false, null, null, null); releaseEntity.addRelationship(releaseRelationship); + relationshipsToResolve.add(releaseRelationship); // // copy attributes @@ -354,7 +327,7 @@ else if (toEntity.hasTag("release:version")) { //ECLog.logInfo("CHECKING relationships for: " + entity.getName() + " relationship to entity: " + toEntity.getName()); MTCompositeEntity toCompositeEntity = compositeEntityConstituentMap.get(toEntity.getName()); - if (toCompositeEntity != null && toCompositeEntity.isCompositeEntity() && !((MTCompositeEntity)releasedEntity).hasConstituentEntity(MTCompositeEntity.ReleaseTag)) { + if (toCompositeEntity != null && toCompositeEntity.isCompositeEntity() && !((MTCompositeEntity) releasedEntity).hasConstituentEntity(MTCompositeEntity.ReleaseTag)) { //ECLog.logInfo("COPYING CONSTITUENT ENTITY (" + MTCompositeEntity.ReleaseTag + ") "+ toCompositeEntity.getConstituentEntity(MTCompositeEntity.ReleaseTag).getName() + " to Composite Entity: " + toCompositeEntity.getName()); MTEntity toEntityReleaseEntity = toCompositeEntity.getConstituentEntity(MTCompositeEntity.ReleaseTag); releasedEntity.addConstituentEntity(MTCompositeEntity.ReleaseTag, toEntityReleaseEntity); @@ -384,6 +357,87 @@ else if (toEntity.hasTag("release:version")) { } } while (foundReleasedRelated); + //ECLog.logInfo("FOUND " + newReleasedEntities + " released entities"); + // + // Now that all the composite entities have been created, we can copy the relationships. + // + //ECLog.logInfo("Resolving relationships..."); + for (MTCompositeEntity compositeEntity : compositeEntityList) { + //ECLog.logInfo("Looking at composite entity: " + compositeEntity.getName()); + MTEntity objectEntity = compositeEntity.getConstituentEntity(MTCompositeEntity.ObjectTag); + MTEntity versionEntity = compositeEntity.getConstituentEntity(MTCompositeEntity.VersionTag); + for (MTRelationship relationship : objectEntity.getRelationships()) { + if (compositeEntity.hasRelationshipNamed(relationship.getName())) { + //ECLog.logWarning("We have already copied relationship: " + relationship); + continue; + } + MTEntity toEntity = relationship.getTo().getEntity(); + // don't take relationships to version + if (versionEntity != null && toEntity.getName().equals(versionEntity.getName())) { + continue; + } + if (!compositeEntityConstituentMap.containsKey(toEntity.getName())) { + // we can copy the relationship exactly - just have to fix the "from" which is done + // in the Copy method. + MTRelationship newRelationship = MTRelationship.Copy(relationship, compositeEntity, null); + //ECLog.logInfo("---- Adding Composite Object Relationship to non-composite entity: " + newRelationship); + compositeEntity.addRelationship(newRelationship); + relationshipsToResolve.add(newRelationship); + continue; + } + MTCompositeEntity toCompositeEntity = compositeEntityConstituentMap.get(toEntity.getName()); + MTRelationship newRelationship = MTRelationship.Copy(relationship, compositeEntity, toCompositeEntity); + compositeEntity.addRelationship(newRelationship); + relationshipsToResolve.add(newRelationship); + //ECLog.logInfo("Adding Composite Object Relationship to Composite object: " + newRelationship); + } + if (versionEntity != null) { + //ECLog.logInfo("Entity " + compositeEntity.getName() + " has Version entity " + versionEntity.getName() + " has " + versionEntity.getRelationshipCount() + " relationships."); + for (MTRelationship relationship : versionEntity.getRelationships()) { + MTEntity toEntity = relationship.getTo().getEntity(); + if (toEntity == null) { + ECLog.logWarning("Relationship " + versionEntity.getName() + "." + relationship.getName() + " does NOT have a \"to\" entity!"); + continue; + } + // don't take relationships to object parent + if (relationship.isParent() && toEntity.getName().equals(objectEntity.getName())) { + continue; + } + if (!compositeEntityConstituentMap.containsKey(toEntity.getName())) { + // we can copy the relationship exactly - just have to fix the "from" which is done + // in the Copy method. + MTRelationship newRelationship = MTRelationship.Copy(relationship, compositeEntity, null); + //ECLog.logInfo("Adding Composite Version Relationship to non-composite entity: " + newRelationship.getName()); + compositeEntity.addRelationship(newRelationship); + relationshipsToResolve.add(newRelationship); + continue; + } + MTCompositeEntity toCompositeEntity = compositeEntityConstituentMap.get(toEntity.getName()); + MTRelationship newRelationship = MTRelationship.Copy(relationship, compositeEntity, toCompositeEntity); + //ECLog.logInfo("Adding Composite Version Relationship to Composite object: " + newRelationship); + compositeEntity.addRelationship(newRelationship); + relationshipsToResolve.add(newRelationship); + } + } + compositeEntity.getModule().addEntity(compositeEntity); + space.addEntity(compositeEntity); + } + + // ------------------------------------------------ + // It turns out that for any entity related to a + // Released entity we also need to create a Released + // version of it so it. + // ------------------------------------------------ + + for (MTRelationship relationship : relationshipsToResolve) { + relationship.resolveReferences(space, 3); + if (relationship.getTo().getEntity() == null) { + ECLog.logFatal("Why cant we resolve this relationship?: " + relationship.getName()); + } + else { + //ECLog.logInfo("Newly created relationship is resolved: " + relationship.getFrom().getEntityName() + "." + relationship.getName()); + } + } // for (MTModule module : space.getModules()) { // // if (module.isIncluded()) { diff --git a/test/java/org/entityc/compiler/EntityCompilerTest.java b/test/java/org/entityc/compiler/EntityCompilerTest.java index 49b12b0..86238ef 100644 --- a/test/java/org/entityc/compiler/EntityCompilerTest.java +++ b/test/java/org/entityc/compiler/EntityCompilerTest.java @@ -24,6 +24,12 @@ void compileBasicEntity() throws IOException { runTemplateTest(TestName); } + @Test + void compileReleasedTransform() throws IOException { + final String TestName = "ReleasedTransform"; + runTemplateTest(TestName); + } + private void runTemplateTest(String testName) throws IOException { final String TestResourceDir = BASE_RESOURCE_DIR + "/" + testName; String strTmp = System.getProperty("java.io.tmpdir"); diff --git a/test/resources/compiler/main/CompilerDocs/CompilerDocsExpected.txt b/test/resources/compiler/main/CompilerDocs/CompilerDocsExpected.txt index e878dc4..601e395 100644 --- a/test/resources/compiler/main/CompilerDocs/CompilerDocsExpected.txt +++ b/test/resources/compiler/main/CompilerDocs/CompilerDocsExpected.txt @@ -374,6 +374,9 @@ These methods relate to a part of application configuration. | `boolean` [**`hasMetadataValue(String name)`**](#class_MTSpace_hasMetadataValue) | | Indicates whether this space has a metadata name/value for the specified name. | |
| +| `boolean` [**`hasRealmWithName(String realm)`**](#class_MTSpace_hasRealmWithName) | +| Returns true if there is a realm by this name. | +|
| | `List` **`importEntityNames`** | | Returns the names of the entities that have been imported into this space. | |
| @@ -383,6 +386,9 @@ These methods relate to a part of application configuration. | `Object` [**`metadataValue(String name)`**](#class_MTSpace_metadataValue) | | Spaces can define a dictionary of name/value pairs that provide some meta data about the space and basically the application. This method allows you to get a value by its name. | |
| +| `MTRealm` [**`realmWithName(String realm)`**](#class_MTSpace_realmWithName) | +| Returns the realm object by its name. | +|
| | `MTRepository` [**`repository(String name)`**](#class_MTSpace_repository) | | Returns the repository object by its name. | |
| @@ -399,6 +405,16 @@ Indicates whether this space has a metadata name/value for the specified name. |-----|-----| |`String name` | The name of the metadata value to return. | + +#### Method `boolean hasRealmWithName(String realm)` + + +Returns true if there is a realm by this name. + +| Parameter | Description | +|-----|-----| +|`String realm` | *no description* | + @@ -411,6 +427,16 @@ Spaces can define a dictionary of name/value pairs that provide some meta data a |-----|-----| |`String name` | The name of the meta data. | + +#### Method `MTRealm realmWithName(String realm)` + + +Returns the realm object by its name. + +| Parameter | Description | +|-----|-----| +|`String realm` | *no description* | + #### Method `MTRepository repository(String name)` @@ -729,6 +755,12 @@ These methods relate to an entity. | Method/Property | |---| +| `void` [**`addRealm(String realm)`**](#class_MTEntity_addRealm) | +| Adds the entity to a realm. | +|
| +| `boolean` **`isCompositeEntity`** | +| Returns true if this entity is a composite entity. | +|
| | `boolean` **`isDeclaredAsPrimary`** | | Indicates whether this entity was **declared** `primary`. If the entity was **not** declared with the `primary` keyword then this will return false even if it is implied as primary. | |
| @@ -741,6 +773,9 @@ These methods relate to an entity. | `boolean` **`isImplicit`** | | Indicates whether this entity was created by the compiler because it represents an implicit entity, such as in a many-to-many relationship. | |
| +| `boolean` [**`isInRealm(String realm)`**](#class_MTEntity_isInRealm) | +| Returns true if this entity is part of a realm. | +|
| | `boolean` **`isPrimary`** | | Indicates whether this entity was declared `primary` or if it was inferred as primary. If an entity has a primary key it is inferred to be a primary entity. | |
| @@ -759,6 +794,37 @@ These methods relate to an entity. | `MTSpace` **`space`** | | Returns the space in which this entity was declared. | + +#### Method `void addRealm(String realm)` + + +Adds the entity to a realm. + +| Parameter | Description | +|-----|-----| +|`String realm` | *no description* | + + + + + + + +#### Method `boolean isInRealm(String realm)` + + +Returns true if this entity is part of a realm. + +| Parameter | Description | +|-----|-----| +|`String realm` | *no description* | + + + + + + + ### Entity Template Category These methods relate to entity templates. @@ -848,6 +914,9 @@ These methods relate to attributes. |
| | `boolean` **`hasBitFields`** | | Indicates whether this entity defines any bit fields. | +|
| +| `MTRelationship` [**`relationshipNamed(String name)`**](#class_MTEntity_relationshipNamed) | +| Returns an relationship of this entity with the specified name. | #### Method `MTAttribute attributeByFullName(String fullName)` @@ -916,6 +985,16 @@ Indicates whether any of the attributes of this entity are of the specified data + +#### Method `MTRelationship relationshipNamed(String name)` + + +Returns an relationship of this entity with the specified name. + +| Parameter | Description | +|-----|-----| +|`String name` | The name of the relationship to return. | + ### Relationship Category These methods relate to relationships. @@ -949,6 +1028,9 @@ These methods relate to relationships. | `boolean` **`hasPrimaryParentRelationship`** | | Indicates whether this entity has a primary parent relationship. A primary parent relationship is one which is declared `parent` and **not** declared `optional`. | |
| +| `boolean` [**`hasRelationshipNamed(String name)`**](#class_MTEntity_hasRelationshipNamed) | +| Indicates whether this entity has an relationship with the specified name. | +|
| | `boolean` **`hasRelationships`** | | Indicates whether this entity defines any relationships. | |
| @@ -973,6 +1055,9 @@ These methods relate to relationships. | `int` **`relationshipCount`** | | Returns the number of declared relationships. | |
| +| `MTRelationship` [**`relationshipWithToEntity(MTEntity toEntity)`**](#class_MTEntity_relationshipWithToEntity) | +| Returns the first relationships from this entity to a specified entity. This method should be used when only one is expected. | +|
| | `List` **`relationships`** | | Returns the list of relationships of this entity. | |
| @@ -1039,6 +1124,16 @@ Indicates whether it has a least one relationship declared as parent to the spec |`MTEntity parentEntity` | *no description* | + +#### Method `boolean hasRelationshipNamed(String name)` + + +Indicates whether this entity has an relationship with the specified name. + +| Parameter | Description | +|-----|-----| +|`String name` | *no description* | + @@ -1065,6 +1160,16 @@ Returns a relationship of this entity by name. If a relationship is not found wi |`String relationshipName` | The name of the relationship to return. | + +#### Method `MTRelationship relationshipWithToEntity(MTEntity toEntity)` + + +Returns the first relationships from this entity to a specified entity. This method should be used when only one is expected. + +| Parameter | Description | +|-----|-----| +|`MTEntity toEntity` | The entity that the relationships are **to**. | + #### Method `List relationshipsWithToEntity(MTEntity toEntity)` @@ -1131,6 +1236,9 @@ These methods relate to the tagging. | `boolean` [**`hasRelationshipTagged(String tag)`**](#class_MTEntity_hasRelationshipTagged) | | Indicates whether this entity has at least one relationship with the specified tag. | |
| +| `boolean` [**`hasRelationshipToEntityNamed(String toEntityName)`**](#class_MTEntity_hasRelationshipToEntityNamed) | +| Indicates whether this entity has at least one relationship to a named other entity. | +|
| | `boolean` [**`hasRelationshipToEntityTagged(String tag)`**](#class_MTEntity_hasRelationshipToEntityTagged) | | Indicates whether the entity **to** which a relationship references is tagged with the specified tag. | |
| @@ -1190,6 +1298,16 @@ Indicates whether this entity has at least one relationship with the specified t |-----|-----| |`String tag` | The tag with which to search. | +
+#### Method `boolean hasRelationshipToEntityNamed(String toEntityName)` + + +Indicates whether this entity has at least one relationship to a named other entity. + +| Parameter | Description | +|-----|-----| +|`String toEntityName` | The name of the other entity. | + #### Method `boolean hasRelationshipToEntityTagged(String tag)` @@ -1262,6 +1380,9 @@ These methods relate to enums. | `boolean` **`isExtern`** | | Indicates whether this was declared as `extern`. | |
| +| `MTEnumItem` [**`item(Long index)`**](#class_MTEnum_item) | +| Returns an item by its index. | +|
| | `List` **`items`** | | Gets the enum items. | |
| @@ -1271,6 +1392,22 @@ These methods relate to enums. | `String` **`name`** | | Gets the name of this enum. | + + + + +#### Method `MTEnumItem item(Long index)` + + +Returns an item by its index. + +| Parameter | Description | +|-----|-----| +|`Long index` | *no description* | + + + + ### Tagging Category These methods relate to the tagging. @@ -1572,6 +1709,9 @@ These methods relate to relationships. | `MTRelationshipHalf` **`from`** | | Returns the "from" part of the relationship which references the entity in which this relationship is defined. | |
| +| `MTEntity` **`implicitToEntity`** | +| Gets the entity on the other side of an implicit many-to-many entity. | +|
| | `boolean` **`isImplicit`** | | Indicates whether the relationship was created because although it was not declared it can be implied based on relationships declared to this entity. | |
| @@ -1651,6 +1791,9 @@ These methods relate to data types. | `boolean` **`isByteArrayType`** | | Indicates whether this type is both an array type and also `byte` data type. | |
| +| `boolean` **`isDataType`** | +| Indicates whether this type is the `data` data type. | +|
| | `boolean` **`isDateType`** | | Indicates whether this type is the `date` data type. | |
| @@ -1683,6 +1826,7 @@ These methods relate to data types. + #### Method `boolean isNativeDataType(DataType dataType)` @@ -1764,6 +1908,7 @@ Model classes that are domain specific are of this type. The classes are briefly |[`MTDEAttribute`](#class_MTDEAttribute)|Represents an attribute in your model in the context of a domain.| |[`MTDEAttributeConstraintExpression`](#class_MTDEAttributeConstraintExpression)|Represents a constraint on an attribute in the form of an expression.| |[`MTDERelationship`](#class_MTDERelationship)|Represents a relationship in your model in the context of a domain.| +|[`MTDERelationshipField`](#class_MTDERelationshipField)|Represents a field (attribute or relationship) associated with the __to__ entity of the relationship.| |[`MTDEntity`](#class_MTDEntity)|Represents an entity in your model in the context of a domain.| |[`MTDEnum`](#class_MTDEnum)|Represents an enum in the context of a domain.| |[`MTDEnumItem`](#class_MTDEnumItem)|Represents an enum item in the context of a domain.| @@ -1957,6 +2102,9 @@ These methods relate to relationships. | `String` **`explicitName`** | | If this relationship was explicitly renamed within its domain, it will return that name. Otherwise it will return `null`. | |
| +| `Collection` **`fields`** | +| Returns all the declared fields of this relationship. | +|
| | `String` [**`fullname(String delim)`**](#class_MTDERelationship_fullname) | | This returns the full name of this domain relationship which includes not only its domain based name but is also preceded with the domain's entity's full name. The delimiter can be provided which is used between all parts of the full name. | |
| @@ -1992,6 +2140,7 @@ These methods relate to relationships. + #### Method `String fullname(String delim)` @@ -2032,6 +2181,15 @@ Returns whether this relationship's "to" entity is tagged with the specified tag |`String tag` | The tag with which to check. | + +## MTDERelationshipField Class + + +Represents a field (attribute or relationship) associated with the __to__ entity of the relationship. + +This class has the following methods broken up into categories: + + ## MTDEntity Class @@ -2235,6 +2393,12 @@ These methods relate to relationships. | `MTDERelationship` [**`domainEntityRelationshipByName(String name, boolean createIfNeeded)`**](#class_MTDEntity_domainEntityRelationshipByName) | | Returns the domain specific version of the specified relationship. | |
| +| `boolean` **`hasDeclaredDomainRelationships`** | +| Indicates if any relationships were declared in this domain entity declaration. | +|
| +| `boolean` **`hasParentRelationship`** | +| Indicates whether this domain entity has a parent relationship. A parent relationship is one that has been declared as `parent` | +|
| | `boolean` **`hasPrimaryParentRelationship`** | | Indicates whether this domain entity has a primary parent relationship. A primary parent relationship is one that has been declared as `parent` and **not** declared `optional`. | |
| @@ -2263,6 +2427,8 @@ Returns the domain specific version of the specified relationship. + + ### Tagging Category These methods relate to the tagging. @@ -2706,6 +2872,7 @@ The model classes of this type are intended to provide support for foundation ty | Class | Description | |-----|-----| |[`MFArray`](#class_MFArray)|This class represents a ordered array of objects. To create an empty array you can use: `$[let myList = @[]@]` then can use these methods on that variable (`myList` in this example) to access the array functionality that is exposed here.| +|[`MFMap`](#class_MFMap)|This class represents a map of objects. To create an empty map you can use: `$[let myMap = @{}@]` then can use these methods on that variable (`myMap` in this example) to access the map functionality that is exposed here.| |[`MFSet`](#class_MFSet)|This class represents a unique set of objects. You cannot create an object of this class in template code, however, some classes have methods that will return such an object. Since this class does not offer methods to manipulate the object, it should be considered immutable. You can iterate through the items in a set using the `foreach` instruction. For example: `$[foreach item in mySet] ... $[/foreach]` would allow you to process each item(object) in the set.| @@ -2743,6 +2910,9 @@ These methods don't really have a category. | `Object` **`first`** | | Returns the first item in the array. | |
| +| `Object` [**`get(Integer index)`**](#class_MFArray_get) | +| Returns the specified item by its index into the array. | +|
| | `Object` [**`get(Long index)`**](#class_MFArray_get) | | Returns the specified item by its index into the array. | |
| @@ -2795,6 +2965,16 @@ Indicates if the array contains the specified object. +
+#### Method `Object get(Integer index)` + + +Returns the specified item by its index into the array. + +| Parameter | Description | +|-----|-----| +|`Integer index` | The index into the array that points to the item to be returned. | + #### Method `Object get(Long index)` @@ -2829,6 +3009,138 @@ Allows you to remove a specified object from the array. This method returns the + +## MFMap Class + + +This class represents a map of objects. To create an empty map you can use: `$[let myMap = @{}@]` then can use these methods on that variable (`myMap` in this example) to access the map functionality that is exposed here. + +This class has the following methods broken up into categories: + +### Other Category + +These methods don't really have a category. + +| Method/Property | +|---| +| `MFMap` **`clear`** | +| This method removes all items in the map. | +|
| +| `boolean` [**`containsKey(Object key)`**](#class_MFMap_containsKey) | +| Indicates if the map contains the specified key. | +|
| +| `boolean` [**`containsValue(Object value)`**](#class_MFMap_containsValue) | +| Indicates if the map contains the specified value. | +|
| +| `MFMap` **`copy`** | +| Allows you to make a copy of this map. Since it returns the new map you can chain other map methods after this one. | +|
| +| `int` **`count`** | +| Returns the number of items in the map. | +|
| +| `Object` [**`get(Object key)`**](#class_MFMap_get) | +| Returns the value in the map by its specified key. | +|
| +| `boolean` **`isEmpty`** | +| Indicates if the map is empty (no items). | +|
| +| `Collection` **`keys`** | +| Returns all the keys of the map | +|
| +| `MFMap` [**`put(Object key, Object o)`**](#class_MFMap_put) | +| Allows you to add an object to this array. The `do` template instruction can be used to do this (e.g., `$[do array.add(obj)]`. This method returns the array itself so you can chain other array methods after this one. | +|
| +| `MFMap` [**`putAll(MFMap otherMap)`**](#class_MFMap_putAll) | +| Allows you to add all elements of another map to this map. The `do` template instruction can be used to do this (e.g., `$[do map.putAll(otherMap)]`. This method returns the map itself so you can chain other map methods after this one. | +|
| +| `MFMap` [**`remove(Object key)`**](#class_MFMap_remove) | +| Allows you to remove a specified entry from the map based on its key. This method returns the map itself so you can chain other map methods after this one. | +|
| +| `MFMap` [**`remove(Object key, Object o)`**](#class_MFMap_remove) | +| Allows you to remove a specified object from the map based on its key. This method returns the map itself so you can chain other map methods after this one. | +|
| +| `Collection` **`values`** | +| Returns all the values of the map. When iterating this array of values with a `foreach` you do **not** need to use this method. | + + + +#### Method `boolean containsKey(Object key)` + + +Indicates if the map contains the specified key. + +| Parameter | Description | +|-----|-----| +|`Object key` | The key of which to determine its presence in the map. | + + +#### Method `boolean containsValue(Object value)` + + +Indicates if the map contains the specified value. + +| Parameter | Description | +|-----|-----| +|`Object value` | The object of which to determine its presence in the map. | + + + + +#### Method `Object get(Object key)` + + +Returns the value in the map by its specified key. + +| Parameter | Description | +|-----|-----| +|`Object key` | The key. | + + + + +#### Method `MFMap put(Object key, Object o)` + + +Allows you to add an object to this array. The `do` template instruction can be used to do this (e.g., `$[do array.add(obj)]`. This method returns the array itself so you can chain other array methods after this one. + +| Parameter | Description | +|-----|-----| +|`Object key` | The key to put to the map. | +|`Object o` | The object to set to the map. | + + +#### Method `MFMap putAll(MFMap otherMap)` + + +Allows you to add all elements of another map to this map. The `do` template instruction can be used to do this (e.g., `$[do map.putAll(otherMap)]`. This method returns the map itself so you can chain other map methods after this one. + +| Parameter | Description | +|-----|-----| +|`MFMap otherMap` | The other map to add to this map. | + + +#### Method `MFMap remove(Object key)` + + +Allows you to remove a specified entry from the map based on its key. This method returns the map itself so you can chain other map methods after this one. + +| Parameter | Description | +|-----|-----| +|`Object key` | The key to remove from this map. | + + +#### Method `MFMap remove(Object key, Object o)` + + +Allows you to remove a specified object from the map based on its key. This method returns the map itself so you can chain other map methods after this one. + +| Parameter | Description | +|-----|-----| +|`Object key` | The key to remove from this map. | +|`Object o` | The object to remove from this map. | + + + ## MFSet Class diff --git a/test/resources/compiler/main/ReleasedTransform/ReleasedTemplate.eml b/test/resources/compiler/main/ReleasedTransform/ReleasedTemplate.eml new file mode 100644 index 0000000..84c2d01 --- /dev/null +++ b/test/resources/compiler/main/ReleasedTransform/ReleasedTemplate.eml @@ -0,0 +1,73 @@ +$[* + The purpose of this template is to test that the ReleasedTransform worked correctly. +*] +$[ function CheckIfReleasedEntity + (entity + )-> + (isReleasedEntity + ) ] + $[ let isReleasedEntity = entity.isCompositeEntity && entity.isInRealm("Released") ] +$[/ function ] +$[ function GetReleaseEntityPKAttribute + (entity + )-> + (releaseEntityPKAttribute + ) ] + $[ let isReleasedEntity = entity.isCompositeEntity && entity.isInRealm("Released") ] + $[ if !isReleasedEntity ] + $[ return ] + $[/ if ] + $[ let releaseEntity = entity.getAnyConstituentEntity("release") ] + $[ if releaseEntity != null ] + $[ let releaseEntityPKAttribute = releaseEntity.primaryKeyAttribute ] + $[/ if ] +$[/ function ] +$[ function GetRelationshipToReleaseEntity + (entity + )-> + (relationship + ) ] + $[ let isReleasedEntity = entity.isCompositeEntity && entity.isInRealm("Released") ] + $[ if !isReleasedEntity ] + $[ return ] + $[/ if ] + $[ let releaseEntity = entity.getAnyConstituentEntity("release") ] + $[ let relationship = null ] + $[ if releaseEntity != null ] + $[ if entity.hasRelationshipToEntityNamed(releaseEntity.name) ] + $[ let relationship = entity.getRelationshipWithToEntity(releaseEntity) ] + $[/ if ] + $[/ if ] +$[/ function ] +$[ file "" "ReleasedTransform" "txt" ] + + $[ foreach entity in space.entities ] + $[ call CheckIfReleasedEntity(entity: entity)->(isReleasedEntity: isReleasedEntity) ] + $[ if !isReleasedEntity ] + $[ continue ] + $[/ if ] +entity ${entity.name} { + + D "${entity.description}" + + primarykey ${entity.primaryKeyAttribute.type} ${entity.primaryKeyAttribute.name} { + D "${entity.primaryKeyAttribute.description}" + } + + attributes { + $[ foreach attribute in entity.attributes ] + ${attribute.type} ${attribute.name} { D "${attribute.description}" } + $[/ foreach ] + } + + relationships { + $[ foreach relationship in entity.relationships ] + ${relationship.to.plurality} ${relationship.to.entity.name} ${relationship.name} { + D "${relationship.description}" + } + $[/ foreach ] + } +} + + $[/ foreach ] +$[/ file ] diff --git a/test/resources/compiler/main/ReleasedTransform/ReleasedTransform.edl b/test/resources/compiler/main/ReleasedTransform/ReleasedTransform.edl new file mode 100644 index 0000000..d069e8c --- /dev/null +++ b/test/resources/compiler/main/ReleasedTransform/ReleasedTransform.edl @@ -0,0 +1,124 @@ +space RevisionedStuff { + + +} + +module Everything +{ + +entity WidgetType { + primarykey uuid widgetTypeId + + attributes { + string identifier + string title + optional string description + } + relationships { + many Widget widgets + } +} + +entity ProductRelease { + primarykey uuid productReleaseId + + T "release:binder" + + relationships { + parent one ProductLineRelease productLineRelease + one O + one V + } +} + +entity ProductLineRelease { + primarykey uuid productLineReleaseId + T "release:top" + + attributes { + string identifier + string notes + } + relationships { + many ProductRelease as WidgetRevisionRelease {} + many ProductRelease as ThingRevisionRelease {} + } +} + +entity Widget { + primarykey uuid widgetId + + T "release:object" + + attributes { + string identifier + string title + optional string description + } + relationships { + many WidgetRevision revisions + parent one WidgetType type + } +} + +entity WidgetRevision { + primarykey uuid widgetRevisionId + + T "release:version" + + attributes { + sequential int64 number + optional string notes + } + relationships { + parent one Widget widget + } +} + +entity Thing { + primarykey uuid thingId + + T "release:object" + + attributes { + string identifier + string title + optional string description + } + relationships { + many ThingRevision revisions + parent one Widget widget + } +} + +entity ThingRevision { + primarykey uuid thingRevisionId + + T "release:version" + + attributes { + sequential int64 number + optional string notes + } + relationships { + parent one Thing thing + } +} +} + +configuration Config +{ + output testOutput { + path $(TEMP_DIR:"/tmp") + } + + transform Released { + } + + templates { + template ReleasedTemplate { + output primary testOutput + } + } +} + diff --git a/test/resources/compiler/main/ReleasedTransform/ReleasedTransformExpected.txt b/test/resources/compiler/main/ReleasedTransform/ReleasedTransformExpected.txt new file mode 100644 index 0000000..102c1c9 --- /dev/null +++ b/test/resources/compiler/main/ReleasedTransform/ReleasedTransformExpected.txt @@ -0,0 +1,77 @@ + +entity ReleasedThing { + + D "" + + primarykey uuid thingId { + D "" + } + + attributes { + string identifier { D "" } + string title { D "" } + string description { D "" } + int64 number { D "" } + string notes { D "" } + } + + relationships { + ONE ProductLineRelease productLineRelease { + D "" + } + ONE ReleasedWidget widget { + D "" + } + } +} + +entity ReleasedWidget { + + D "" + + primarykey uuid widgetId { + D "" + } + + attributes { + string identifier { D "" } + string title { D "" } + string description { D "" } + int64 number { D "" } + string notes { D "" } + } + + relationships { + ONE ProductLineRelease productLineRelease { + D "" + } + ONE ReleasedWidgetType type { + D "" + } + } +} + +entity ReleasedWidgetType { + + D "" + + primarykey uuid widgetTypeId { + D "" + } + + attributes { + string identifier { D "" } + string title { D "" } + string description { D "" } + } + + relationships { + ONE ProductLineRelease productLineRelease { + D "" + } + MANY ReleasedWidget widgets { + D "" + } + } +} + From 8f5451bfc5bc94461304fba1e412a8149507e14c Mon Sep 17 00:00:00 2001 From: Bob Garner Date: Sun, 17 Dec 2023 04:34:44 -0800 Subject: [PATCH 11/12] Added methods to entity and domain entity that can be useful for templates. --- .../entityc/compiler/model/domain/MTDEntity.java | 10 ++++++++-- .../compiler/model/entity/MTCompositeEntity.java | 2 ++ .../entityc/compiler/model/entity/MTEntity.java | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/entityc/compiler/model/domain/MTDEntity.java b/src/main/java/org/entityc/compiler/model/domain/MTDEntity.java index 49c4f7f..b0e9c1c 100644 --- a/src/main/java/org/entityc/compiler/model/domain/MTDEntity.java +++ b/src/main/java/org/entityc/compiler/model/domain/MTDEntity.java @@ -363,8 +363,14 @@ public MTDEAttribute getDomainAttributeByName( return domainAttribute; } - @ModelMethod(category = ModelMethodCategory.RELATIONSHIP, - description = "Returns the domain specific version of the specified relationship.") + @ModelMethod(category = ModelMethodCategory.ATTRIBUTE, + description = "Returns the domain specific version of the specified attribute.") + public MTDEAttribute getDomainAttributeByName( + @ModelMethodParameter(description = "The name of the attribute to return.") + String attributeName) { + return getDomainAttributeByName(attributeName, false); + } + public MTDERelationship getDomainEntityRelationshipByName( @ModelMethodParameter(description = "The name of the relationship to return.") String name, diff --git a/src/main/java/org/entityc/compiler/model/entity/MTCompositeEntity.java b/src/main/java/org/entityc/compiler/model/entity/MTCompositeEntity.java index 4c65160..47c2508 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTCompositeEntity.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTCompositeEntity.java @@ -1,6 +1,7 @@ package org.entityc.compiler.model.entity; import org.antlr.v4.runtime.ParserRuleContext; +import org.entityc.compiler.doc.annotation.*; import org.entityc.compiler.model.MTModule; import org.entityc.compiler.util.ECLog; @@ -8,6 +9,7 @@ import java.util.HashSet; import java.util.Map; +@ModelClass(type = ModelClassType.ENTITY, description = "Represents a composite entity in your model.") public class MTCompositeEntity extends MTEntity { public static final String ObjectTag = "object"; diff --git a/src/main/java/org/entityc/compiler/model/entity/MTEntity.java b/src/main/java/org/entityc/compiler/model/entity/MTEntity.java index cdf0fc1..0eb9439 100644 --- a/src/main/java/org/entityc/compiler/model/entity/MTEntity.java +++ b/src/main/java/org/entityc/compiler/model/entity/MTEntity.java @@ -866,6 +866,21 @@ public MTRelationship getRelationshipWithToEntity( return null; } + @ModelMethod( + category = ModelMethodCategory.RELATIONSHIP, + description = "Returns the first relationships from this entity to a specified entity by its name. This method should be used when only one is expected.") + public MTRelationship getRelationshipWithToEntityNamed( + @ModelMethodParameter(description = "The entity that the relationships are **to**.") + String toEntityName) { + List matchingRelationships = new ArrayList<>(); + for (MTRelationship relationship : relationships) { + if (relationship.getTo().getEntityName().equals(toEntityName)) { + return relationship; + } + } + return null; + } + @ModelMethod( category = ModelMethodCategory.RELATIONSHIP, description = From de170b3fb192493085bb45e5550e4d660c0abf91 Mon Sep 17 00:00:00 2001 From: Bob Garner Date: Sun, 17 Dec 2023 04:45:34 -0800 Subject: [PATCH 12/12] Fixed documentation strings. --- .../transform/template/tree/filter/FTNameAsFilter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTNameAsFilter.java b/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTNameAsFilter.java index 4da6eb7..4461bc1 100644 --- a/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTNameAsFilter.java +++ b/src/main/java/org/entityc/compiler/transform/template/tree/filter/FTNameAsFilter.java @@ -21,10 +21,10 @@ public class FTNameAsFilter extends FTFilter { public FTNameAsFilter() { super(null, "nameas", - "Places underscore between words then forces all characters to be lowercase."); + "Changes the input string (considered a \"name\" because it is using camel case) to another string based on the specified method."); this.addFilterParam(new FTFilterParam("method", "Specifies the naming method: " + String.join(", ", Arrays.stream(MTNamingMethod.values()).map(MTNamingMethod::getName).toArray(String[]::new)))); - addSingleInputType(String.class, "The string to change into an underscore lowercase format."); + addSingleInputType(String.class, "The camel case name string to change."); } @Override @@ -44,7 +44,7 @@ public Object filter(ParserRuleContext ctx, FTTransformSession session, Object i } else { - ECLog.logFatal(ctx, "Naming method must be specified directly. For example: entity|nameas:uppercase"); + ECLog.logFatal(ctx, "Naming method must be specified directly. For example: entity.name|nameas:uppercase"); } MTNamingMethod namingMethod = MTNamingMethod.fromName(methodName); if (namingMethod == null) {