Skip to content

Generate SQL table creation script for Aspect Models #585

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jun 3, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Set;

import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@ protected void writeCharSequenceToOutputStream( final CharSequence charSequence,
writer.flush();
}
}

public static final String SAMM_EXTENSION = "x-samm-aspect-model-urn";
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import java.util.function.Function;
import java.util.stream.Collectors;

import org.eclipse.esmf.aspectmodel.generator.jsonschema.AspectModelJsonSchemaVisitor;
import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;

import com.fasterxml.jackson.core.JsonProcessingException;
Expand Down Expand Up @@ -125,14 +124,14 @@ private JsonNode updateRefValues( final JsonNode node, final Map<String, String>
protected Map<Path, JsonNode> getContentWithSeparateSchemasAsJson( final Optional<String> mainSpec ) {
final JsonNode jsonContent = getContent();
final String aspectName = AspectModelUrn.fromUrn(
jsonContent.get( "info" ).get( AspectModelJsonSchemaVisitor.SAMM_EXTENSION ).asText() ).getName();
jsonContent.get( "info" ).get( AbstractGenerator.SAMM_EXTENSION ).asText() ).getName();
return getSeparateSchemas( aspectName, "json", mainSpec );
}

protected Map<Path, String> getContentWithSeparateSchemasAsYaml( final Optional<String> mainSpec ) {
final JsonNode jsonContent = getContent();
final String aspectName = AspectModelUrn.fromUrn(
jsonContent.get( "info" ).get( AspectModelJsonSchemaVisitor.SAMM_EXTENSION ).asText() ).getName();
jsonContent.get( "info" ).get( AbstractGenerator.SAMM_EXTENSION ).asText() ).getName();
return getSeparateSchemas( aspectName, "yaml", mainSpec ).entrySet().stream().collect( Collectors.toMap(
Map.Entry::getKey, entry -> jsonToYaml( entry.getValue() ) ) );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
import java.util.Locale;

import org.eclipse.esmf.aspectmodel.VersionNumber;
import org.eclipse.esmf.aspectmodel.generator.AbstractGenerator;
import org.eclipse.esmf.aspectmodel.generator.ArtifactGenerator;
import org.eclipse.esmf.aspectmodel.generator.XsdToJsonTypeMapping;
import org.eclipse.esmf.aspectmodel.generator.jsonschema.AspectModelJsonSchemaVisitor;
import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;
import org.eclipse.esmf.metamodel.Aspect;
import org.eclipse.esmf.metamodel.Event;
Expand Down Expand Up @@ -59,7 +59,7 @@ public AsyncApiSchemaArtifact apply( final Aspect aspect, final AsyncApiSchemaGe
info.put( TITLE_FIELD, aspect.getPreferredName( config.locale() ) + " MQTT API" );
info.put( "version", apiVersion );
info.put( DESCRIPTION_FIELD, getDescription( aspect.getDescription( config.locale() ) ) );
info.put( AspectModelJsonSchemaVisitor.SAMM_EXTENSION,
info.put( AbstractGenerator.SAMM_EXTENSION,
aspect.getAspectModelUrn().map( AspectModelUrn::toString ).orElseThrow() );

rootNode.set( "channels", getChannelNode( aspect, config ) );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.stream.IntStream;
import java.util.stream.Stream;

import org.eclipse.esmf.aspectmodel.generator.AbstractGenerator;
import org.eclipse.esmf.aspectmodel.generator.DocumentGenerationException;
import org.eclipse.esmf.aspectmodel.generator.XsdToJsonTypeMapping;
import org.eclipse.esmf.aspectmodel.resolver.services.SammDataType;
Expand Down Expand Up @@ -77,7 +78,6 @@
import org.apache.jena.vocabulary.XSD;

public class AspectModelJsonSchemaVisitor implements AspectVisitor<JsonNode, ObjectNode> {
public static final String SAMM_EXTENSION = "x-samm-aspect-model-urn";
private static final JsonNodeFactory FACTORY = JsonNodeFactory.instance;
private final List<Property> processedProperties = new LinkedList<>();
private final BiMap<NamedElement, String> schemaNameForElement = HashBiMap.create();
Expand Down Expand Up @@ -667,6 +667,6 @@ private ObjectNode addDescription( final ObjectNode node, final NamedElement des
}

private void addSammExtensionAttribute( final ObjectNode node, final NamedElement describedElement ) {
describedElement.getAspectModelUrn().ifPresent( urn -> node.put( SAMM_EXTENSION, urn.toString() ) );
describedElement.getAspectModelUrn().ifPresent( urn -> node.put( AbstractGenerator.SAMM_EXTENSION, urn.toString() ) );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.eclipse.esmf.aspectmodel.generator.AbstractGenerator;
import org.eclipse.esmf.aspectmodel.generator.ArtifactGenerator;
import org.eclipse.esmf.aspectmodel.generator.jsonschema.AspectModelJsonSchemaGenerator;
import org.eclipse.esmf.aspectmodel.generator.jsonschema.AspectModelJsonSchemaVisitor;
Expand Down Expand Up @@ -123,7 +124,7 @@ public OpenApiSchemaArtifact apply( final Aspect aspect, final OpenApiSchemaGene

((ObjectNode) rootNode.get( "info" )).put( "title", aspect.getPreferredName( config.locale() ) );
((ObjectNode) rootNode.get( "info" )).put( "version", apiVersion );
((ObjectNode) rootNode.get( "info" )).put( AspectModelJsonSchemaVisitor.SAMM_EXTENSION,
((ObjectNode) rootNode.get( "info" )).put( AbstractGenerator.SAMM_EXTENSION,
aspect.getAspectModelUrn().map( Object::toString ).orElse( "" ) );
setServers( rootNode, config.baseUrl(), apiVersion, READ_SERVER_PATH );
final boolean includePaging = includePaging( aspect, config.pagingOption() );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH
*
* See the AUTHORS file(s) distributed with this work for additional
* information regarding authorship.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* SPDX-License-Identifier: MPL-2.0
*/

package org.eclipse.esmf.aspectmodel.generator.sql;

import org.eclipse.esmf.aspectmodel.generator.ArtifactGenerator;
import org.eclipse.esmf.aspectmodel.generator.sql.databricks.AspectModelDatabricksDenormalizedSqlVisitor;
import org.eclipse.esmf.aspectmodel.generator.sql.databricks.AspectModelDatabricksDenormalizedSqlVisitorContextBuilder;
import org.eclipse.esmf.aspectmodel.generator.sql.databricks.DatabricksSqlGenerationConfig;
import org.eclipse.esmf.metamodel.Aspect;

/**
* Generates SQL scripts from an Aspect Model that set up tables to contain the data of the Aspect.
*/
public class AspectModelSqlGenerator implements ArtifactGenerator<String, String, Aspect, SqlGenerationConfig, SqlArtifact> {
public static final AspectModelSqlGenerator INSTANCE = new AspectModelSqlGenerator();

private AspectModelSqlGenerator() {
}

@Override
public SqlArtifact apply( final Aspect aspect, final SqlGenerationConfig sqlGenerationConfig ) {
final String content = switch ( sqlGenerationConfig.dialect() ) {
case DATABRICKS -> switch ( sqlGenerationConfig.mappingStrategy() ) {
case DENORMALIZED -> {
final DatabricksSqlGenerationConfig config =
sqlGenerationConfig.dialectSpecificConfig() instanceof final DatabricksSqlGenerationConfig databricksConfig
? databricksConfig
: new DatabricksSqlGenerationConfig();
yield aspect.accept( new AspectModelDatabricksDenormalizedSqlVisitor( config ),
AspectModelDatabricksDenormalizedSqlVisitorContextBuilder.builder().build() );
}
};
};

return new SqlArtifact( aspect.getName() + ".sql", content );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH
*
* See the AUTHORS file(s) distributed with this work for additional
* information regarding authorship.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* SPDX-License-Identifier: MPL-2.0
*/

package org.eclipse.esmf.aspectmodel.generator.sql;

import org.eclipse.esmf.aspectmodel.generator.Artifact;

/**
* Represents a generated SQL script.
*/
public class SqlArtifact implements Artifact<String, String> {
private final String id;
private final String content;

public SqlArtifact( final String id, final String content ) {
this.id = id;
this.content = content;
}

@Override
public String getId() {
return id;
}

@Override
public String getContent() {
return content;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH
*
* See the AUTHORS file(s) distributed with this work for additional
* information regarding authorship.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* SPDX-License-Identifier: MPL-2.0
*/

package org.eclipse.esmf.aspectmodel.generator.sql;

import org.eclipse.esmf.aspectmodel.generator.GenerationConfig;

import io.soabase.recordbuilder.core.RecordBuilder;

/**
* Configuration for generating SQL scripts from an Aspect Model.
*
* @param dialect the SQL dialect to generate for
* @param mappingStrategy the mapping strategy to use
* @param dialectSpecificConfig the dialect-specific configuration
*/
@RecordBuilder
public record SqlGenerationConfig(
Dialect dialect,
MappingStrategy mappingStrategy,
DialectSpecificConfig dialectSpecificConfig
) implements GenerationConfig {
public enum Dialect {
DATABRICKS
}

public enum MappingStrategy {
DENORMALIZED
}

public interface DialectSpecificConfig extends GenerationConfig {
}

public static class DefaultDialectSpecificConfig implements DialectSpecificConfig {
}

public SqlGenerationConfig {
if ( dialect == null ) {
dialect = Dialect.DATABRICKS;
}

if ( mappingStrategy == null ) {
mappingStrategy = MappingStrategy.DENORMALIZED;
}

if ( dialectSpecificConfig == null ) {
dialectSpecificConfig = new DefaultDialectSpecificConfig();
}
}
}
Loading
Loading