Skip to content

Commit

Permalink
Merge pull request #42 from codenotary/sql_apis
Browse files Browse the repository at this point in the history
Sql apis
  • Loading branch information
jeroiraz committed Nov 29, 2022
2 parents d17d48d + 080e8e9 commit c4996d9
Show file tree
Hide file tree
Showing 13 changed files with 543 additions and 38 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/gradle.yml
Expand Up @@ -20,6 +20,8 @@ jobs:
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Start immudb container
run: docker run -d --health-cmd "immuadmin status" --health-interval 10s --health-timeout 5s --health-retries 5 -p 3322:3322 codenotary/immudb:1.4.0
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
Expand Down
32 changes: 2 additions & 30 deletions build.gradle
Expand Up @@ -120,32 +120,6 @@ dependencies {
implementation 'javax.annotation:javax.annotation-api:1.2-b01'
}

task immudbStart {
// INFO: You can disable this logic (comment these lines below within this task)
// if you want to use an existing immudb server, without starting and stopping
// the locally used immudb version (stored in `immudb` directory and controlled
// through the scripts). Just make sure immudb server has the proper version.
ProcessBuilder pb = new ProcessBuilder()
pb.command("/bin/bash", "immudb/clean.sh")
Process procClean = pb.start()
procClean.waitFor()

pb = new ProcessBuilder()
pb.command("/bin/bash", "immudb/start.sh")
Process proc = pb.start()
proc.waitFor(15, TimeUnit.SECONDS)
}

task immudbStop(type: Exec) {
// INFO: You can disable this logic (comment these lines below within this task)
// if you want to use an existing immudb server, without starting and stopping
// the locally used immudb version (stored in `immudb` directory and controlled
// through the scripts). Just make sure immudb server has the proper version.
workingDir 'immudb'
commandLine './clean.sh'
}


idea {
module {
sourceDirs += file("${projectDir}/src/generated/main/java")
Expand All @@ -166,9 +140,7 @@ test {
}
}

test.dependsOn immudbStart

test.finalizedBy([jacocoTestReport, immudbStop])
test.finalizedBy([jacocoTestReport])

task integrationTest(type: Test) {
testClassesDirs = sourceSets.integrationTest.output.classesDirs
Expand Down Expand Up @@ -259,4 +231,4 @@ publishing {
signing {
sign publishing.publications.gpr
}
}
}
129 changes: 126 additions & 3 deletions src/main/java/io/codenotary/immudb4j/ImmuClient.java
Expand Up @@ -20,13 +20,19 @@
import io.codenotary.immudb.ImmuServiceGrpc;
import io.codenotary.immudb.ImmudbProto;
import io.codenotary.immudb.ImmudbProto.Chunk;
import io.codenotary.immudb.ImmudbProto.NamedParam;
import io.codenotary.immudb.ImmudbProto.NewTxResponse;
import io.codenotary.immudb.ImmudbProto.ScanRequest;
import io.codenotary.immudb.ImmudbProto.Score;
import io.codenotary.immudb.ImmudbProto.TxMode;
import io.codenotary.immudb4j.basics.LatchHolder;
import io.codenotary.immudb4j.crypto.CryptoUtils;
import io.codenotary.immudb4j.crypto.DualProof;
import io.codenotary.immudb4j.crypto.InclusionProof;
import io.codenotary.immudb4j.exceptions.*;
import io.codenotary.immudb4j.sql.SQLException;
import io.codenotary.immudb4j.sql.SQLQueryResult;
import io.codenotary.immudb4j.sql.SQLValue;
import io.codenotary.immudb4j.user.Permission;
import io.codenotary.immudb4j.user.User;
import io.grpc.ManagedChannel;
Expand All @@ -42,9 +48,10 @@
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -205,6 +212,122 @@ public synchronized ImmuState currentState() throws VerificationException {
return immuState;
}

//
// ========== SQL ==========
//

public synchronized void beginTransaction() throws SQLException {
if (session == null) {
throw new IllegalStateException("no open session");
}

if (session.getTransactionID() != null) {
throw new IllegalStateException("transaction already initiated");
}

final ImmudbProto.NewTxRequest req = ImmudbProto.NewTxRequest.newBuilder()
.setMode(TxMode.ReadWrite)
.build();

final NewTxResponse res = blockingStub.newTx(req);

session.setTransactionID(res.getTransactionID());
}

public synchronized void commitTransaction() throws SQLException {
if (session == null) {
throw new IllegalStateException("no open session");
}

if (session.getTransactionID() == null) {
throw new IllegalStateException("no transaction initiated");
}

blockingStub.commit(Empty.getDefaultInstance());

session.setTransactionID( null);
}

public synchronized void rollbackTransaction() throws SQLException {
if (session == null) {
throw new IllegalStateException("no open session");
}

if (session.getTransactionID() == null) {
throw new IllegalStateException("no transaction initiated");
}

blockingStub.rollback(Empty.getDefaultInstance());

session.setTransactionID(null);
}

public void sqlExec(String stmt, SQLValue... params) throws SQLException {
sqlExec(stmt, sqlNameParams(params));
}

public synchronized void sqlExec(String stmt, Map<String, SQLValue> params) throws SQLException {
if (session == null) {
throw new IllegalStateException("no open session");
}

if (session.getTransactionID() == null) {
throw new IllegalStateException("no transaction initiated");
}

final ImmudbProto.SQLExecRequest req = ImmudbProto.SQLExecRequest.newBuilder()
.setSql(stmt)
.addAllParams(sqlEncodeParams(params))
.build();

blockingStub.txSQLExec(req);
}

public SQLQueryResult sqlQuery(String stmt, SQLValue... params) throws SQLException {
return sqlQuery(stmt, sqlNameParams(params));
}

public synchronized SQLQueryResult sqlQuery(String stmt, Map<String, SQLValue> params) throws SQLException {
if (session == null) {
throw new IllegalStateException("no open session");
}

if (session.getTransactionID() == null) {
throw new IllegalStateException("no transaction initiated");
}

final ImmudbProto.SQLQueryRequest req = ImmudbProto.SQLQueryRequest.newBuilder()
.setSql(stmt)
.addAllParams(sqlEncodeParams(params))
.build();

return new SQLQueryResult(blockingStub.txSQLQuery(req));
}

private Map<String, SQLValue> sqlNameParams(SQLValue... params) {
final Map<String, SQLValue> nparams = new HashMap<>(params.length);

for (int i = 1; i <= params.length; i++) {
nparams.put("param" + i, params[i-1]);
}

return nparams;
}

private Iterable<NamedParam> sqlEncodeParams(Map<String, SQLValue> params) {
List<ImmudbProto.NamedParam> nparams = new ArrayList<>();

for (Map.Entry<String, SQLValue> p : params.entrySet()) {
nparams.add(NamedParam.newBuilder()
.setName(p.getKey())
.setValue(p.getValue().asProtoSQLValue())
.build()
);
}

return nparams;
}

//
// ========== DATABASE ==========
//
Expand Down Expand Up @@ -1103,12 +1226,12 @@ public synchronized List<Tx> txScanAll(long initialTxId) {
return buildList(txList);
}

public synchronized List<Tx> txScanAll(long initialTxId, int limit, boolean desc) {
public synchronized List<Tx> txScanAll(long initialTxId, boolean desc, int limit) {
final ImmudbProto.TxScanRequest req = ImmudbProto.TxScanRequest
.newBuilder()
.setInitialTx(initialTxId)
.setDesc(desc)
.setLimit(limit)
.setDesc(desc)
.build();

final ImmudbProto.TxList txList = blockingStub.txScan(req);
Expand Down
@@ -1,11 +1,32 @@
package io.codenotary.immudb4j;
/*
Copyright 2022 CodeNotary, Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
import io.grpc.*;
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package io.codenotary.immudb4j;

import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.ClientCall;
import io.grpc.ClientInterceptor;
import io.grpc.ForwardingClientCall;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;

public class ImmudbAuthRequestInterceptor implements ClientInterceptor {

private static final String SESSION_ID = "sessionid";
private static final String TRANSACTION_ID = "transactionid";

private final ImmuClient client;

Expand All @@ -26,6 +47,10 @@ public void start(Listener<RespT> responseListener, Metadata headers) {

if (session != null) {
headers.put(Metadata.Key.of(SESSION_ID, Metadata.ASCII_STRING_MARSHALLER), session.getSessionID());

if (session.getTransactionID() != null) {
headers.put(Metadata.Key.of(TRANSACTION_ID, Metadata.ASCII_STRING_MARSHALLER), session.getTransactionID());
}
}

super.start(responseListener, headers);
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/io/codenotary/immudb4j/KV.java
@@ -1,3 +1,18 @@
/*
Copyright 2022 CodeNotary, Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package io.codenotary.immudb4j;

import io.codenotary.immudb4j.crypto.CryptoUtils;
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/io/codenotary/immudb4j/KVPair.java
@@ -1,3 +1,18 @@
/*
Copyright 2022 CodeNotary, Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package io.codenotary.immudb4j;

/**
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/io/codenotary/immudb4j/Session.java
Expand Up @@ -20,6 +20,8 @@ public class Session {
private String sessionID;
private String database;

private String transactionID;

public Session(String sessionID, String database) {
this.sessionID = sessionID;
this.database = database;
Expand All @@ -33,4 +35,11 @@ public String getDatabase() {
return database;
}

public String getTransactionID() {
return transactionID;
}

public void setTransactionID(String transactionID) {
this.transactionID = transactionID;
}
}
Expand Up @@ -16,7 +16,6 @@
package io.codenotary.immudb4j.crypto;

import io.codenotary.immudb.ImmudbProto;
import io.codenotary.immudb4j.Utils;

public class InclusionProof {

Expand Down
25 changes: 25 additions & 0 deletions src/main/java/io/codenotary/immudb4j/sql/SQLException.java
@@ -0,0 +1,25 @@

/*
Copyright 2022 CodeNotary, Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package io.codenotary.immudb4j.sql;

public class SQLException extends Exception {

public SQLException(String message) {
super(message);
}

}

0 comments on commit c4996d9

Please sign in to comment.