Skip to content

feat: implement row columnCount, columnName and columnType methods #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions libsql/src/androidTest/java/tech/turso/libsql/LibsqlTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;

Expand Down Expand Up @@ -40,6 +41,46 @@ public void failNestedTransaction() {
}
}

@Test
public void queryColumnCount() {
try (var db = Libsql.open(":memory:");
var conn = db.connect()) {
try (var rows = conn.query("select 1 as foo, 2 as bar")) {
assertEquals(2, rows.getColumnCount());

}
}
}


@Test
public void queryColumnName() {
try (var db = Libsql.open(":memory:");
var conn = db.connect()) {
try (var rows = conn.query("select 1 as foo, 2 as bar")) {
assertEquals("foo", rows.columnNames((0)));
assertEquals("bar", rows.columnNames((1)));
assertNull(rows.columnNames((2)));

}
}
}

@Test
public void queryColumnType() {
try (var db = Libsql.open(":memory:");
var conn = db.connect()) {
try (var rows = conn.query("select 1 as integer, 3.14 as real, 'text' as text, X'68656C6C6F' as blob, null as nullValue")) {
assertEquals(ValueType.Integer, rows.columnType((0)));
assertEquals(ValueType.Real, rows.columnType((1)));
assertEquals(ValueType.Text, rows.columnType((2)));
assertEquals(ValueType.Blob, rows.columnType((3)));
assertEquals(ValueType.Null, rows.columnType((4)));
assertNull(rows.columnNames((5)));
}
}
}

@Test
public void queryEmptyParameters() {
try (var db = Libsql.open(":memory:");
Expand Down
17 changes: 17 additions & 0 deletions libsql/src/main/kotlin/tech/turso/libsql/Rows.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ class Rows internal constructor(private var inner: Long) : AutoCloseable, Iterab
require(this.inner != 0L) { "Attempted to construct a Rows with a null pointer" }
}

val columnCount: Int
get() = nativeColumnCount(inner)

fun columnNames(idx: Int): String? {
return nativeColumnName(this.inner, idx)
}

fun columnType(idx: Int): ValueType? {
return ValueType.fromInt(nativeColumnType(this.inner ,idx))
}

fun next(): Row {
val buf: ByteArray = nativeNext(this.inner)
return ProtoRow.parseFrom(buf).valuesList.map {
Expand All @@ -32,6 +43,12 @@ class Rows internal constructor(private var inner: Long) : AutoCloseable, Iterab

override fun iterator(): Iterator<Row> = RowsIterator(this)

private external fun nativeColumnCount(rows: Long): Int

private external fun nativeColumnName(rows: Long, idx: Int): String?

private external fun nativeColumnType(rows: Long, idx: Int): Int

private external fun nativeNext(rows: Long): ByteArray

private external fun nativeClose(rows: Long)
Expand Down
15 changes: 15 additions & 0 deletions libsql/src/main/kotlin/tech/turso/libsql/ValueType.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package tech.turso.libsql

enum class ValueType(val value: Int) {
Integer(1),
Real(2),
Text(3),
Blob(4),
Null(5);

companion object {
fun fromInt(value: Int): ValueType? {
return entries.find { it.value == value }
}
}
}
40 changes: 39 additions & 1 deletion libsql/src/main/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use jni::{
objects::{JByteArray, JClass, JString},
sys::{jboolean, jbyteArray, jlong},
sys::{jboolean, jbyteArray, jint, jlong, jstring},
JNIEnv,
};
use jni_fn::jni_fn;
Expand Down Expand Up @@ -283,6 +283,44 @@ pub fn nativeClose(_: JNIEnv, _: JClass, conn: jlong) {
drop(unsafe { Box::from_raw(conn as *mut Connection) });
}

#[jni_fn("tech.turso.libsql.Rows")]
pub fn nativeColumnCount(_: JNIEnv, _: JClass, rows: jlong) -> jint {
let rows = ManuallyDrop::new(unsafe { Box::from_raw(rows as *mut Rows) });
return rows.column_count();
}

#[jni_fn("tech.turso.libsql.Rows")]
pub fn nativeColumnName(mut env: JNIEnv, _: JClass, rows: jlong, idx: jint) -> jstring {
let result = (|| -> anyhow::Result<Option<JString>> {
let rows = ManuallyDrop::new(unsafe { Box::from_raw(rows as *mut Rows) });
if let Some(name) = rows.column_name(idx) {
Ok(Some(env.new_string(name)?))
} else {
Ok(None)
}
})();

match result {
Ok(Some(jstr)) => jstr.into_raw(),
Ok(None) => ptr::null_mut(),
Err(err) => {
env.throw(err.to_string()).unwrap();
ptr::null_mut()
}
}
}

#[jni_fn("tech.turso.libsql.Rows")]
pub fn nativeColumnType(mut env: JNIEnv, _: JClass, rows: jlong, idx: jint) -> jint {
let rows = ManuallyDrop::new(unsafe { Box::from_raw(rows as *mut Rows) });
match rows.column_type(idx) {
Ok(v) => v as jint,
Err(err) => {
env.throw(err.to_string()).unwrap();
-1
}
}
}
#[jni_fn("tech.turso.libsql.Rows")]
pub fn nativeNext(mut env: JNIEnv, _: JClass, rows: jlong) -> jbyteArray {
match (|| -> anyhow::Result<JByteArray> {
Expand Down