Skip to content

Commit 08d91bd

Browse files
mp911deschauder
authored andcommitted
#75 - Add anonymous indexed bind markers.
Anonymous indexed bind markers come with a static placeholder symbol for all parameter occurrences and they are bound by index. Original pull request: #84.
1 parent 2f5d11b commit 08d91bd

File tree

5 files changed

+195
-44
lines changed

5 files changed

+195
-44
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2019 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+
* http://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.dialect;
17+
18+
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
19+
20+
/**
21+
* Anonymous, index-based bind marker using a static placeholder. Instances are bound by the ordinal position ordered by
22+
* the appearance of the placeholder. This implementation creates indexed bind markers using an anonymous placeholder
23+
* that correlates with an index.
24+
*
25+
* @author Mark Paluch
26+
*/
27+
class AnonymousBindMarkers implements BindMarkers {
28+
29+
private static final AtomicIntegerFieldUpdater<AnonymousBindMarkers> COUNTER_INCREMENTER = AtomicIntegerFieldUpdater
30+
.newUpdater(AnonymousBindMarkers.class, "counter");
31+
32+
// access via COUNTER_INCREMENTER
33+
@SuppressWarnings("unused") private volatile int counter;
34+
35+
private final String placeholder;
36+
37+
/**
38+
* Creates a new {@link AnonymousBindMarkers} instance given {@code placeholder}.
39+
*
40+
* @param placeholder parameter bind marker.
41+
*/
42+
AnonymousBindMarkers(String placeholder) {
43+
this.counter = 0;
44+
this.placeholder = placeholder;
45+
}
46+
47+
/*
48+
* (non-Javadoc)
49+
* @see org.springframework.data.r2dbc.dialect.BindMarkers#next()
50+
*/
51+
@Override
52+
public BindMarker next() {
53+
54+
int index = COUNTER_INCREMENTER.getAndIncrement(this);
55+
56+
return new IndexedBindMarker(placeholder, index);
57+
}
58+
59+
}

src/main/java/org/springframework/data/r2dbc/dialect/BindMarkersFactory.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,22 @@ static BindMarkersFactory indexed(String prefix, int beginWith) {
4343
return () -> new IndexedBindMarkers(prefix, beginWith);
4444
}
4545

46+
/**
47+
* Creates anonymous, index-based bind marker using a static placeholder. Instances are bound by the ordinal position
48+
* ordered by the appearance of the placeholder. This implementation creates indexed bind markers using an anonymous
49+
* placeholder that correlates with an index.
50+
*
51+
* @param placeholder parameter placeholder.
52+
* @return a {@link BindMarkersFactory} using {@code placeholder}.
53+
* @see io.r2dbc.spi.Statement#bindNull(int, Class)
54+
* @see io.r2dbc.spi.Statement#bind(int, Object)
55+
*/
56+
static BindMarkersFactory anonymous(String placeholder) {
57+
58+
Assert.hasText(placeholder, "Placeholder must not be empty!");
59+
return () -> new AnonymousBindMarkers(placeholder);
60+
}
61+
4662
/**
4763
* Create named {@link BindMarkers} using identifiers to bind parameters. Named bind markers can support
4864
* {@link BindMarkers#next(String) name hints}. If no {@link BindMarkers#next(String) hint} is given, named bind
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2019 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+
* http://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.dialect;
17+
18+
import io.r2dbc.spi.Statement;
19+
20+
/**
21+
* A single indexed bind marker.
22+
*/
23+
class IndexedBindMarker implements BindMarker {
24+
25+
private final String placeholder;
26+
27+
private int index;
28+
29+
IndexedBindMarker(String placeholder, int index) {
30+
this.placeholder = placeholder;
31+
this.index = index;
32+
}
33+
34+
/*
35+
* (non-Javadoc)
36+
* @see org.springframework.data.r2dbc.dialect.BindMarker#getPlaceholder()
37+
*/
38+
@Override
39+
public String getPlaceholder() {
40+
return placeholder;
41+
}
42+
43+
/*
44+
* (non-Javadoc)
45+
* @see org.springframework.data.r2dbc.dialect.BindMarker#bindValue(io.r2dbc.spi.Statement, java.lang.Object)
46+
*/
47+
@Override
48+
public void bind(Statement statement, Object value) {
49+
statement.bind(this.index, value);
50+
}
51+
52+
/*
53+
* (non-Javadoc)
54+
* @see org.springframework.data.r2dbc.dialect.BindMarker#bindNull(io.r2dbc.spi.Statement, java.lang.Class)
55+
*/
56+
@Override
57+
public void bindNull(Statement statement, Class<?> valueType) {
58+
statement.bindNull(this.index, valueType);
59+
}
60+
}
Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package org.springframework.data.r2dbc.dialect;
22

3-
import io.r2dbc.spi.Statement;
4-
53
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
64

75
/**
@@ -45,46 +43,4 @@ public BindMarker next() {
4543

4644
return new IndexedBindMarker(prefix + "" + (index + offset), index);
4745
}
48-
49-
/**
50-
* A single indexed bind marker.
51-
*/
52-
static class IndexedBindMarker implements BindMarker {
53-
54-
private final String placeholder;
55-
56-
private int index;
57-
58-
IndexedBindMarker(String placeholder, int index) {
59-
this.placeholder = placeholder;
60-
this.index = index;
61-
}
62-
63-
/*
64-
* (non-Javadoc)
65-
* @see org.springframework.data.r2dbc.dialect.BindMarker#getPlaceholder()
66-
*/
67-
@Override
68-
public String getPlaceholder() {
69-
return placeholder;
70-
}
71-
72-
/*
73-
* (non-Javadoc)
74-
* @see org.springframework.data.r2dbc.dialect.BindMarker#bindValue(io.r2dbc.spi.Statement, java.lang.Object)
75-
*/
76-
@Override
77-
public void bind(Statement statement, Object value) {
78-
statement.bind(this.index, value);
79-
}
80-
81-
/*
82-
* (non-Javadoc)
83-
* @see org.springframework.data.r2dbc.dialect.BindMarker#bindNull(io.r2dbc.spi.Statement, java.lang.Class)
84-
*/
85-
@Override
86-
public void bindNull(Statement statement, Class<?> valueType) {
87-
statement.bindNull(this.index, valueType);
88-
}
89-
}
9046
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2019 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+
* http://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.dialect;
17+
18+
import static org.assertj.core.api.Assertions.*;
19+
import static org.mockito.Mockito.*;
20+
21+
import io.r2dbc.spi.Statement;
22+
23+
import org.junit.Test;
24+
25+
/**
26+
* Unit tests for {@link AnonymousBindMarkers}.
27+
*
28+
* @author Mark Paluch
29+
*/
30+
public class AnonymousBindMarkersUnitTests {
31+
32+
@Test // gh-75
33+
public void shouldCreateNewBindMarkers() {
34+
35+
BindMarkersFactory factory = BindMarkersFactory.anonymous("?");
36+
37+
BindMarkers bindMarkers1 = factory.create();
38+
BindMarkers bindMarkers2 = factory.create();
39+
40+
assertThat(bindMarkers1.next().getPlaceholder()).isEqualTo("?");
41+
assertThat(bindMarkers2.next().getPlaceholder()).isEqualTo("?");
42+
}
43+
44+
@Test // gh-75
45+
public void shouldBindByIndex() {
46+
47+
Statement statement = mock(Statement.class);
48+
49+
BindMarkers bindMarkers = BindMarkersFactory.anonymous("?").create();
50+
51+
BindMarker first = bindMarkers.next();
52+
BindMarker second = bindMarkers.next();
53+
54+
second.bind(statement, "foo");
55+
first.bindNull(statement, Object.class);
56+
57+
verify(statement).bindNull(0, Object.class);
58+
verify(statement).bind(1, "foo");
59+
}
60+
}

0 commit comments

Comments
 (0)