Skip to content
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

feat(sql): add query capabilities to the SQL Policy Store #1571

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ in the detailed section referring to by linking pull requests or issues.
* Fix TODO and document `:extensions:data-plane-transfer` (#1519)
* CloudEvents Http extension (#1160)
* Full Query capabilities for SQL TransferProcess Store (#1483)
* Full Query capabilities for SQL PolicyDefinition Store (#1484)

#### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.eclipse.dataspaceconnector.spi.query.Criterion;
import org.eclipse.dataspaceconnector.spi.query.QuerySpec;
import org.eclipse.dataspaceconnector.spi.result.Result;
import org.eclipse.dataspaceconnector.sql.dialect.BaseSqlDialect;
import org.eclipse.dataspaceconnector.sql.translation.SqlConditionExpression;
import org.eclipse.dataspaceconnector.sql.translation.SqlQueryStatement;

Expand Down Expand Up @@ -98,7 +99,7 @@ public String getQuerySubSelectTemplate() {

@Override
public String getFormatAsJsonOperator() {
return " FORMAT JSON";
return BaseSqlDialect.getJsonCastOperator();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
package org.eclipse.dataspaceconnector.sql.assetindex.schema.postgres;

import org.eclipse.dataspaceconnector.sql.assetindex.schema.BaseSqlDialectStatements;
import org.eclipse.dataspaceconnector.sql.dialect.PostgresDialect;

public class PostgresDialectStatements extends BaseSqlDialectStatements {
@Override
public String getFormatAsJsonOperator() {
return "::json";
return PostgresDialect.getJsonCastOperator();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.eclipse.dataspaceconnector.spi.types.domain.asset.Asset;
import org.eclipse.dataspaceconnector.sql.SqlQueryExecutor;
import org.eclipse.dataspaceconnector.sql.assetindex.schema.BaseSqlDialectStatements;
import org.eclipse.dataspaceconnector.sql.dialect.BaseSqlDialect;
import org.h2.jdbcx.JdbcDataSource;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -448,7 +449,7 @@ private Connection getConnection() throws SQLException {
private static class H2DialectStatements extends BaseSqlDialectStatements {
@Override
public String getFormatAsJsonOperator() {
return " FORMAT JSON";
return BaseSqlDialect.getJsonCastOperator();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ private SqlQueryExecutor() {
/**
* Intended for mutating queries.
*
* @param sql the parametrized sql query
* @param sql the parametrized sql query
* @param arguments the parameters to interpolate with the parametrized sql query
* @return rowsChanged
*/
Expand All @@ -57,9 +57,9 @@ public static int executeQuery(Connection connection, String sql, Object... argu
* Intended for reading queries.
*
* @param resultSetMapper able to map a row to an object e.g. pojo.
* @param sql the parametrized sql query
* @param arguments the parameteres to interpolate with the parametrized sql query
* @param <T> generic type returned after mapping from the executed query
* @param sql the parametrized sql query
* @param arguments the parameteres to interpolate with the parametrized sql query
* @param <T> generic type returned after mapping from the executed query
* @return results
*/
public static <T> List<T> executeQuery(Connection connection, ResultSetMapper<T> resultSetMapper, String sql, Object... arguments) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2022 Microsoft Corporation
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Microsoft Corporation - initial API and implementation
*
*/

package org.eclipse.dataspaceconnector.sql.dialect;

/**
* Global, domain-agnostic and generic SQL statements, operators, functions, clauses, etc.
*/
public class BaseSqlDialect {
public static String getJsonCastOperator() {
return " FORMAT JSON";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2022 Microsoft Corporation
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Microsoft Corporation - initial API and implementation
*
*/

package org.eclipse.dataspaceconnector.sql.dialect;

import static java.lang.String.format;

/**
* Global, domain-agnostic Postgres statements, operators, functions, clauses, etc.
*/
public class PostgresDialect {
/**
* Creates a SELECT statement that targets a Postgres JSON array
*
* @param selectStatement The select statement, does not include the {@code json_array_elements} function
* call
* @param jsonPath The path to the array object, which is passed as parameter to the
* {@code json_array_elements()} function
* @param aliasName the alias under which the JSON array is available, e.g. for WHERE clauses
*/
public static String getSelectFromJsonArrayTemplate(String selectStatement, String jsonPath, String aliasName) {
return format("%s, json_array_elements(%s) as %s", selectStatement, jsonPath, aliasName);
}

/**
* Returns the Postgres operator to cast a varchar to json ({@code "::json"})
*/
public static String getJsonCastOperator() {
return "::json";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,8 @@ public SqlQueryStatement createQuery(QuerySpec querySpec) {
var select = format("SELECT * FROM %s", getContractDefinitionTable());
return new SqlQueryStatement(select, querySpec, new ContractDefinitionMapping(this));
}

protected String getSelectStatement() {
return "SELECT * FROM " + getContractDefinitionTable();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.eclipse.dataspaceconnector.sql.contractdefinition.store.schema;

import org.eclipse.dataspaceconnector.spi.query.QuerySpec;
import org.eclipse.dataspaceconnector.sql.dialect.BaseSqlDialect;
import org.eclipse.dataspaceconnector.sql.translation.SqlQueryStatement;

/**
Expand Down Expand Up @@ -54,6 +55,6 @@ default String getIdColumn() {
SqlQueryStatement createQuery(QuerySpec querySpec);

default String getFormatAsJsonOperator() {
return " FORMAT JSON";
return BaseSqlDialect.getJsonCastOperator();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,30 @@

import org.eclipse.dataspaceconnector.spi.query.QuerySpec;
import org.eclipse.dataspaceconnector.sql.contractdefinition.store.schema.BaseSqlDialectStatements;
import org.eclipse.dataspaceconnector.sql.dialect.PostgresDialect;
import org.eclipse.dataspaceconnector.sql.translation.SqlQueryStatement;

import static java.lang.String.format;
import static org.eclipse.dataspaceconnector.sql.dialect.PostgresDialect.getSelectFromJsonArrayTemplate;

/**
* Contains Postgres-specific SQL statements
*/
public class PostgresDialectStatements extends BaseSqlDialectStatements {
@Override
public String getFormatAsJsonOperator() {
return "::json";
return PostgresDialect.getJsonCastOperator();
}

@Override
public SqlQueryStatement createQuery(QuerySpec querySpec) {
// if any criterion targets a JSON array field, we need to slightly adapt the FROM clause
if (querySpec.getFilterExpression().stream().anyMatch(c -> c.getOperandLeft().toString().startsWith("selectorExpression.criteria"))) {
var select = getSelectFromJsonArrayTemplate(format("%s -> '%s'", getSelectorExpressionColumn(), "criteria"), "criteria");
if (querySpec.containsAnyLeftOperand("selectorExpression.criteria")) {
var select = getSelectFromJsonArrayTemplate(getSelectStatement(), format("%s -> '%s'", getSelectorExpressionColumn(), "criteria"), "criteria");
return new SqlQueryStatement(select, querySpec, new ContractDefinitionMapping(this));
}
return super.createQuery(querySpec);
}

/**
* Creates a SELECT statement that targets a Postgres JSON array
*
* @param jsonPath The path to the array object, which is passed as parameter to the
* {@code json_array_elements()} function
* @param aliasName the alias under which the JSON array is available, e.g. for WHERE clauses
*/
private String getSelectFromJsonArrayTemplate(String jsonPath, String aliasName) {
return format("SELECT * FROM %s, json_array_elements(%s) as %s", getContractDefinitionTable(), jsonPath, aliasName);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.eclipse.dataspaceconnector.sql.contractnegotiation.store.schema;

import org.eclipse.dataspaceconnector.spi.query.QuerySpec;
import org.eclipse.dataspaceconnector.sql.dialect.BaseSqlDialect;
import org.eclipse.dataspaceconnector.sql.translation.SqlQueryStatement;

import static java.lang.String.format;
Expand Down Expand Up @@ -147,7 +148,7 @@ public String getFindLeaseByEntityTemplate() {
* Overridable operator to convert strings to JSON. For postgres, this is the "::json" operator
*/
protected String getFormatJsonOperator() {
return " FORMAT JSON";
return BaseSqlDialect.getJsonCastOperator();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.eclipse.dataspaceconnector.spi.query.QuerySpec;
import org.eclipse.dataspaceconnector.sql.contractnegotiation.store.schema.BaseSqlDialectStatements;
import org.eclipse.dataspaceconnector.sql.contractnegotiation.store.schema.ContractNegotiationStatements;
import org.eclipse.dataspaceconnector.sql.dialect.PostgresDialect;
import org.eclipse.dataspaceconnector.sql.translation.SqlQueryStatement;

/**
Expand Down Expand Up @@ -45,6 +46,6 @@ public SqlQueryStatement createAgreementsQuery(QuerySpec querySpec) {
*/
@Override
protected String getFormatJsonOperator() {
return "::json";
return PostgresDialect.getJsonCastOperator();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.eclipse.dataspaceconnector.spi.types.domain.contract.negotiation.ContractNegotiationStates;
import org.eclipse.dataspaceconnector.sql.SqlQueryExecutor;
import org.eclipse.dataspaceconnector.sql.contractnegotiation.store.schema.postgres.PostgresDialectStatements;
import org.eclipse.dataspaceconnector.sql.dialect.BaseSqlDialect;
import org.eclipse.dataspaceconnector.sql.lease.LeaseUtil;
import org.h2.jdbcx.JdbcDataSource;
import org.junit.jupiter.api.AfterEach;
Expand Down Expand Up @@ -613,7 +614,7 @@ protected Connection getConnection() {
private static class H2DialectStatements extends PostgresDialectStatements {
@Override
protected String getFormatJsonOperator() {
return " FORMAT JSON";
return BaseSqlDialect.getJsonCastOperator();
}
}
}
2 changes: 2 additions & 0 deletions extensions/sql/policy-store-sql/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ plugins {

val h2Version: String by project
val assertj: String by project
val postgresVersion: String by project

dependencies {
api(project(":spi:core-spi"))
Expand All @@ -32,6 +33,7 @@ dependencies {
testImplementation("com.h2database:h2:${h2Version}")
testImplementation(project(":extensions:junit"))
testImplementation(testFixtures(project(":common:util")))
testImplementation("org.postgresql:postgresql:${postgresVersion}")

}

Expand Down
5 changes: 3 additions & 2 deletions extensions/sql/policy-store-sql/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

Provides SQL persistence for policies.

Note that the SQL statements (DDL) are specific to and only tested with PostgreSQL. Using it with other RDBMS may work but might have unexpected side effects!
Note that the SQL statements (DDL) are specific to and only tested with PostgreSQL. Using it with other RDBMS may work
but might have unexpected side effects!

## Prerequisites

Expand All @@ -14,7 +15,7 @@ Please apply this [schema](schema.sql) to your SQL database.
<!--
```plantuml
@startuml
entity edc_policies {
entity edc_policydefinitions {
* policy_id: string <<PK>>
--
* access_policy: string <<json>>
Expand Down
2 changes: 1 addition & 1 deletion extensions/sql/policy-store-sql/docs/er.puml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Contributors:


@startuml
entity edc_policies {
entity edc_policydefinitions {
* policy_id: string <<PK>>
--
permissions: string <<json>>
Expand Down
38 changes: 19 additions & 19 deletions extensions/sql/policy-store-sql/docs/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,27 @@

-- Statements are designed for and tested with Postgres only!

-- table: edc_policies
CREATE TABLE IF NOT EXISTS edc_policies
-- table: edc_policydefinitions
CREATE TABLE IF NOT EXISTS edc_policydefinitions
(
policy_id VARCHAR NOT NULL,
permissions VARCHAR,
prohibitions VARCHAR,
duties VARCHAR,
extensible_properties VARCHAR,
inherits_from VARCHAR,
assigner VARCHAR,
assignee VARCHAR,
target VARCHAR,
policy_type VARCHAR NOT NULL,
policy_id VARCHAR NOT NULL,
permissions JSON,
prohibitions JSON,
duties JSON,
extensible_properties JSON,
inherits_from VARCHAR,
assigner VARCHAR,
assignee VARCHAR,
target VARCHAR,
policy_type VARCHAR NOT NULL,
PRIMARY KEY (policy_id)
);

COMMENT ON COLUMN edc_policies.permissions IS 'Java List<Permission> serialized as JSON';
COMMENT ON COLUMN edc_policies.prohibitions IS 'Java List<Prohibition> serialized as JSON';
COMMENT ON COLUMN edc_policies.duties IS 'Java List<Duty> serialized as JSON';
COMMENT ON COLUMN edc_policies.extensible_properties IS 'Java Map<String, Object> serialized as JSON';
COMMENT ON COLUMN edc_policies.policy_type IS 'Java PolicyType serialized as JSON';
COMMENT ON COLUMN edc_policydefinitions.permissions IS 'Java List<Permission> serialized as JSON';
COMMENT ON COLUMN edc_policydefinitions.prohibitions IS 'Java List<Prohibition> serialized as JSON';
COMMENT ON COLUMN edc_policydefinitions.duties IS 'Java List<Duty> serialized as JSON';
COMMENT ON COLUMN edc_policydefinitions.extensible_properties IS 'Java Map<String, Object> serialized as JSON';
COMMENT ON COLUMN edc_policydefinitions.policy_type IS 'Java PolicyType serialized as JSON';

CREATE UNIQUE INDEX IF NOT EXISTS edc_policies_id_uindex
ON edc_policies (policy_id);
CREATE UNIQUE INDEX IF NOT EXISTS edc_policydefinitions_id_uindex
ON edc_policydefinitions (policy_id);
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
import org.eclipse.dataspaceconnector.spi.system.ServiceExtensionContext;
import org.eclipse.dataspaceconnector.spi.transaction.TransactionContext;
import org.eclipse.dataspaceconnector.spi.transaction.datasource.DataSourceRegistry;
import org.eclipse.dataspaceconnector.sql.policy.store.PostgressStatements;
import org.eclipse.dataspaceconnector.sql.policy.store.SqlPolicyDefinitionStore;
import org.eclipse.dataspaceconnector.sql.policy.store.SqlPolicyStoreStatements;
import org.eclipse.dataspaceconnector.sql.policy.store.schema.SqlPolicyStoreStatements;
import org.eclipse.dataspaceconnector.sql.policy.store.schema.postgres.PostgresDialectStatements;

@Provides(PolicyDefinitionStore.class)
public class SqlPolicyStoreExtension implements ServiceExtension {
Expand Down Expand Up @@ -53,7 +53,7 @@ public void initialize(ServiceExtensionContext context) {
* returns an externally-provided sql statement dialect, or postgres as a default
*/
private SqlPolicyStoreStatements getStatementImpl() {
return statements != null ? statements : new PostgressStatements();
return statements != null ? statements : new PostgresDialectStatements();
}

private String getDataSourceName(ServiceExtensionContext context) {
Expand Down
Loading