diff --git a/.gitignore b/.gitignore index 443ace390c..70015e34ad 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,5 @@ tutorial/mimic_iii_demo/data/** /node_modules cypress/screenshots/ cypress/videos/ + +.codex diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000000..7caaae64bb --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,3 @@ +distributionType=bin +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar diff --git a/README.md b/README.md index c43c0101b0..832fdabb69 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,33 @@ configurations, such as: ## Development +### Backend Development + +#### Dropwizard backend (current production backend) + +From the repository root: + +```bash +./mvnw -pl backend -am test +./mvnw -pl executable -am package +java -jar executable/target/conquery.jar standalone +``` + +#### Quarkus backend (migration target) + +From the repository root: + +```bash +./mvnw -pl backend-quarkus quarkus:dev +``` + +Useful endpoints while running: + +- `http://localhost:8090/api/ping` +- `http://localhost:8090/api/config/frontend` +- `http://localhost:8090/q/health` +- `http://localhost:8090/q/swagger-ui` + ### Testing #### Integration Tests diff --git a/backend-quarkus-plugin-api/README.md b/backend-quarkus-plugin-api/README.md new file mode 100644 index 0000000000..0c9f93fb9b --- /dev/null +++ b/backend-quarkus-plugin-api/README.md @@ -0,0 +1,23 @@ +# Conquery Quarkus Plugin API + +This artifact is the compilation contract for third-party Conquery model plugins. A plugin should depend on +`backend-quarkus-plugin-api` with Maven scope `provided`; it must not depend on the `backend-quarkus` application. + +The current stable surface covers metadata filters: + +- `FilterDefinition`, `AbstractFilterDefinition`, and `SingleColumnFilterDefinition` describe plugin metadata. +- `FilterDefinitionProvider` is the CDI discovery hook. +- `FilterConversionContext` validates referenced columns without exposing backend repositories or IDs. It returns the + shared `dataset-model` contracts `ColumnDescriptor` and `ColumnType` rather than filter-specific column models. +- `FilterResult` is the implementation-neutral result mapped to the backend catalog by the host. +- `PolymorphicModelSubtype` declares the JSON/OpenAPI discriminator. + +Use frontend filter-value discriminator IDs such as `STRING` in `acceptedValueTypes()`. Include a Jandex index in the +plugin JAR. The complete development, installation, reaugmentation, and test workflow is documented in +[`backend-quarkus/README.md`](../backend-quarkus/README.md#polymorphic-model-plugins). + +Query filter-value, select, and condition contracts have not yet been extracted into this artifact and should be +considered provisional. + +The plugin API exposes `dataset-model` transitively because dataset vocabulary is part of its public signatures. Plugin +code imports those types from `com.bakdata.conquery.models.datasets`; it does not need a second explicit dependency. diff --git a/backend-quarkus-plugin-api/pom.xml b/backend-quarkus-plugin-api/pom.xml new file mode 100644 index 0000000000..2436b03911 --- /dev/null +++ b/backend-quarkus-plugin-api/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + + + com.bakdata.conquery + parent + ${revision} + ../pom.xml + + + backend-quarkus-plugin-api + Conquery Quarkus Plugin API + + + + com.bakdata.conquery + dataset-model + ${project.version} + + + com.fasterxml.jackson.core + jackson-annotations + 2.18.3 + + + jakarta.validation + jakarta.validation-api + 3.0.2 + + + org.eclipse.microprofile.openapi + microprofile-openapi-api + 4.0.2 + + + + + + + io.smallrye + jandex-maven-plugin + 3.3.1 + + + make-index + + jandex + + + + + + + diff --git a/backend-quarkus-plugin-api/src/main/java/com/bakdata/conquery/quarkus/plugin/api/filters/AbstractFilterDefinition.java b/backend-quarkus-plugin-api/src/main/java/com/bakdata/conquery/quarkus/plugin/api/filters/AbstractFilterDefinition.java new file mode 100644 index 0000000000..9d5b39eab3 --- /dev/null +++ b/backend-quarkus-plugin-api/src/main/java/com/bakdata/conquery/quarkus/plugin/api/filters/AbstractFilterDefinition.java @@ -0,0 +1,52 @@ +package com.bakdata.conquery.quarkus.plugin.api.filters; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class AbstractFilterDefinition implements FilterDefinition { + + @Schema(description = "Filter implementation discriminator.") + private String type; + @Schema(description = "Stable local name used to form the filter id. Falls back to the label when omitted.", pattern = "^\\w+$") + private String name; + @Schema(description = "Label displayed to users.") + private String label; + @JsonAlias("description") + @Schema(description = "Additional explanation displayed for the filter.") + private String tooltip; + @Schema(description = "Unit displayed with filter values.") + private String unit; + @Schema(description = "Optional input validation pattern.") + private String pattern; + @Schema(description = "Whether values may be supplied using a dropped file.") + private Boolean allowDropFile; + @Schema(description = "Default frontend value.") + private Object defaultValue; + @Schema(description = "Optional minimum frontend value.") + private Integer min; + @Schema(description = "Optional maximum frontend value.") + private Integer max; + + public String getType() { return type; } + public void setType(String type) { this.type = type; } + public String getName() { return name; } + public void setName(String name) { this.name = name; } + public String getLabel() { return label; } + public void setLabel(String label) { this.label = label; } + public String getTooltip() { return tooltip; } + public void setTooltip(String tooltip) { this.tooltip = tooltip; } + public String getUnit() { return unit; } + public void setUnit(String unit) { this.unit = unit; } + public String getPattern() { return pattern; } + public void setPattern(String pattern) { this.pattern = pattern; } + public Boolean getAllowDropFile() { return allowDropFile; } + public void setAllowDropFile(Boolean allowDropFile) { this.allowDropFile = allowDropFile; } + public Object getDefaultValue() { return defaultValue; } + public void setDefaultValue(Object defaultValue) { this.defaultValue = defaultValue; } + public Integer getMin() { return min; } + public void setMin(Integer min) { this.min = min; } + public Integer getMax() { return max; } + public void setMax(Integer max) { this.max = max; } +} diff --git a/backend-quarkus-plugin-api/src/main/java/com/bakdata/conquery/quarkus/plugin/api/filters/FilterConversionContext.java b/backend-quarkus-plugin-api/src/main/java/com/bakdata/conquery/quarkus/plugin/api/filters/FilterConversionContext.java new file mode 100644 index 0000000000..9ff6caefcd --- /dev/null +++ b/backend-quarkus-plugin-api/src/main/java/com/bakdata/conquery/quarkus/plugin/api/filters/FilterConversionContext.java @@ -0,0 +1,17 @@ +package com.bakdata.conquery.quarkus.plugin.api.filters; + +import com.bakdata.conquery.models.datasets.ColumnDescriptor; + +/** Host services available while converting a plugin filter definition. */ +public interface FilterConversionContext { + + /** Selects a stable local ID component and reports sanitized fallbacks through the host. */ + String idPartFromPreferredOrFallback(String preferred, String fallback, String idType, Object fallbackContext); + + /** + * Resolves and validates a local connector-table column. + * + * @throws IllegalArgumentException when the name is invalid or the column does not exist + */ + ColumnDescriptor requireColumn(String columnName); +} diff --git a/backend-quarkus-plugin-api/src/main/java/com/bakdata/conquery/quarkus/plugin/api/filters/FilterDefinition.java b/backend-quarkus-plugin-api/src/main/java/com/bakdata/conquery/quarkus/plugin/api/filters/FilterDefinition.java new file mode 100644 index 0000000000..ee8c68ef88 --- /dev/null +++ b/backend-quarkus-plugin-api/src/main/java/com/bakdata/conquery/quarkus/plugin/api/filters/FilterDefinition.java @@ -0,0 +1,22 @@ +package com.bakdata.conquery.quarkus.plugin.api.filters; + +import com.bakdata.conquery.quarkus.plugin.api.models.PolymorphicModelBase; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.EXISTING_PROPERTY, + property = "type", + visible = true, + defaultImpl = UnknownFilterDefinition.class +) +@Schema(name = "MetadataFilterDefinition", description = "Filter definition used in connector metadata. The concrete model is selected by `type`.", discriminatorProperty = "type") +@PolymorphicModelBase( + schemaName = "MetadataFilterDefinition", + description = "Filter definition used in connector metadata. The concrete model is selected by `type`." +) +public interface FilterDefinition { + + String getType(); +} diff --git a/backend-quarkus-plugin-api/src/main/java/com/bakdata/conquery/quarkus/plugin/api/filters/FilterDefinitionProvider.java b/backend-quarkus-plugin-api/src/main/java/com/bakdata/conquery/quarkus/plugin/api/filters/FilterDefinitionProvider.java new file mode 100644 index 0000000000..af1e072d67 --- /dev/null +++ b/backend-quarkus-plugin-api/src/main/java/com/bakdata/conquery/quarkus/plugin/api/filters/FilterDefinitionProvider.java @@ -0,0 +1,29 @@ +package com.bakdata.conquery.quarkus.plugin.api.filters; + +import java.util.Set; + +import com.bakdata.conquery.quarkus.plugin.api.models.PolymorphicModelTypeProvider; + +/** + * CDI discovery and conversion contract for one metadata filter model. + * + * @param concrete, annotated filter definition contributed by the plugin + */ +public interface FilterDefinitionProvider extends PolymorphicModelTypeProvider { + + default String type() { + return typeId(); + } + + /** + * Declares the frontend filter-value discriminator IDs emitted by this provider. + * + * @return non-empty set of registered IDs such as {@code STRING} or {@code INTEGER_RANGE} + */ + Set acceptedValueTypes(); + + /** + * Converts validated plugin metadata into an implementation-neutral filter description. + */ + FilterResult convert(FilterConversionContext context, T payload); +} diff --git a/backend-quarkus-plugin-api/src/main/java/com/bakdata/conquery/quarkus/plugin/api/filters/FilterResult.java b/backend-quarkus-plugin-api/src/main/java/com/bakdata/conquery/quarkus/plugin/api/filters/FilterResult.java new file mode 100644 index 0000000000..4e15e00c69 --- /dev/null +++ b/backend-quarkus-plugin-api/src/main/java/com/bakdata/conquery/quarkus/plugin/api/filters/FilterResult.java @@ -0,0 +1,32 @@ +package com.bakdata.conquery.quarkus.plugin.api.filters; + +import java.util.List; + +/** + * Backend-independent filter description emitted by a plugin provider. + * + *

Required columns are local names. The host validates them again and creates its own IDs and repository records.

+ */ +public record FilterResult( + String name, + String label, + String valueType, + String unit, + String tooltip, + List