Add basic tuple and value fetching from queries.
Add safeties for =destroy hooks. FossilOrigin-Name: 2fae5297a0d0598cc3580777688b4f4307de008d4f379d2fb224c8a74cb9b708
This commit is contained in:
parent
1ed442a68a
commit
7850a79372
14 changed files with 237 additions and 17 deletions
|
|
@ -13,14 +13,18 @@ else:
|
||||||
include "kuzu/0.8.2.nim"
|
include "kuzu/0.8.2.nim"
|
||||||
|
|
||||||
import
|
import
|
||||||
std/strformat
|
std/strformat,
|
||||||
|
std/strutils
|
||||||
|
|
||||||
|
# Order very much matters here pre Nim 3.0 multi-pass compiling.
|
||||||
include
|
include
|
||||||
"kuzu/constants.nim",
|
"kuzu/constants.nim",
|
||||||
"kuzu/types.nim",
|
"kuzu/types.nim",
|
||||||
"kuzu/config.nim",
|
"kuzu/config.nim",
|
||||||
"kuzu/database.nim",
|
"kuzu/database.nim",
|
||||||
"kuzu/connection.nim",
|
"kuzu/connection.nim",
|
||||||
|
"kuzu/value.nim",
|
||||||
|
"kuzu/tuple.nim",
|
||||||
"kuzu/queries.nim"
|
"kuzu/queries.nim"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,16 @@
|
||||||
|
|
||||||
proc `=destroy`*( conn: KuzuConnectionObj ) =
|
proc `=destroy`*( conn: KuzuConnectionObj ) =
|
||||||
## Graceful cleanup for open connection handles.
|
## Graceful cleanup for open connection handles.
|
||||||
|
if conn.valid:
|
||||||
kuzu_connection_destroy( addr conn.handle )
|
kuzu_connection_destroy( addr conn.handle )
|
||||||
|
|
||||||
|
|
||||||
proc connect*( db: KuzuDB ): KuzuConnection =
|
proc connect*( db: KuzuDatabase ): KuzuConnection =
|
||||||
## Connect to a database.
|
## Connect to a database.
|
||||||
result = new KuzuConnection
|
result = new KuzuConnection
|
||||||
var rv = kuzu_connection_init( addr db.handle, addr result.handle )
|
if kuzu_connection_init( addr db.handle, addr result.handle ) == KuzuSuccess:
|
||||||
if rv != KuzuSuccess:
|
result.valid = true
|
||||||
|
else:
|
||||||
raise newException( KuzuException, "Unable to connect to the database." )
|
raise newException( KuzuException, "Unable to connect to the database." )
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,23 @@
|
||||||
# vim: set et sta sw=4 ts=4 :
|
# vim: set et sta sw=4 ts=4 :
|
||||||
|
|
||||||
proc `=destroy`*( db: KuzuDBObj ) =
|
proc `=destroy`*( db: KuzuDatabaseObj ) =
|
||||||
## Graceful cleanup for an open DB handle when it goes out of scope.
|
## Graceful cleanup for an open DB handle when it goes out of scope.
|
||||||
|
if db.valid:
|
||||||
kuzu_database_destroy( addr db.handle )
|
kuzu_database_destroy( addr db.handle )
|
||||||
|
|
||||||
|
|
||||||
proc newKuzuDatabase*( path="", config=kuzuConfig() ): KuzuDB =
|
proc newKuzuDatabase*( path="", config=kuzuConfig() ): KuzuDatabase =
|
||||||
## Create a new Kuzu database handle. Creates an in-memory
|
## Create a new Kuzu database handle. Creates an in-memory
|
||||||
## database by default, but writes to disk if a +path+ is supplied.
|
## database by default, but writes to disk if a +path+ is supplied.
|
||||||
|
|
||||||
result = new KuzuDB
|
result = new KuzuDatabase
|
||||||
result.config = config
|
result.config = config
|
||||||
result.path = if path != "" and path != ":memory:": path else: "(in-memory)"
|
result.path = if path != "" and path != ":memory:": path else: "(in-memory)"
|
||||||
result.handle = kuzu_database()
|
result.handle = kuzu_database()
|
||||||
|
|
||||||
var rv = kuzu_database_init( path, config, addr result.handle )
|
if kuzu_database_init( path, config, addr result.handle ) == KuzuSuccess:
|
||||||
if rv != KuzuSuccess:
|
result.valid = true
|
||||||
|
else:
|
||||||
raise newException( KuzuException, "Unable to open database." )
|
raise newException( KuzuException, "Unable to open database." )
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
proc `=destroy`*( query: KuzuQueryResultObj ) =
|
proc `=destroy`*( query: KuzuQueryResultObj ) =
|
||||||
## Graceful cleanup for out of scope query objects.
|
## Graceful cleanup for out of scope query objects.
|
||||||
|
if query.valid:
|
||||||
kuzu_query_result_destroy( addr query.handle )
|
kuzu_query_result_destroy( addr query.handle )
|
||||||
kuzu_query_summary_destroy( addr query.summary )
|
kuzu_query_summary_destroy( addr query.summary )
|
||||||
|
|
||||||
|
|
@ -9,15 +10,39 @@ proc `=destroy`*( query: KuzuQueryResultObj ) =
|
||||||
proc query*( conn: KuzuConnection, query: string ): KuzuQueryResult =
|
proc query*( conn: KuzuConnection, query: string ): KuzuQueryResult =
|
||||||
## Perform a database +query+ and return the result.
|
## Perform a database +query+ and return the result.
|
||||||
result = new KuzuQueryResult
|
result = new KuzuQueryResult
|
||||||
var rv = kuzu_connection_query( addr conn.handle, query, addr result.handle )
|
if kuzu_connection_query( addr conn.handle, query, addr result.handle ) == KuzuSuccess:
|
||||||
if rv == KuzuSuccess:
|
|
||||||
discard kuzu_query_result_get_query_summary( addr result.handle, addr result.summary )
|
discard kuzu_query_result_get_query_summary( addr result.handle, addr result.summary )
|
||||||
result.num_columns = kuzu_query_result_get_num_columns( addr result.handle )
|
result.num_columns = kuzu_query_result_get_num_columns( addr result.handle )
|
||||||
result.num_tuples = kuzu_query_result_get_num_tuples( addr result.handle )
|
result.num_tuples = kuzu_query_result_get_num_tuples( addr result.handle )
|
||||||
result.compile_time = kuzu_query_summary_get_compiling_time( addr result.summary )
|
result.compile_time = kuzu_query_summary_get_compiling_time( addr result.summary )
|
||||||
result.execution_time = kuzu_query_summary_get_execution_time( addr result.summary )
|
result.execution_time = kuzu_query_summary_get_execution_time( addr result.summary )
|
||||||
|
result.valid = true
|
||||||
else:
|
else:
|
||||||
var err = kuzu_query_result_get_error_message( addr result.handle )
|
var err = kuzu_query_result_get_error_message( addr result.handle )
|
||||||
raise newException( KuzuQueryException, &"Error running query: {err}" )
|
raise newException( KuzuQueryException, &"Error running query: {err}" )
|
||||||
|
|
||||||
|
|
||||||
|
proc `$`*( query: KuzuQueryResult ): string =
|
||||||
|
## Return the entire result set as a string.
|
||||||
|
result = $kuzu_query_result_to_string( addr query.handle )
|
||||||
|
|
||||||
|
|
||||||
|
proc hasNext*( query: KuzuQueryResult ): bool =
|
||||||
|
## Returns +true+ if there are more tuples to be consumed.
|
||||||
|
result = kuzu_query_result_has_next( addr query.handle )
|
||||||
|
|
||||||
|
|
||||||
|
proc getNext*( query: KuzuQueryResult ): KuzuFlatTuple =
|
||||||
|
result = new KuzuFlatTuple
|
||||||
|
if kuzu_query_result_get_next( addr query.handle, addr result.handle ) == KuzuSuccess:
|
||||||
|
result.valid = true
|
||||||
|
result.num_columns = query.num_columns
|
||||||
|
else:
|
||||||
|
raise newException( KuzuQueryException, &"Unable to fetch next tuple." )
|
||||||
|
|
||||||
|
|
||||||
|
iterator items*( query: KuzuQueryResult ): KuzuFlatTuple =
|
||||||
|
## Iterate available tuples, yielding to the block.
|
||||||
|
while query.hasNext:
|
||||||
|
yield query.getNext
|
||||||
|
|
||||||
|
|
|
||||||
23
src/kuzu/tuple.nim
Normal file
23
src/kuzu/tuple.nim
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# vim: set et sta sw=4 ts=4 :
|
||||||
|
|
||||||
|
proc `=destroy`*( tpl: KuzuFlatTupleObj ) =
|
||||||
|
## Graceful cleanup for out of scope tuples.
|
||||||
|
if tpl.valid:
|
||||||
|
kuzu_flat_tuple_destroy( addr tpl.handle )
|
||||||
|
|
||||||
|
|
||||||
|
proc `$`*( tpl: KuzuFlatTuple ): string =
|
||||||
|
## Stringify a tuple.
|
||||||
|
result = $kuzu_flat_tuple_to_string( addr tpl.handle )
|
||||||
|
result.removeSuffix( "\n" )
|
||||||
|
|
||||||
|
|
||||||
|
proc `[]`*( tpl: KuzuFlatTuple, idx: int ): KuzuValue =
|
||||||
|
## Returns a KuzuValue at the given +idx+.
|
||||||
|
result = new KuzuValue
|
||||||
|
if kuzu_flat_tuple_get_value( addr tpl.handle, idx.uint64, addr result.handle ) == KuzuSuccess:
|
||||||
|
result.valid = true
|
||||||
|
else:
|
||||||
|
raise newException( KuzuIndexException,
|
||||||
|
&"Unable to fetch tuple value at idx {idx}. ({tpl.num_columns} column(s).)" )
|
||||||
|
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
# vim: set et sta sw=4 ts=4 :
|
# vim: set et sta sw=4 ts=4 :
|
||||||
|
|
||||||
type
|
type
|
||||||
KuzuDBObj = object
|
KuzuDatabaseObj = object
|
||||||
handle*: kuzu_database
|
handle*: kuzu_database
|
||||||
path*: string
|
path*: string
|
||||||
config*: kuzu_system_config
|
config*: kuzu_system_config
|
||||||
KuzuDB* = ref KuzuDBObj
|
valid = false
|
||||||
|
KuzuDatabase* = ref KuzuDatabaseObj
|
||||||
|
|
||||||
KuzuConnectionObj = object
|
KuzuConnectionObj = object
|
||||||
handle*: kuzu_connection
|
handle*: kuzu_connection
|
||||||
|
valid = false
|
||||||
KuzuConnection* = ref KuzuConnectionObj
|
KuzuConnection* = ref KuzuConnectionObj
|
||||||
|
|
||||||
KuzuQueryResultObj = object
|
KuzuQueryResultObj = object
|
||||||
|
|
@ -18,8 +20,21 @@ type
|
||||||
num_tuples*: uint64 = 0
|
num_tuples*: uint64 = 0
|
||||||
compile_time*: cdouble = 0
|
compile_time*: cdouble = 0
|
||||||
execution_time*: cdouble = 0
|
execution_time*: cdouble = 0
|
||||||
|
valid = false
|
||||||
KuzuQueryResult* = ref KuzuQueryResultObj
|
KuzuQueryResult* = ref KuzuQueryResultObj
|
||||||
|
|
||||||
|
KuzuFlatTupleObj = object
|
||||||
|
handle*: kuzu_flat_tuple
|
||||||
|
num_columns: uint64 = 0
|
||||||
|
valid = false
|
||||||
|
KuzuFlatTuple* = ref KuzuFlatTupleObj
|
||||||
|
|
||||||
|
KuzuValueObj = object
|
||||||
|
handle*: kuzu_value
|
||||||
|
valid = false
|
||||||
|
KuzuValue* = ref KuzuValueObj
|
||||||
|
|
||||||
KuzuException* = object of CatchableError
|
KuzuException* = object of CatchableError
|
||||||
KuzuQueryException* = object of KuzuException
|
KuzuQueryException* = object of KuzuException
|
||||||
|
KuzuIndexException* = object of KuzuException
|
||||||
|
|
||||||
|
|
|
||||||
13
src/kuzu/value.nim
Normal file
13
src/kuzu/value.nim
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
# vim: set et sta sw=4 ts=4 :
|
||||||
|
|
||||||
|
proc `=destroy`*( value: KuzuValueObj ) =
|
||||||
|
## Graceful cleanup for out of scope values.
|
||||||
|
if value.valid:
|
||||||
|
kuzu_value_destroy( addr value.handle )
|
||||||
|
|
||||||
|
|
||||||
|
proc `$`*( value: KuzuValue ): string =
|
||||||
|
## Stringify a value.
|
||||||
|
result = $kuzu_value_to_string( addr value.handle )
|
||||||
|
|
||||||
|
|
||||||
19
tests/queries/t_can_iterate_tuples.nim
Normal file
19
tests/queries/t_can_iterate_tuples.nim
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# vim: set et sta sw=4 ts=4 :
|
||||||
|
|
||||||
|
discard """
|
||||||
|
output: "Camel\nLampshade\nDelicious Cake\n"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import kuzu
|
||||||
|
|
||||||
|
let db = newKuzuDatabase()
|
||||||
|
let conn = db.connect
|
||||||
|
|
||||||
|
var q = conn.query( "CREATE NODE TABLE Doop ( id SERIAL, thing STRING, PRIMARY KEY(id) )" )
|
||||||
|
|
||||||
|
for thing in @[ "Camel", "Lampshade", "Delicious Cake" ]:
|
||||||
|
q = conn.query( "CREATE (d:Doop {thing: '" & thing & "'})" )
|
||||||
|
|
||||||
|
for tpl in conn.query( "MATCH (d:Doop) RETURN d.thing" ):
|
||||||
|
echo $tpl
|
||||||
|
|
||||||
17
tests/queries/t_can_stringify_results.nim
Normal file
17
tests/queries/t_can_stringify_results.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# vim: set et sta sw=4 ts=4 :
|
||||||
|
|
||||||
|
discard """
|
||||||
|
output: "d.thing\nokay!\n\n"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import kuzu
|
||||||
|
|
||||||
|
let db = newKuzuDatabase()
|
||||||
|
let conn = db.connect
|
||||||
|
|
||||||
|
var q = conn.query( "CREATE NODE TABLE Doop ( id SERIAL, thing STRING, PRIMARY KEY(id) )" )
|
||||||
|
q = conn.query( "CREATE (d:Doop {thing: 'okay!'})" )
|
||||||
|
q = conn.query( "MATCH (d:Doop) RETURN d.thing" )
|
||||||
|
|
||||||
|
echo $q
|
||||||
|
|
||||||
24
tests/queries/t_knows_if_there_are_waiting_tuples.nim
Normal file
24
tests/queries/t_knows_if_there_are_waiting_tuples.nim
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# vim: set et sta sw=4 ts=4 :
|
||||||
|
|
||||||
|
import kuzu
|
||||||
|
|
||||||
|
let db = newKuzuDatabase()
|
||||||
|
let conn = db.connect
|
||||||
|
|
||||||
|
var q = conn.query( "CREATE NODE TABLE Doop ( id SERIAL, thing STRING, PRIMARY KEY(id) )" )
|
||||||
|
assert typeOf( q ) is KuzuQueryResult
|
||||||
|
|
||||||
|
q = conn.query( "MATCH (d:Doop) RETURN d.thing" )
|
||||||
|
assert q.num_tuples == 0
|
||||||
|
assert q.hasNext == false
|
||||||
|
|
||||||
|
q = conn.query( "CREATE (d:Doop {thing: 'okay!'})" )
|
||||||
|
q = conn.query( "MATCH (d:Doop) RETURN d.thing" )
|
||||||
|
assert q.num_tuples == 1
|
||||||
|
assert q.hasNext == true
|
||||||
|
|
||||||
|
discard $q # consume the tuple result
|
||||||
|
|
||||||
|
assert q.num_tuples == 1
|
||||||
|
assert q.hasNext == false
|
||||||
|
|
||||||
19
tests/tuples/t_can_be_stringified.nim
Normal file
19
tests/tuples/t_can_be_stringified.nim
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# vim: set et sta sw=4 ts=4 :
|
||||||
|
|
||||||
|
discard """
|
||||||
|
output: "okay!"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import kuzu
|
||||||
|
|
||||||
|
let db = newKuzuDatabase()
|
||||||
|
let conn = db.connect
|
||||||
|
|
||||||
|
var q = conn.query( "CREATE NODE TABLE Doop ( id SERIAL, thing STRING, PRIMARY KEY(id) )" )
|
||||||
|
q = conn.query( "CREATE (d:Doop {thing: 'okay!'})" )
|
||||||
|
q = conn.query( "MATCH (d:Doop) RETURN d.thing" )
|
||||||
|
|
||||||
|
var tup = q.getNext
|
||||||
|
|
||||||
|
echo $tup
|
||||||
|
|
||||||
17
tests/tuples/t_throws_exception_fetching_at_end.nim
Normal file
17
tests/tuples/t_throws_exception_fetching_at_end.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# vim: set et sta sw=4 ts=4 :
|
||||||
|
|
||||||
|
import
|
||||||
|
std/re
|
||||||
|
import kuzu
|
||||||
|
|
||||||
|
let db = newKuzuDatabase()
|
||||||
|
let conn = db.connect
|
||||||
|
|
||||||
|
var q = conn.query( "CREATE NODE TABLE Doop ( id SERIAL, thing STRING, PRIMARY KEY(id) )" )
|
||||||
|
q = conn.query( "MATCH (d:Doop) RETURN d.thing" )
|
||||||
|
|
||||||
|
try:
|
||||||
|
discard q.getNext
|
||||||
|
except KuzuQueryException as err:
|
||||||
|
assert err.msg.contains( re"""Unable to fetch next tuple.""" )
|
||||||
|
|
||||||
20
tests/tuples/t_throws_exception_invalid_index.nim
Normal file
20
tests/tuples/t_throws_exception_invalid_index.nim
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# vim: set et sta sw=4 ts=4 :
|
||||||
|
|
||||||
|
import
|
||||||
|
std/re
|
||||||
|
import kuzu
|
||||||
|
|
||||||
|
let db = newKuzuDatabase()
|
||||||
|
let conn = db.connect
|
||||||
|
|
||||||
|
var q = conn.query( "CREATE NODE TABLE Doop ( id SERIAL, thing STRING, PRIMARY KEY(id) )" )
|
||||||
|
q = conn.query( "CREATE (d:Doop {thing: 'okay!'})" )
|
||||||
|
q = conn.query( "MATCH (d:Doop) RETURN d.thing" )
|
||||||
|
|
||||||
|
let tup = q.getNext
|
||||||
|
|
||||||
|
try:
|
||||||
|
echo tup[22]
|
||||||
|
except KuzuIndexException as err:
|
||||||
|
assert err.msg.contains( re"""Unable to fetch tuple value at idx 22.""" )
|
||||||
|
|
||||||
20
tests/values/t_can_be_stringified.nim
Normal file
20
tests/values/t_can_be_stringified.nim
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# vim: set et sta sw=4 ts=4 :
|
||||||
|
|
||||||
|
discard """
|
||||||
|
output: "okay!"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import kuzu
|
||||||
|
|
||||||
|
let db = newKuzuDatabase()
|
||||||
|
let conn = db.connect
|
||||||
|
|
||||||
|
var q = conn.query( "CREATE NODE TABLE Doop ( id SERIAL, thing STRING, PRIMARY KEY(id) )" )
|
||||||
|
q = conn.query( "CREATE (d:Doop {thing: 'okay!'})" )
|
||||||
|
q = conn.query( "MATCH (d:Doop) RETURN d.thing" )
|
||||||
|
|
||||||
|
var tup = q.getNext
|
||||||
|
var val = tup[0]
|
||||||
|
|
||||||
|
echo $val
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue