├── .gitignore
├── src
├── test
│ ├── resources
│ │ ├── container-license-acceptance.txt
│ │ └── logback-test.xml
│ └── java
│ │ └── io
│ │ └── r2dbc
│ │ └── client
│ │ ├── MockResultBearing.java
│ │ ├── BatchTest.java
│ │ ├── util
│ │ └── ChangeLogReportGenerator.java
│ │ ├── ResultBearingTest.java
│ │ ├── UpdateTest.java
│ │ ├── MssqlExample.java
│ │ ├── PostgresqlExample.java
│ │ ├── QueryTest.java
│ │ ├── MysqlExample.java
│ │ ├── H2Example.java
│ │ ├── R2dbcTest.java
│ │ ├── Example.java
│ │ └── HandleTest.java
└── main
│ └── java
│ └── io
│ └── r2dbc
│ └── client
│ ├── util
│ ├── package-info.java
│ ├── Assert.java
│ └── ReactiveUtils.java
│ ├── package-info.java
│ ├── Batch.java
│ ├── ResultBearing.java
│ ├── Update.java
│ ├── Query.java
│ ├── R2dbc.java
│ └── Handle.java
├── .mvn
└── wrapper
│ ├── maven-wrapper.jar
│ ├── maven-wrapper.properties
│ └── MavenWrapperDownloader.java
├── ci
├── builder.yml
├── release.yml
├── create-release.sh
├── release.sh
├── build.yml
├── Dockerfile
├── build.sh
└── docker-lib.sh
├── NOTICE
├── CHANGELOG
├── README.md
├── mvnw.cmd
├── mvnw
├── LICENSE
├── intellij-style.xml
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .idea
3 | target
4 | .flattened-pom.xml
5 |
--------------------------------------------------------------------------------
/src/test/resources/container-license-acceptance.txt:
--------------------------------------------------------------------------------
1 | mcr.microsoft.com/mssql/server:2017-CU12
2 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r2dbc/r2dbc-client/HEAD/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.1/apache-maven-3.6.1-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar
3 |
--------------------------------------------------------------------------------
/ci/builder.yml:
--------------------------------------------------------------------------------
1 | ---
2 | platform: linux
3 |
4 | image_resource:
5 | type: registry-image
6 | source:
7 | repository: concourse/builder
8 |
9 | inputs:
10 | - name: builder
11 |
12 | outputs:
13 | - name: image
14 |
15 | caches:
16 | - path: cache
17 |
18 | run:
19 | path: build
20 |
21 | params:
22 | CONTEXT: builder/ci
23 |
--------------------------------------------------------------------------------
/ci/release.yml:
--------------------------------------------------------------------------------
1 | ---
2 | platform: linux
3 |
4 | image_resource:
5 | type: registry-image
6 | source:
7 | repository: r2dbc/r2dbc-client
8 |
9 | inputs:
10 | - name: r2dbc-client
11 |
12 | outputs:
13 | - name: r2dbc-client-artifactory
14 |
15 | caches:
16 | - path: maven
17 |
18 | run:
19 | path: r2dbc-client/ci/release.sh
20 |
--------------------------------------------------------------------------------
/ci/create-release.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -euo pipefail
4 |
5 | RELEASE=$1
6 | SNAPSHOT=$2
7 |
8 | ./mvnw versions:set -DnewVersion=$RELEASE -DgenerateBackupPoms=false
9 | git add .
10 | git commit --message "v$RELEASE Release"
11 | git tag -s v$RELEASE -m "v$RELEASE"
12 |
13 | git reset --hard HEAD^1
14 | ./mvnw versions:set -DnewVersion=$SNAPSHOT -DgenerateBackupPoms=false
15 | git add .
16 | git commit --message "v$SNAPSHOT Development"
17 |
--------------------------------------------------------------------------------
/ci/release.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -euo pipefail
4 |
5 | source r2dbc-client/ci/docker-lib.sh
6 | start_docker "3" "3" "" ""
7 |
8 | [[ -d $PWD/maven && ! -d $HOME/.m2 ]] && ln -s $PWD/maven $HOME/.m2
9 |
10 | r2dbc_client_artifactory=$(pwd)/r2dbc-client-artifactory
11 |
12 | rm -rf $HOME/.m2/repository/io/r2dbc 2> /dev/null || :
13 |
14 | cd r2dbc-client
15 | ./mvnw deploy \
16 | -DaltDeploymentRepository=distribution::default::file://${r2dbc_client_artifactory}
17 |
--------------------------------------------------------------------------------
/ci/build.yml:
--------------------------------------------------------------------------------
1 | ---
2 | platform: linux
3 |
4 | image_resource:
5 | type: registry-image
6 | source:
7 | repository: r2dbc/r2dbc-client
8 |
9 | inputs:
10 | - name: r2dbc-client
11 | - name: r2dbc-h2-artifactory
12 | - name: r2dbc-mssql-artifactory
13 | - name: r2dbc-pool-artifactory
14 | - name: r2dbc-postgresql-artifactory
15 | - name: r2dbc-spi-artifactory
16 |
17 | outputs:
18 | - name: r2dbc-client-artifactory
19 |
20 | caches:
21 | - path: maven
22 |
23 | run:
24 | path: r2dbc-client/ci/build.sh
25 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | Reactive Relational Database Connectivity
2 |
3 | Copyright 2017-2018 the original author or authors.
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | https://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 |
--------------------------------------------------------------------------------
/ci/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8-jdk
2 |
3 | RUN apt-get update && apt-get install --no-install-recommends -y \
4 | apt-transport-https \
5 | ca-certificates \
6 | curl \
7 | gnupg2 \
8 | software-properties-common \
9 | && rm -rf /var/lib/apt/lists/*
10 |
11 | RUN curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
12 |
13 | RUN add-apt-repository \
14 | "deb [arch=amd64] https://download.docker.com/linux/debian \
15 | $(lsb_release -cs) \
16 | stable"
17 |
18 | RUN apt-get update && apt-get install --no-install-recommends -y \
19 | docker-ce \
20 | && rm -rf /var/lib/apt/lists/*
21 |
22 | RUN mkdir -p /root/.docker \
23 | && echo "{}" > /root/.docker/config.json
24 |
--------------------------------------------------------------------------------
/src/main/java/io/r2dbc/client/util/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-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 | * 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 |
17 | /**
18 | * Utility code used throughout the project.
19 | */
20 |
21 | @NonNullApi
22 | package io.r2dbc.client.util;
23 |
24 | import reactor.util.annotation.NonNullApi;
25 |
--------------------------------------------------------------------------------
/src/main/java/io/r2dbc/client/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-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 | * 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 |
17 | /**
18 | * The client Reactive Relational Database Connection API.
19 | */
20 |
21 | @NonNullApi
22 | package io.r2dbc.client;
23 |
24 | import reactor.util.annotation.NonNullApi;
25 |
--------------------------------------------------------------------------------
/CHANGELOG:
--------------------------------------------------------------------------------
1 | R2DBC Client Changelog
2 | =============================
3 |
4 | 0.8.0.RC1
5 | ------------------
6 | * Release 0.8.0.RC1 #62.
7 | * Upgrade to Reactor Dysprosium GA #61.
8 | * Upgrade to changed MySQL driver coordinates #60.
9 | * Remove repositories declaration from published pom #59.
10 | * Replace Jasync with r2dbc-mysql in the suite of database tests #56.
11 | * Upgrade to JAsync 1.0.6 and remove jcenter repository declaration #55.
12 | * Adapt to Statement.bind and Row.get by name #54.
13 | * Class javadoc of r2dbc mentions postgresql #53.
14 | * Adapt to SPI changes for TransactionIsolation #52.
15 | * testcontainers-java 1.12.0 #51.
16 | * 0.8.0.RC1 Changelog #48.
17 |
18 | 0.8.0.M8
19 | ------------------
20 | * Added MySQL Example
21 |
22 | 1.0.0.M7
23 | ------------------
24 | * Update changelong for M7 #37
25 | * ConnectionFactory Discovery #31, #32, #33
26 | * Nullability enforcement returns accurate exception #29
27 |
28 | 1.0.0.M6
29 | ------------------
30 | * MSSQL Examples #24
31 | * H2 Examples #18
32 | * Extract Examples #19
33 |
--------------------------------------------------------------------------------
/ci/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -euo pipefail
4 |
5 | source r2dbc-client/ci/docker-lib.sh
6 | start_docker "3" "3" "" ""
7 |
8 | [[ -d $PWD/maven && ! -d $HOME/.m2 ]] && ln -s $PWD/maven $HOME/.m2
9 |
10 | r2dbc_client_artifactory=$(pwd)/r2dbc-client-artifactory
11 | r2dbc_h2_artifactory=$(pwd)/r2dbc-h2-artifactory
12 | r2dbc_mssql_artifactory=$(pwd)/r2dbc-mssql-artifactory
13 | r2dbc_pool_artifactory=$(pwd)/r2dbc-pool-artifactory
14 | r2dbc_postgresql_artifactory=$(pwd)/r2dbc-postgresql-artifactory
15 | r2dbc_spi_artifactory=$(pwd)/r2dbc-spi-artifactory
16 |
17 | rm -rf $HOME/.m2/repository/io/r2dbc 2> /dev/null || :
18 |
19 | cd r2dbc-client
20 | ./mvnw deploy \
21 | -DaltDeploymentRepository=distribution::default::file://${r2dbc_client_artifactory} \
22 | -Dr2dbcH2Artifactory=file://${r2dbc_h2_artifactory} \
23 | -Dr2dbcMssqlArtifactory=file://${r2dbc_mssql_artifactory} \
24 | -Dr2dbcPoolArtifactory=file://${r2dbc_pool_artifactory} \
25 | -Dr2dbcPostgresqlArtifactory=file://${r2dbc_postgresql_artifactory} \
26 | -Dr2dbcSpiArtifactory=file://${r2dbc_spi_artifactory}
27 |
--------------------------------------------------------------------------------
/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 | %date{HH:mm:ss.SSS} %-18thread %-55logger %msg%n
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/main/java/io/r2dbc/client/util/Assert.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-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 | * 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 |
17 | package io.r2dbc.client.util;
18 |
19 | import reactor.util.annotation.Nullable;
20 |
21 | /**
22 | * Assertion library for the implementation.
23 | */
24 | public final class Assert {
25 |
26 | private Assert() {
27 | }
28 |
29 | /**
30 | * Checks that a specified object reference is not {@code null} and throws a customized {@link IllegalArgumentException} if it is.
31 | *
32 | * @param t the object reference to check for nullity
33 | * @param message the detail message to be used in the event that an {@link IllegalArgumentException} is thrown
34 | * @param the type of the reference
35 | * @return {@code t} if not {@code null}
36 | * @throws IllegalArgumentException if {@code t} is {code null}
37 | */
38 | public static T requireNonNull(@Nullable T t, String message) {
39 | if (t == null) {
40 | throw new IllegalArgumentException(message);
41 | }
42 |
43 | return t;
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/io/r2dbc/client/Batch.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-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 | * 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 |
17 | package io.r2dbc.client;
18 |
19 | import io.r2dbc.client.util.Assert;
20 | import io.r2dbc.spi.Result;
21 | import org.reactivestreams.Publisher;
22 | import reactor.core.publisher.Flux;
23 |
24 | import java.util.function.Function;
25 |
26 | /**
27 | * A wrapper for a {@link io.r2dbc.spi.Batch} providing additional convenience APIs
28 | */
29 | public final class Batch implements ResultBearing {
30 |
31 | private final io.r2dbc.spi.Batch batch;
32 |
33 | Batch(io.r2dbc.spi.Batch batch) {
34 | this.batch = Assert.requireNonNull(batch, "batch must not be null");
35 | }
36 |
37 | /**
38 | * Add a statement to this batch.
39 | *
40 | * @param sql the statement to add
41 | * @return this {@link Batch}
42 | * @throws IllegalArgumentException if {@code sql} is {@code null}
43 | */
44 | public Batch add(String sql) {
45 | Assert.requireNonNull(sql, "sql must not be null");
46 |
47 | this.batch.add(sql);
48 | return this;
49 | }
50 |
51 | public Flux mapResult(Function> mappingFunction) {
52 | Assert.requireNonNull(mappingFunction, "mappingFunction must not be null");
53 |
54 | return Flux.from(this.batch.execute())
55 | .flatMap(mappingFunction);
56 | }
57 |
58 | @Override
59 | public String toString() {
60 | return "Batch{" +
61 | "batch=" + this.batch +
62 | '}';
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This project is no longer being actively maintained.
2 |
3 | # Reactive Relational Database Connectivity Client (Archived)
4 | This project is an exploration of what a Java API for relational database access with [Reactive Streams][rs] might look like. It uses [Project Reactor][pr]. It uses [Jdbi][jd] as an inspiration.
5 |
6 | [jd]: http://jdbi.org
7 | [pr]: https://projectreactor.io
8 | [rs]: https://www.reactive-streams.org
9 |
10 | ## Examples
11 | A quick example of configuration and execution would look like:
12 |
13 | ```java
14 | PostgresqlConnectionConfiguration configuration = PostgresqlConnectionConfiguration.builder()
15 | .host("")
16 | .database("")
17 | .username("")
18 | .password("")
19 | .build();
20 |
21 | R2dbc r2dbc = new R2dbc(new PostgresqlConnectionFactory(configuration));
22 |
23 | r2dbc.inTransaction(handle ->
24 | handle.execute("INSERT INTO test VALUES ($1)", 100))
25 |
26 | .thenMany(r2dbc.inTransaction(handle ->
27 | handle.select("SELECT value FROM test")
28 | .mapResult(result -> result.map((row, rowMetadata) -> row.get("value", Integer.class)))))
29 |
30 | .subscribe(System.out::println);
31 | ```
32 |
33 | ## Maven
34 | Both milestone and snapshot artifacts (library, source, and javadoc) can be found in Maven repositories.
35 |
36 | ```xml
37 |
38 | io.r2dbc
39 | r2dbc-client
40 | 0.8.0.RC1
41 |
42 | ```
43 |
44 | Artifacts can bound found at the following repositories.
45 |
46 | ### Repositories
47 | ```xml
48 |
49 | spring-snapshots
50 | Spring Snapshots
51 | https://repo.spring.io/snapshot
52 |
53 | true
54 |
55 |
56 | ```
57 |
58 | ```xml
59 |
60 | spring-milestones
61 | Spring Milestones
62 | https://repo.spring.io/milestone
63 |
64 | false
65 |
66 |
67 | ```
68 |
69 | ## License
70 | This project is released under version 2.0 of the [Apache License][l].
71 |
72 | [l]: https://www.apache.org/licenses/LICENSE-2.0
73 |
--------------------------------------------------------------------------------
/src/test/java/io/r2dbc/client/MockResultBearing.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-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 | * 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 |
17 | package io.r2dbc.client;
18 |
19 | import io.r2dbc.client.util.Assert;
20 | import io.r2dbc.spi.Result;
21 | import org.reactivestreams.Publisher;
22 | import reactor.core.publisher.Flux;
23 |
24 | import java.util.function.Function;
25 |
26 | public final class MockResultBearing implements ResultBearing {
27 |
28 | private final Result result;
29 |
30 | private MockResultBearing(Result result) {
31 | this.result = Assert.requireNonNull(result, "result must not be null");
32 | }
33 |
34 | public static Builder builder() {
35 | return new Builder();
36 | }
37 |
38 | @Override
39 | public Flux mapResult(Function> mappingFunction) {
40 | Assert.requireNonNull(mappingFunction, "mappingFunction must not be null");
41 |
42 | return Flux.from(mappingFunction.apply(this.result));
43 | }
44 |
45 | @Override
46 | public String toString() {
47 | return "MockResultBearing{" +
48 | "result=" + this.result +
49 | '}';
50 | }
51 |
52 | public static final class Builder {
53 |
54 | private Result result;
55 |
56 | private Builder() {
57 | }
58 |
59 | public MockResultBearing build() {
60 | return new MockResultBearing(this.result);
61 | }
62 |
63 | public Builder result(Result result) {
64 | this.result = Assert.requireNonNull(result, "result must not be null");
65 | return this;
66 | }
67 |
68 | @Override
69 | public String toString() {
70 | return "Builder{" +
71 | "result=" + this.result +
72 | '}';
73 | }
74 |
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/test/java/io/r2dbc/client/BatchTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-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 | * 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 |
17 | package io.r2dbc.client;
18 |
19 | import io.r2dbc.spi.test.MockBatch;
20 | import io.r2dbc.spi.test.MockResult;
21 | import org.junit.jupiter.api.Test;
22 | import reactor.core.publisher.Mono;
23 | import reactor.test.StepVerifier;
24 |
25 | import static org.assertj.core.api.Assertions.assertThat;
26 | import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
27 |
28 | final class BatchTest {
29 |
30 | @Test
31 | void add() {
32 | MockBatch batch = MockBatch.empty();
33 |
34 | new Batch(batch)
35 | .add("test-query");
36 |
37 | assertThat(batch.getSqls()).contains("test-query");
38 | }
39 |
40 | @Test
41 | void addNoSql() {
42 | assertThatIllegalArgumentException().isThrownBy(() -> new Batch(MockBatch.empty()).add(null))
43 | .withMessage("sql must not be null");
44 | }
45 |
46 | @Test
47 | void constructorNoBatch() {
48 | assertThatIllegalArgumentException().isThrownBy(() -> new Batch(null))
49 | .withMessage("batch must not be null");
50 | }
51 |
52 | @Test
53 | void mapResult() {
54 | MockResult result = MockResult.empty();
55 |
56 | MockBatch batch = MockBatch.builder()
57 | .result(result)
58 | .build();
59 |
60 | new Batch(batch)
61 | .mapResult(actual -> {
62 | assertThat(actual).isSameAs(result);
63 | return Mono.just(1);
64 | })
65 | .as(StepVerifier::create)
66 | .expectNext(1)
67 | .verifyComplete();
68 | }
69 |
70 | @Test
71 | void mapResultNoF() {
72 | assertThatIllegalArgumentException().isThrownBy(() -> new Batch(MockBatch.empty()).mapResult(null))
73 | .withMessage("mappingFunction must not be null");
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/io/r2dbc/client/util/ReactiveUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-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 | * 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 |
17 | package io.r2dbc.client.util;
18 |
19 | import org.reactivestreams.Publisher;
20 | import reactor.core.publisher.Flux;
21 | import reactor.core.publisher.Mono;
22 |
23 | import java.util.function.Function;
24 | import java.util.function.Supplier;
25 |
26 | /**
27 | * Utilities for working with Reactive flows.
28 | */
29 | public final class ReactiveUtils {
30 |
31 | private ReactiveUtils() {
32 | }
33 |
34 | /**
35 | * Execute the {@link Publisher} provided by a {@link Supplier} and propagate the error that initiated this behavior. Typically used with {@link Flux#onErrorResume(Function)} and
36 | * {@link Mono#onErrorResume(Function)}.
37 | *
38 | * @param s a {@link Supplier} of a {@link Publisher} to execute when an error occurs
39 | * @param the type passing through the flow
40 | * @return a {@link Mono#error(Throwable)} with the original error
41 | * @see Flux#onErrorResume(Function)
42 | * @see Mono#onErrorResume(Function)
43 | */
44 | public static Function> appendError(Supplier> s) {
45 | Assert.requireNonNull(s, "s must not be null");
46 |
47 | return t ->
48 | Flux.from(s.get())
49 | .then(Mono.error(t));
50 | }
51 |
52 | /**
53 | * Convert a {@code Publisher} to a {@code Publisher} allowing for type passthrough behavior.
54 | *
55 | * @param s a {@link Supplier} of a {@link Publisher} to execute
56 | * @param the type passing through the flow
57 | * @return {@link Mono#empty()} of the appropriate type
58 | */
59 | public static Mono typeSafe(Supplier> s) {
60 | Assert.requireNonNull(s, "s must not be null");
61 |
62 | return Flux.from(s.get())
63 | .then(Mono.empty());
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/io/r2dbc/client/ResultBearing.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017-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 | * 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 |
17 | package io.r2dbc.client;
18 |
19 | import io.r2dbc.client.util.Assert;
20 | import io.r2dbc.spi.Result;
21 | import io.r2dbc.spi.Row;
22 | import io.r2dbc.spi.RowMetadata;
23 | import org.reactivestreams.Publisher;
24 | import reactor.core.publisher.Flux;
25 |
26 | import java.util.function.BiFunction;
27 | import java.util.function.Function;
28 |
29 | /**
30 | * An interface indicating that a type returns results.
31 | */
32 | public interface ResultBearing {
33 |
34 | /**
35 | * Transforms the {@link Result}s that are returned from execution.
36 | *
37 | * @param mappingFunction a {@link Function} used to transform each {@link Result} into a {@code Publisher} of values
38 | * @param the type of results
39 | * @return the values resulting from the {@link Result} transformation
40 | * @throws IllegalArgumentException if {@code mappingFunction} is {@code null}
41 | * @see #mapRow(Function)
42 | * @see #mapRow(BiFunction)
43 | */
44 | Flux mapResult(Function> mappingFunction);
45 |
46 | /**
47 | * Transforms each {@link Row} and {@link RowMetadata} pair into an object.
48 | *
49 | * @param mappingFunction a {@link BiFunction} used to transform each {@link Row} and {@link RowMetadata} pair into an object
50 | * @param the type of results
51 | * @return the values resulting from the {@link Row} and {@link RowMetadata} transformation
52 | * @throws IllegalArgumentException if {@code mappingFunction} is {@code null}
53 | */
54 | default Flux mapRow(BiFunction mappingFunction) {
55 | Assert.requireNonNull(mappingFunction, "mappingFunction must not be null");
56 |
57 | return mapResult(result -> result.map(mappingFunction));
58 | }
59 |
60 | /**
61 | * Transforms each {@link Row} into an object.
62 | *
63 | * @param mappingFunction a {@link Function} used to transform each {@link Row} into an object
64 | * @param the type of the results
65 | * @return the values resulting from the {@link Row} transformation
66 | * @throws IllegalArgumentException if {@code mappingFunction} is {@code null}
67 | */
68 | default Flux mapRow(Function mappingFunction) {
69 | Assert.requireNonNull(mappingFunction, "mappingFunction must not be null");
70 |
71 | return mapRow((row, rowMetadata) -> mappingFunction.apply(row));
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/test/java/io/r2dbc/client/util/ChangeLogReportGenerator.java:
--------------------------------------------------------------------------------
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 | * 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 |
17 | package io.r2dbc.client.util;
18 |
19 | import com.jayway.jsonpath.JsonPath;
20 | import net.minidev.json.JSONArray;
21 | import org.springframework.hateoas.IanaLinkRelations;
22 | import org.springframework.hateoas.Links;
23 | import org.springframework.http.HttpEntity;
24 | import org.springframework.http.HttpHeaders;
25 | import org.springframework.web.reactive.function.client.WebClient;
26 |
27 | import java.time.Duration;
28 | import java.util.Iterator;
29 | import java.util.List;
30 |
31 | /**
32 | * Changelog report generator.
33 | */
34 | final class ChangeLogReportGenerator {
35 |
36 | private static final int MILESTONE_ID = 6;
37 | private static final String URI_TEMPLATE = "https://api.github.com/repos/r2dbc/r2dbc-client/issues?milestone={id}&state=closed";
38 |
39 | public static void main(String... args) {
40 |
41 | /*
42 | * If you run into github rate limiting issues, you can always use a Github Personal Token by adding
43 | * {@code .header(HttpHeaders.AUTHORIZATION, "token your-github-token")} to the webClient call.
44 | */
45 |
46 | WebClient webClient = WebClient.create();
47 |
48 | HttpEntity response = webClient //
49 | .get().uri(URI_TEMPLATE, MILESTONE_ID) //
50 | .exchange() //
51 | .flatMap(clientResponse -> clientResponse.toEntity(String.class)) //
52 | .block(Duration.ofSeconds(10));
53 |
54 | boolean keepChecking = true;
55 | boolean printHeader = true;
56 |
57 | while (keepChecking) {
58 |
59 | readPage(response.getBody(), printHeader);
60 | printHeader = false;
61 |
62 | List linksInHeader = response.getHeaders().get(HttpHeaders.LINK);
63 | Links links = linksInHeader == null ? Links.NONE : Links.parse(linksInHeader.get(0));
64 |
65 | if (links.getLink(IanaLinkRelations.NEXT).isPresent()) {
66 |
67 | response = webClient //
68 | .get().uri(links.getRequiredLink(IanaLinkRelations.NEXT).expand().getHref()) //
69 | .exchange() //
70 | .flatMap(clientResponse -> clientResponse.toEntity(String.class)) //
71 | .block(Duration.ofSeconds(10));
72 |
73 | } else {
74 | keepChecking = false;
75 | }
76 | }
77 | }
78 |
79 | private static void readPage(String content, boolean header) {
80 |
81 | JsonPath titlePath = JsonPath.compile("$[*].title");
82 | JsonPath idPath = JsonPath.compile("$[*].number");
83 |
84 | JSONArray titles = titlePath.read(content);
85 | Iterator