Skip to content

Commit 41805cc

Browse files
committed
Refine API to create and render CQL object specifications.
We now expose specification entrypoints at SpecificationBuilder and a generic generator at CqlGenerator.toCql(…). Closes #1506
1 parent e154ef6 commit 41805cc

File tree

43 files changed

+1010
-202
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1010
-202
lines changed

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminTemplate.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,9 @@
2323
import org.springframework.data.cassandra.core.convert.SchemaFactory;
2424
import org.springframework.data.cassandra.core.cql.CqlOperations;
2525
import org.springframework.data.cassandra.core.cql.SessionCallback;
26-
import org.springframework.data.cassandra.core.cql.generator.CreateTableCqlGenerator;
27-
import org.springframework.data.cassandra.core.cql.generator.DropTableCqlGenerator;
28-
import org.springframework.data.cassandra.core.cql.generator.DropUserTypeCqlGenerator;
26+
import org.springframework.data.cassandra.core.cql.generator.CqlGenerator;
2927
import org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification;
30-
import org.springframework.data.cassandra.core.cql.keyspace.DropTableSpecification;
31-
import org.springframework.data.cassandra.core.cql.keyspace.DropUserTypeSpecification;
28+
import org.springframework.data.cassandra.core.cql.keyspace.SpecificationBuilder;
3229
import org.springframework.data.cassandra.core.cql.keyspace.TableOption;
3330
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
3431
import org.springframework.util.Assert;
@@ -127,7 +124,7 @@ public void createTable(boolean ifNotExists, CqlIdentifier tableName, Class<?> e
127124
});
128125
}
129126

130-
getCqlOperations().execute(CreateTableCqlGenerator.toCql(createTableSpecification));
127+
getCqlOperations().execute(CqlGenerator.toCql(createTableSpecification));
131128
}
132129

133130
@Override
@@ -143,7 +140,7 @@ public void dropTable(CqlIdentifier tableName) {
143140
@Override
144141
public void dropTable(boolean ifExists, CqlIdentifier tableName) {
145142

146-
String dropTableCql = DropTableCqlGenerator.toCql(DropTableSpecification.dropTable(tableName).ifExists(ifExists));
143+
String dropTableCql = CqlGenerator.toCql(SpecificationBuilder.dropTable(tableName).ifExists(ifExists));
147144

148145
getCqlOperations().execute(dropTableCql);
149146
}
@@ -153,7 +150,7 @@ public void dropUserType(CqlIdentifier typeName) {
153150

154151
Assert.notNull(typeName, "Type name must not be null");
155152

156-
String dropUserTypeCql = DropUserTypeCqlGenerator.toCql(DropUserTypeSpecification.dropType(typeName));
153+
String dropUserTypeCql = CqlGenerator.toCql(SpecificationBuilder.dropType(typeName));
157154

158155
getCqlOperations().execute(dropUserTypeCql);
159156
}

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraPersistentEntitySchemaCreator.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@
2424
import java.util.stream.Collectors;
2525

2626
import org.jetbrains.annotations.NotNull;
27-
import org.springframework.data.cassandra.core.cql.generator.CreateIndexCqlGenerator;
28-
import org.springframework.data.cassandra.core.cql.generator.CreateTableCqlGenerator;
29-
import org.springframework.data.cassandra.core.cql.generator.CreateUserTypeCqlGenerator;
27+
28+
import org.springframework.data.cassandra.core.cql.generator.CqlGenerator;
3029
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification;
3130
import org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification;
3231
import org.springframework.data.cassandra.core.cql.keyspace.CreateUserTypeSpecification;
@@ -96,7 +95,7 @@ public CassandraPersistentEntitySchemaCreator(CassandraMappingContext mappingCon
9695
public void createTables(boolean ifNotExists) {
9796

9897
createTableSpecifications(ifNotExists).stream() //
99-
.map(CreateTableCqlGenerator::toCql) //
98+
.map(CqlGenerator::toCql) //
10099
.forEach(cql -> this.cassandraAdminOperations.getCqlOperations().execute(cql));
101100
}
102101

@@ -123,7 +122,7 @@ protected List<CreateTableSpecification> createTableSpecifications(boolean ifNot
123122
public void createIndexes(boolean ifNotExists) {
124123

125124
createIndexSpecifications(ifNotExists).stream() //
126-
.map(CreateIndexCqlGenerator::toCql) //
125+
.map(CqlGenerator::toCql) //
127126
.forEach(cql -> this.cassandraAdminOperations.getCqlOperations().execute(cql));
128127
}
129128

@@ -150,7 +149,7 @@ protected List<CreateIndexSpecification> createIndexSpecifications(boolean ifNot
150149
public void createUserTypes(boolean ifNotExists) {
151150

152151
createUserTypeSpecifications(ifNotExists).stream() //
153-
.map(CreateUserTypeCqlGenerator::toCql) //
152+
.map(CqlGenerator::toCql) //
154153
.forEach(cql -> this.cassandraAdminOperations.getCqlOperations().execute(cql));
155154
}
156155

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/IndexSpecificationFactory.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import org.springframework.core.annotation.AnnotatedElementUtils;
2929
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification;
30+
import org.springframework.data.cassandra.core.cql.keyspace.SpecificationBuilder;
3031
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
3132
import org.springframework.data.cassandra.core.mapping.Indexed;
3233
import org.springframework.data.cassandra.core.mapping.SASI;
@@ -136,9 +137,9 @@ static CreateIndexSpecification createIndexSpecification(@Nullable CqlIdentifier
136137
CreateIndexSpecification index;
137138

138139
if (StringUtils.hasText(annotation.value())) {
139-
index = CreateIndexSpecification.createIndex(keyspace, CqlIdentifier.fromCql(annotation.value()));
140+
index = SpecificationBuilder.createIndex(keyspace, CqlIdentifier.fromCql(annotation.value()));
140141
} else {
141-
index = CreateIndexSpecification.createIndex(keyspace, null);
142+
index = SpecificationBuilder.createIndex(keyspace, null);
142143
}
143144

144145
return index.columnName(property.getRequiredColumnName());
@@ -150,9 +151,9 @@ private static CreateIndexSpecification createIndexSpecification(@Nullable CqlId
150151
CreateIndexSpecification index;
151152

152153
if (StringUtils.hasText(annotation.value())) {
153-
index = CreateIndexSpecification.createIndex(keyspace, CqlIdentifier.fromCql(annotation.value()));
154+
index = SpecificationBuilder.createIndex(keyspace, CqlIdentifier.fromCql(annotation.value()));
154155
} else {
155-
index = CreateIndexSpecification.createIndex(keyspace, null);
156+
index = SpecificationBuilder.createIndex(keyspace, null);
156157
}
157158

158159
index.using("org.apache.cassandra.index.sasi.SASIIndex") //

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/SchemaFactory.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,14 @@
1515
*/
1616
package org.springframework.data.cassandra.core.convert;
1717

18-
import static org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification.*;
19-
2018
import java.util.ArrayList;
2119
import java.util.List;
2220
import java.util.Objects;
2321

2422
import org.springframework.data.cassandra.core.cql.keyspace.CreateIndexSpecification;
2523
import org.springframework.data.cassandra.core.cql.keyspace.CreateTableSpecification;
2624
import org.springframework.data.cassandra.core.cql.keyspace.CreateUserTypeSpecification;
25+
import org.springframework.data.cassandra.core.cql.keyspace.SpecificationBuilder;
2726
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
2827
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
2928
import org.springframework.data.cassandra.core.mapping.EmbeddedEntityOperations;
@@ -141,7 +140,7 @@ public CreateTableSpecification getCreateTableSpecificationFor(CassandraPersiste
141140
Assert.notNull(tableName, "Table name must not be null");
142141
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
143142

144-
CreateTableSpecification specification = createTable(entity.getKeyspace(), tableName);
143+
CreateTableSpecification specification = SpecificationBuilder.createTable(entity.getKeyspace(), tableName);
145144

146145
for (CassandraPersistentProperty property : entity) {
147146

@@ -296,7 +295,7 @@ public CreateUserTypeSpecification getCreateUserTypeSpecificationFor(CassandraPe
296295

297296
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
298297

299-
CreateUserTypeSpecification specification = CreateUserTypeSpecification.createType(entity.getKeyspace(),
298+
CreateUserTypeSpecification specification = SpecificationBuilder.createType(entity.getKeyspace(),
300299
entity.getTableName());
301300

302301
for (CassandraPersistentProperty property : entity) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.cassandra.core.cql.generator;
17+
18+
import org.springframework.data.cassandra.core.cql.keyspace.*;
19+
20+
/**
21+
* Entrypoint for CQL generation of {@link CqlSpecification} objects representing DML statements such as table creations
22+
* or keyspace drops. For example:
23+
*
24+
* <pre class="code">
25+
* DropUserTypeSpecification spec = SpecificationBuilder.dropType("address");
26+
* String cql = CqlGenerator.toCql(spec);
27+
* </pre>
28+
*
29+
* @author Mark Paluch
30+
* @since 4.4
31+
* @see SpecificationBuilder
32+
*/
33+
public final class CqlGenerator {
34+
35+
private CqlGenerator() {
36+
// utility class, no instances
37+
}
38+
39+
/**
40+
* Entrypoint for CQL generation of {@link CqlSpecification} objects.
41+
*
42+
* @param specification the CQL specification to generate CQL for.
43+
* @return the generated CQL from {@link CqlSpecification}.
44+
*/
45+
public static String toCql(CqlSpecification specification) {
46+
47+
if (specification instanceof CreateKeyspaceSpecification createKeyspace) {
48+
return CreateKeyspaceCqlGenerator.toCql(createKeyspace);
49+
}
50+
51+
if (specification instanceof AlterKeyspaceSpecification alterKeyspace) {
52+
return AlterKeyspaceCqlGenerator.toCql(alterKeyspace);
53+
}
54+
55+
if (specification instanceof DropKeyspaceSpecification dropKeyspace) {
56+
return DropKeyspaceCqlGenerator.toCql(dropKeyspace);
57+
}
58+
59+
if (specification instanceof CreateTableSpecification createTable) {
60+
return CreateTableCqlGenerator.toCql(createTable);
61+
}
62+
63+
if (specification instanceof AlterTableSpecification alterTable) {
64+
return AlterTableCqlGenerator.toCql(alterTable);
65+
}
66+
67+
if (specification instanceof DropTableSpecification dropTable) {
68+
return DropTableCqlGenerator.toCql(dropTable);
69+
}
70+
71+
if (specification instanceof CreateUserTypeSpecification createType) {
72+
return CreateUserTypeCqlGenerator.toCql(createType);
73+
}
74+
75+
if (specification instanceof AlterUserTypeSpecification alterType) {
76+
return AlterUserTypeCqlGenerator.toCql(alterType);
77+
}
78+
79+
if (specification instanceof DropUserTypeSpecification dropType) {
80+
return DropUserTypeCqlGenerator.toCql(dropType);
81+
}
82+
83+
if (specification instanceof CreateIndexSpecification createIndex) {
84+
return CreateIndexCqlGenerator.toCql(createIndex);
85+
}
86+
87+
if (specification instanceof DropIndexSpecification dropIndex) {
88+
return DropIndexCqlGenerator.toCql(dropIndex);
89+
}
90+
91+
throw new UnsupportedOperationException(String.format("CQL specification %s is not supported", specification));
92+
}
93+
}

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/AlterKeyspaceSpecification.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
*
2323
* @author Mark Paluch
2424
*/
25-
public class AlterKeyspaceSpecification extends KeyspaceOptionsSpecification<AlterKeyspaceSpecification> {
25+
public class AlterKeyspaceSpecification extends KeyspaceOptionsSpecification<AlterKeyspaceSpecification>
26+
implements CqlSpecification {
2627

2728
private AlterKeyspaceSpecification(CqlIdentifier name) {
2829
super(name);

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/AlterTableSpecification.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
* @see TableOptionsSpecification
3939
* @see org.springframework.data.cassandra.core.cql.generator.AlterTableCqlGenerator
4040
*/
41-
public class AlterTableSpecification extends TableOptionsSpecification<AlterTableSpecification> {
41+
public class AlterTableSpecification extends TableOptionsSpecification<AlterTableSpecification>
42+
implements CqlSpecification {
4243

4344
/**
4445
* The list of column changes.
@@ -81,7 +82,7 @@ public static AlterTableSpecification alterTable(CqlIdentifier tableName) {
8182
* @return a new {@link AlterTableSpecification}.
8283
* @since 4.4
8384
*/
84-
public static AlterTableSpecification alterTable(CqlIdentifier keyspace, CqlIdentifier tableName) {
85+
public static AlterTableSpecification alterTable(@Nullable CqlIdentifier keyspace, CqlIdentifier tableName) {
8586
return new AlterTableSpecification(keyspace, tableName);
8687
}
8788

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/AlterUserTypeSpecification.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
* @since 1.5
3333
* @see CqlIdentifier
3434
*/
35-
public class AlterUserTypeSpecification extends UserTypeNameSpecification {
35+
public class AlterUserTypeSpecification extends UserTypeNameSpecification implements CqlSpecification {
3636

3737
private final List<ColumnChangeSpecification> changes = new ArrayList<>();
3838

@@ -58,7 +58,7 @@ public static AlterUserTypeSpecification alterType(String typeName) {
5858
* @param typeName must not be {@literal null}.
5959
* @return a new {@link AlterUserTypeSpecification}.
6060
*/
61-
private static AlterUserTypeSpecification alterType(CqlIdentifier typeName) {
61+
public static AlterUserTypeSpecification alterType(CqlIdentifier typeName) {
6262
return new AlterUserTypeSpecification(null, typeName);
6363
}
6464

@@ -70,8 +70,9 @@ private static AlterUserTypeSpecification alterType(CqlIdentifier typeName) {
7070
* @param keyspace can be {@literal null}.
7171
* @param typeName must not be {@literal null}.
7272
* @return a new {@link AlterUserTypeSpecification}.
73+
* @since 4.4
7374
*/
74-
private static AlterUserTypeSpecification alterType(@Nullable CqlIdentifier keyspace, CqlIdentifier typeName) {
75+
public static AlterUserTypeSpecification alterType(@Nullable CqlIdentifier keyspace, CqlIdentifier typeName) {
7576
return new AlterUserTypeSpecification(keyspace, typeName);
7677
}
7778

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.cassandra.core.cql.keyspace;
17+
18+
/**
19+
* Marker interface for CQL specification objects that describe CQL keyspace objects.
20+
*
21+
* @author Mark Paluch
22+
* @since 4.4
23+
*/
24+
public interface CqlSpecification {}

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/CreateIndexSpecification.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
* @author Mark Paluch
3535
*/
3636
public class CreateIndexSpecification extends IndexNameSpecification<CreateIndexSpecification>
37-
implements IndexDescriptor {
37+
implements IndexDescriptor, CqlSpecification {
3838

3939
private @Nullable CqlIdentifier tableName;
4040

@@ -57,15 +57,15 @@ private CreateIndexSpecification(@Nullable CqlIdentifier keyspace, @Nullable Cql
5757
}
5858

5959
/**
60-
* Entry point into the {@link CreateIndexSpecification}'s fluent API to create a index. Convenient if imported
60+
* Entry point into the {@link CreateIndexSpecification}'s fluent API to create an index. Convenient if imported
6161
* statically.
6262
*/
6363
public static CreateIndexSpecification createIndex() {
6464
return new CreateIndexSpecification();
6565
}
6666

6767
/**
68-
* Entry point into the {@link CreateIndexSpecification}'s fluent API given {@code indexName} to create a index.
68+
* Entry point into the {@link CreateIndexSpecification}'s fluent API given {@code indexName} to create an index.
6969
* Convenient if imported statically.
7070
*
7171
* @param indexName must not be {@literal null} or empty.
@@ -76,7 +76,7 @@ public static CreateIndexSpecification createIndex(String indexName) {
7676
}
7777

7878
/**
79-
* Entry point into the {@link CreateIndexSpecification}'s fluent API given {@code indexName} to create a index.
79+
* Entry point into the {@link CreateIndexSpecification}'s fluent API given {@code indexName} to create an index.
8080
* Convenient if imported statically.
8181
*
8282
* @param indexName must not be {@literal null}.

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/CreateKeyspaceSpecification.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
* @author Mark Paluch
2929
*/
3030
public class CreateKeyspaceSpecification extends KeyspaceOptionsSpecification<CreateKeyspaceSpecification>
31-
implements KeyspaceDescriptor {
31+
implements KeyspaceDescriptor, CqlSpecification {
3232

3333
private boolean ifNotExists = false;
3434

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/cql/keyspace/CreateTableSpecification.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
* @author Matthew T. Adams
2626
* @author Mark Paluch
2727
*/
28-
public class CreateTableSpecification extends TableSpecification<CreateTableSpecification> {
28+
public class CreateTableSpecification extends TableSpecification<CreateTableSpecification> implements CqlSpecification {
2929

3030
private boolean ifNotExists = false;
3131

0 commit comments

Comments
 (0)