Skip to content

Commit 9b6c2f0

Browse files
committed
#220 - Add Fluent API for EntityOperations.
1 parent 1cfc367 commit 9b6c2f0

13 files changed

+1542
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2018-2020 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.r2dbc.core;
17+
18+
/**
19+
* Stripped down interface providing access to a fluent API that specifies a basic set of reactive R2DBC operations.
20+
*
21+
* @author Mark Paluch
22+
* @since 1.1
23+
* @see R2dbcEntityOperations
24+
*/
25+
public interface FluentR2dbcOperations
26+
extends ReactiveSelectOperation, ReactiveInsertOperation, ReactiveUpdateOperation, ReactiveDeleteOperation {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Copyright 2018-2020 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.r2dbc.core;
17+
18+
import reactor.core.publisher.Mono;
19+
20+
import org.springframework.data.r2dbc.query.Query;
21+
22+
/**
23+
* The {@link ReactiveDeleteOperation} interface allows creation and execution of {@code DELETE} operations in a fluent
24+
* API style.
25+
* <p>
26+
* The starting {@literal domainType} is used for mapping the {@link Query} provided via {@code matching}. By default,
27+
* the table to operate on is derived from the initial {@literal domainType} and can be defined there via
28+
* {@link org.springframework.data.relational.core.mapping.Table} annotation. Using {@code inTable} allows to override
29+
* the table name for the execution.
30+
*
31+
* <pre>
32+
* <code>
33+
* delete(Jedi.class)
34+
* .from("star_wars")
35+
* .matching(query(where("firstname").is("luke")))
36+
* .all();
37+
* </code>
38+
* </pre>
39+
*
40+
* @author Mark Paluch
41+
* @since 1.1
42+
*/
43+
public interface ReactiveDeleteOperation {
44+
45+
/**
46+
* Begin creating a {@code DELETE} operation for the given {@link Class domainType}.
47+
*
48+
* @param domainType {@link Class type} of domain object to delete; must not be {@literal null}.
49+
* @return new instance of {@link ReactiveDelete}.
50+
* @throws IllegalArgumentException if {@link Class domainType} is {@literal null}.
51+
* @see ReactiveDelete
52+
*/
53+
ReactiveDelete delete(Class<?> domainType);
54+
55+
/**
56+
* Table override (optional).
57+
*/
58+
interface DeleteWithTable {
59+
60+
/**
61+
* Explicitly set the {@link String name} of the table on which to perform the delete.
62+
* <p>
63+
* Skip this step to use the default table derived from the {@link Class domain type}.
64+
*
65+
* @param table {@link String name} of the table; must not be {@literal null} or empty.
66+
* @return new instance of {@link DeleteWithQuery}.
67+
* @throws IllegalArgumentException if {@link String table} is {@literal null} or empty.
68+
* @see DeleteWithQuery
69+
*/
70+
DeleteWithQuery from(String table);
71+
}
72+
73+
/**
74+
* Required {@link Query filter}.
75+
*/
76+
interface DeleteWithQuery {
77+
78+
/**
79+
* Define the {@link Query} used to filter elements in the delete.
80+
*
81+
* @param query {@link Query} used as the filter in the delete; must not be {@literal null}.
82+
* @return new instance of {@link TerminatingDelete}.
83+
* @throws IllegalArgumentException if {@link Query} is {@literal null}.
84+
* @see TerminatingDelete
85+
* @see Query
86+
*/
87+
TerminatingDelete matching(Query query);
88+
}
89+
90+
/**
91+
* Trigger {@code DELETE} operation by calling one of the terminating methods.
92+
*/
93+
interface TerminatingDelete {
94+
95+
/**
96+
* Remove all matching rows.
97+
*
98+
* @return the number of affected rows; never {@literal null}.
99+
* @see Mono
100+
*/
101+
Mono<Integer> all();
102+
}
103+
104+
/**
105+
* The {@link ReactiveDelete} interface provides methods for constructing {@code DELETE} operations in a fluent way.
106+
*/
107+
interface ReactiveDelete extends DeleteWithTable, DeleteWithQuery {}
108+
109+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright 2018-2020 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.r2dbc.core;
17+
18+
import reactor.core.publisher.Mono;
19+
20+
import org.springframework.data.r2dbc.query.Query;
21+
import org.springframework.lang.Nullable;
22+
import org.springframework.util.Assert;
23+
24+
/**
25+
* Implementation of {@link ReactiveDeleteOperation}.
26+
*
27+
* @author Mark Paluch
28+
* @since 1.1
29+
*/
30+
class ReactiveDeleteOperationSupport implements ReactiveDeleteOperation {
31+
32+
private final R2dbcEntityTemplate template;
33+
34+
ReactiveDeleteOperationSupport(R2dbcEntityTemplate template) {
35+
this.template = template;
36+
}
37+
38+
/*
39+
* (non-Javadoc)
40+
* @see org.springframework.data.r2dbc.core.ReactiveDeleteOperation#delete(java.lang.Class)
41+
*/
42+
@Override
43+
public ReactiveDelete delete(Class<?> domainType) {
44+
45+
Assert.notNull(domainType, "DomainType must not be null");
46+
47+
return new ReactiveDeleteSupport(this.template, domainType, Query.empty(), null);
48+
}
49+
50+
static class ReactiveDeleteSupport implements ReactiveDelete, TerminatingDelete {
51+
52+
private final R2dbcEntityTemplate template;
53+
54+
private final Class<?> domainType;
55+
56+
private final Query query;
57+
58+
private final @Nullable String tableName;
59+
60+
ReactiveDeleteSupport(R2dbcEntityTemplate template, Class<?> domainType, Query query, @Nullable String tableName) {
61+
this.template = template;
62+
this.domainType = domainType;
63+
this.query = query;
64+
this.tableName = tableName;
65+
}
66+
67+
/*
68+
* (non-Javadoc)
69+
* @see org.springframework.data.r2dbc.core.ReactiveDeleteOperation.DeleteWithTable#from(java.lang.String)
70+
*/
71+
@Override
72+
public DeleteWithQuery from(String tableName) {
73+
74+
Assert.hasText(tableName, "Table name must not be null or empty");
75+
76+
return new ReactiveDeleteSupport(this.template, this.domainType, this.query, tableName);
77+
}
78+
79+
/*
80+
* (non-Javadoc)
81+
* @see org.springframework.data.r2dbc.core.ReactiveDeleteOperation.DeleteWithQuery#matching(org.springframework.data.r2dbc.query.Query)
82+
*/
83+
@Override
84+
public TerminatingDelete matching(Query query) {
85+
86+
Assert.notNull(query, "Query must not be null");
87+
88+
return new ReactiveDeleteSupport(this.template, this.domainType, query, this.tableName);
89+
}
90+
91+
/*
92+
* (non-Javadoc)
93+
* @see org.springframework.data.r2dbc.core.ReactiveDeleteOperation.TerminatingDelete#all()
94+
*/
95+
public Mono<Integer> all() {
96+
return this.template.doDelete(this.query, this.domainType, getTableName());
97+
}
98+
99+
private String getTableName() {
100+
return this.tableName != null ? this.tableName : this.template.getTableName(this.domainType);
101+
}
102+
}
103+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2018-2020 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.r2dbc.core;
17+
18+
import reactor.core.publisher.Mono;
19+
20+
/**
21+
* The {@link ReactiveInsertOperation} interface allows creation and execution of {@code INSERT} operations in a fluent
22+
* API style.
23+
* <p>
24+
* By default,the table to operate on is derived from the initial {@link Class domainType} and can be defined there via
25+
* {@link org.springframework.data.relational.core.mapping.Table} annotation. Using {@code inTable} allows to override
26+
* the table name for the execution.
27+
*
28+
* <pre>
29+
* <code>
30+
* insert(Jedi.class)
31+
* .into("star_wars")
32+
* .using(luke);
33+
* </code>
34+
* </pre>
35+
*
36+
* @author Mark Paluch
37+
* @since 1.1
38+
*/
39+
public interface ReactiveInsertOperation {
40+
41+
/**
42+
* Begin creating an {@code INSERT} operation for given {@link Class domainType}.
43+
*
44+
* @param <T> {@link Class type} of the application domain object.
45+
* @param domainType {@link Class type} of the domain object to insert; must not be {@literal null}.
46+
* @return new instance of {@link ReactiveInsert}.
47+
* @throws IllegalArgumentException if {@link Class domainType} is {@literal null}.
48+
* @see ReactiveInsert
49+
*/
50+
<T> ReactiveInsert<T> insert(Class<T> domainType);
51+
52+
/**
53+
* Table override (optional).
54+
*/
55+
interface InsertWithTable<T> extends TerminatingInsert<T> {
56+
57+
/**
58+
* Explicitly set the {@link String name} of the table.
59+
* <p>
60+
* Skip this step to use the default table derived from the {@link Class domain type}.
61+
*
62+
* @param table {@link String name} of the table; must not be {@literal null} or empty.
63+
* @return new instance of {@link TerminatingInsert}.
64+
* @throws IllegalArgumentException if {@link String table} is {@literal null} or empty.
65+
*/
66+
TerminatingInsert<T> into(String table);
67+
}
68+
69+
/**
70+
* Trigger {@code INSERT} execution by calling one of the terminating methods.
71+
*/
72+
interface TerminatingInsert<T> {
73+
74+
/**
75+
* Insert exactly one {@link Object}.
76+
*
77+
* @param object {@link Object} to insert; must not be {@literal null}.
78+
* @return the write result for this operation.
79+
* @throws IllegalArgumentException if {@link Object} is {@literal null}.
80+
* @see Mono
81+
*/
82+
Mono<T> using(T object);
83+
}
84+
85+
/**
86+
* The {@link ReactiveInsert} interface provides methods for constructing {@code INSERT} operations in a fluent way.
87+
*/
88+
interface ReactiveInsert<T> extends InsertWithTable<T> {}
89+
90+
}

0 commit comments

Comments
 (0)