Multiple changes.
- Minor README updates. - Create LICENSE and History files. - Use 'func' instead of 'proc' where applicable. - Add some destructor debug. - Rename primary exceptions to 'X-error'. - Bind to proper object types in prepared statement parameters. - Retain the found 'type' in the KuzuValue object. FossilOrigin-Name: db59c0b901b1715170e0d269fc2bf00477ac48af4d10a747eb5a749adbf6268e
This commit is contained in:
parent
421cb87e57
commit
db85c36d70
22 changed files with 284 additions and 162 deletions
15
.editorconfig
Normal file
15
.editorconfig
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# http://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# Space indentation
|
||||
[**.nim]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
7
History.md
Normal file
7
History.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# Release History for nim-kuzu
|
||||
|
||||
---
|
||||
## v0.1.0 [2025-??-??] Mahlon E. Smith <mahlon@martini.nu>
|
||||
|
||||
Initial public release.
|
||||
|
||||
29
LICENCE
Normal file
29
LICENCE
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
Copyright (c) 2025 Mahlon E. Smith
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author/s, nor the names of the project's
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
35
README.md
35
README.md
|
|
@ -10,7 +10,7 @@ github_mirror
|
|||
|
||||
## Description
|
||||
|
||||
This is a Nim binding for the Kuzu graph database library.
|
||||
This is a Nim binding for the [Kuzu](https://kuzudb.com) graph database library.
|
||||
|
||||
Kuzu is an embedded graph database built for query speed and scalability. It is
|
||||
optimized for handling complex join-heavy analytical workloads on very large
|
||||
|
|
@ -32,7 +32,7 @@ For more information about Kuzu itself, see its
|
|||
## Prerequisites
|
||||
|
||||
* A functioning Nim >= 2 installation
|
||||
- [KuzuDB](https://kuzudb.com)
|
||||
- [KuzuDB](https://kuzudb.com) to be locally installed!
|
||||
|
||||
|
||||
## Installation
|
||||
|
|
@ -76,34 +76,3 @@ development.
|
|||
A note of thanks to @mantielero on Github, who has a Kuzu binding for an early
|
||||
KuzuDB (0.4.x) that I found after starting this project.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) 2025 Mahlon E. Smith
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author/s, nor the names of the project's
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# vim: set et sta sw=4 ts=4 :
|
||||
|
||||
proc kuzuConfig*(
|
||||
func kuzuConfig*(
|
||||
buffer_pool_size = KUZU_DEFAULT_CONFIG.buffer_pool_size,
|
||||
max_num_threads = KUZU_DEFAULT_CONFIG.max_num_threads,
|
||||
enable_compression = KUZU_DEFAULT_CONFIG.enable_compression,
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@
|
|||
proc `=destroy`*( conn: KuzuConnectionObj ) =
|
||||
## Graceful cleanup for open connection handles.
|
||||
if conn.valid:
|
||||
when defined( debug ): echo &"Destroying connection: {conn}"
|
||||
kuzu_connection_destroy( addr conn.handle )
|
||||
|
||||
|
||||
proc connect*( db: KuzuDatabase ): KuzuConnection =
|
||||
func connect*( db: KuzuDatabase ): KuzuConnection =
|
||||
## Connect to a database.
|
||||
result = new KuzuConnection
|
||||
if kuzu_connection_init( addr db.handle, addr result.handle ) == KuzuSuccess:
|
||||
|
|
@ -15,12 +16,12 @@ proc connect*( db: KuzuDatabase ): KuzuConnection =
|
|||
raise newException( KuzuException, "Unable to connect to the database." )
|
||||
|
||||
|
||||
proc queryTimeout*( conn: KuzuConnection, timeout: uint64 ) =
|
||||
func queryTimeout*( conn: KuzuConnection, timeout: uint64 ) =
|
||||
## Set a maximum time limit (in milliseconds) for query runtime.
|
||||
discard kuzu_connection_set_query_timeout( addr conn.handle, timeout )
|
||||
|
||||
|
||||
proc queryInterrupt*( conn: KuzuConnection ) =
|
||||
func queryInterrupt*( conn: KuzuConnection ) =
|
||||
## Cancel any running queries.
|
||||
kuzu_connection_interrupt( addr conn.handle )
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@
|
|||
proc `=destroy`*( db: KuzuDatabaseObj ) =
|
||||
## Graceful cleanup for an open DB handle when it goes out of scope.
|
||||
if db.valid:
|
||||
when defined( debug ): echo &"Destroying database: {db}"
|
||||
kuzu_database_destroy( addr db.handle )
|
||||
|
||||
|
||||
proc newKuzuDatabase*( path="", config=kuzuConfig() ): KuzuDatabase =
|
||||
func newKuzuDatabase*( path="", config=kuzuConfig() ): KuzuDatabase =
|
||||
## Create a new Kuzu database handle. Creates an in-memory
|
||||
## database by default, but writes to disk if a +path+ is supplied.
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@
|
|||
proc `=destroy`*( query: KuzuQueryResultObj ) =
|
||||
## Graceful cleanup for out of scope query objects.
|
||||
if query.valid:
|
||||
when defined( debug ): echo &"Destroying query: {query}"
|
||||
kuzu_query_result_destroy( addr query.handle )
|
||||
|
||||
|
||||
proc getQueryMetadata( query: KuzuQueryResult ) =
|
||||
func getQueryMetadata( query: KuzuQueryResult ) =
|
||||
## Find and retain additional data for the query.
|
||||
query.num_columns = kuzu_query_result_get_num_columns( addr query.handle )
|
||||
query.num_tuples = kuzu_query_result_get_num_tuples( addr query.handle )
|
||||
|
|
@ -21,6 +22,7 @@ proc getQueryMetadata( query: KuzuQueryResult ) =
|
|||
# Column information.
|
||||
query.column_types = @[]
|
||||
query.column_names = @[]
|
||||
if query.num_columns == 0: return
|
||||
for idx in ( 0 .. query.num_columns-1 ):
|
||||
|
||||
# types
|
||||
|
|
@ -46,7 +48,7 @@ proc getQueryMetadata( query: KuzuQueryResult ) =
|
|||
kuzu_destroy_string( name )
|
||||
|
||||
|
||||
proc query*( conn: KuzuConnection, query: string ): KuzuQueryResult =
|
||||
func query*( conn: KuzuConnection, query: string ): KuzuQueryResult =
|
||||
## Perform a database +query+ and return the result.
|
||||
result = new KuzuQueryResult
|
||||
|
||||
|
|
@ -55,16 +57,17 @@ proc query*( conn: KuzuConnection, query: string ): KuzuQueryResult =
|
|||
result.getQueryMetadata()
|
||||
else:
|
||||
var err = kuzu_query_result_get_error_message( addr result.handle )
|
||||
raise newException( KuzuQueryException, &"Error running query: {err}" )
|
||||
raise newException( KuzuQueryError, &"Error running query: {err}" )
|
||||
|
||||
|
||||
proc `=destroy`*( prepared: KuzuPreparedStatementObj ) =
|
||||
## Graceful cleanup for out of scope prepared objects.
|
||||
if prepared.valid:
|
||||
when defined( debug ): echo &"Destroying prepared statement: {prepared}"
|
||||
kuzu_prepared_statement_destroy( addr prepared.handle )
|
||||
|
||||
|
||||
proc prepare*( conn: KuzuConnection, query: string ): KuzuPreparedStatement =
|
||||
func prepare*( conn: KuzuConnection, query: string ): KuzuPreparedStatement =
|
||||
## Return a prepared statement that can avoid planning for repeat calls,
|
||||
## with optional variable binding via #execute.
|
||||
result = new KuzuPreparedStatement
|
||||
|
|
@ -73,7 +76,40 @@ proc prepare*( conn: KuzuConnection, query: string ): KuzuPreparedStatement =
|
|||
result.valid = true
|
||||
else:
|
||||
var err = kuzu_prepared_statement_get_error_message( addr result.handle )
|
||||
raise newException( KuzuQueryException, &"Error preparing statement: {err}" )
|
||||
raise newException( KuzuQueryError, &"Error preparing statement: {err}" )
|
||||
|
||||
|
||||
func bindValue[T](
|
||||
stmtHandle: kuzu_prepared_statement,
|
||||
key: cstring,
|
||||
val: T
|
||||
) =
|
||||
## Bind a key/value to a prepared statement handle.
|
||||
when typeOf( val ) is bool:
|
||||
assert( kuzu_prepared_statement_bind_bool( addr stmtHandle, key, val ) == KuzuSuccess )
|
||||
elif typeOf( val ) is int8:
|
||||
assert( kuzu_prepared_statement_bind_int8( addr stmtHandle, key, val ) == KuzuSuccess )
|
||||
elif typeOf( val ) is int16:
|
||||
assert( kuzu_prepared_statement_bind_int16( addr stmtHandle, key, val ) == KuzuSuccess )
|
||||
elif typeOf( val ) is int64:
|
||||
assert( kuzu_prepared_statement_bind_int64( addr stmtHandle, key, val ) == KuzuSuccess )
|
||||
elif typeOf( val ) is int or typeOf( val ) is int32:
|
||||
assert( kuzu_prepared_statement_bind_int32( addr stmtHandle, key, val.int32 ) == KuzuSuccess )
|
||||
elif typeOf( val ) is uint8:
|
||||
assert( kuzu_prepared_statement_bind_uint8( addr stmtHandle, key, val ) == KuzuSuccess )
|
||||
elif typeOf( val ) is uint16:
|
||||
assert( kuzu_prepared_statement_bind_uint16( addr stmtHandle, key, val ) == KuzuSuccess )
|
||||
elif typeOf( val ) is uint64:
|
||||
assert( kuzu_prepared_statement_bind_uint64( addr stmtHandle, key, val ) == KuzuSuccess )
|
||||
elif typeOf( val ) is uint or typeOf( val ) is uint32:
|
||||
assert( kuzu_prepared_statement_bind_uint32( addr stmtHandle, key, val.uint32 ) == KuzuSuccess )
|
||||
elif typeOf( val ) is float:
|
||||
assert( kuzu_prepared_statement_bind_double( addr stmtHandle, key, val ) == KuzuSuccess )
|
||||
elif typeOf( val ) is string:
|
||||
# Fallback to string. For custom types, just cast in the cypher query.
|
||||
assert( kuzu_prepared_statement_bind_string( addr stmtHandle, key, val.cstring ) == KuzuSuccess )
|
||||
else:
|
||||
raise newException( KuzuTypeError, &"""Unsupported type {$typeOf(val)} for prepared statement.""" )
|
||||
|
||||
|
||||
proc execute*(
|
||||
|
|
@ -86,111 +122,42 @@ proc execute*(
|
|||
result = new KuzuQueryResult
|
||||
|
||||
for key, val in params.fieldPairs:
|
||||
#
|
||||
# FIXME: type checks and conversions for all bound variables
|
||||
# from nim types to supported Kuzu types.
|
||||
#
|
||||
discard kuzu_prepared_statement_bind_string( addr prepared.handle, key.cstring, val.cstring )
|
||||
|
||||
#[
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_bool (kuzu_prepared_statement *prepared_statement, const char *param_name, bool value)
|
||||
Binds the given boolean value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_int64 (kuzu_prepared_statement *prepared_statement, const char *param_name, int64_t value)
|
||||
Binds the given int64_t value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_int32 (kuzu_prepared_statement *prepared_statement, const char *param_name, int32_t value)
|
||||
Binds the given int32_t value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_int16 (kuzu_prepared_statement *prepared_statement, const char *param_name, int16_t value)
|
||||
Binds the given int16_t value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_int8 (kuzu_prepared_statement *prepared_statement, const char *param_name, int8_t value)
|
||||
Binds the given int8_t value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_uint64 (kuzu_prepared_statement *prepared_statement, const char *param_name, uint64_t value)
|
||||
Binds the given uint64_t value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_uint32 (kuzu_prepared_statement *prepared_statement, const char *param_name, uint32_t value)
|
||||
Binds the given uint32_t value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_uint16 (kuzu_prepared_statement *prepared_statement, const char *param_name, uint16_t value)
|
||||
Binds the given uint16_t value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_uint8 (kuzu_prepared_statement *prepared_statement, const char *param_name, uint8_t value)
|
||||
Binds the given int8_t value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_double (kuzu_prepared_statement *prepared_statement, const char *param_name, double value)
|
||||
Binds the given double value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_float (kuzu_prepared_statement *prepared_statement, const char *param_name, float value)
|
||||
Binds the given float value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_date (kuzu_prepared_statement *prepared_statement, const char *param_name, kuzu_date_t value)
|
||||
Binds the given date value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_timestamp_ns (kuzu_prepared_statement *prepared_statement, const char *param_name, kuzu_timestamp_ns_t value)
|
||||
Binds the given timestamp_ns value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_timestamp_sec (kuzu_prepared_statement *prepared_statement, const char *param_name, kuzu_timestamp_sec_t value)
|
||||
Binds the given timestamp_sec value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_timestamp_tz (kuzu_prepared_statement *prepared_statement, const char *param_name, kuzu_timestamp_tz_t value)
|
||||
Binds the given timestamp_tz value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_timestamp_ms (kuzu_prepared_statement *prepared_statement, const char *param_name, kuzu_timestamp_ms_t value)
|
||||
Binds the given timestamp_ms value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_timestamp (kuzu_prepared_statement *prepared_statement, const char *param_name, kuzu_timestamp_t value)
|
||||
Binds the given timestamp value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_interval (kuzu_prepared_statement *prepared_statement, const char *param_name, kuzu_interval_t value)
|
||||
Binds the given interval value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_string (kuzu_prepared_statement *prepared_statement, const char *param_name, const char *value)
|
||||
Binds the given string value to the given parameter name in the prepared statement.
|
||||
|
||||
KUZU_C_API kuzu_state kuzu_prepared_statement_bind_value (kuzu_prepared_statement *prepared_statement, const char *param_name, kuzu_value *value)
|
||||
]#
|
||||
prepared.handle.bindValue( key, val )
|
||||
|
||||
if kuzu_connection_execute(
|
||||
addr prepared.conn.handle,
|
||||
addr prepared.handle,
|
||||
addr result.handle
|
||||
) == KuzuSuccess:
|
||||
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_tuples = kuzu_query_result_get_num_tuples( addr result.handle )
|
||||
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.valid = true
|
||||
result.valid = false
|
||||
result.getQueryMetadata()
|
||||
else:
|
||||
var err = kuzu_query_result_get_error_message( addr result.handle )
|
||||
raise newException( KuzuQueryException, &"Error executing prepared statement: {err}" )
|
||||
raise newException( KuzuQueryError, &"Error executing prepared statement: {err}" )
|
||||
|
||||
|
||||
proc `$`*( query: KuzuQueryResult ): string =
|
||||
func `$`*( 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 =
|
||||
func 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 =
|
||||
## Consume and return the next tuple result, or raise a KuzuIndexException
|
||||
func getNext*( query: KuzuQueryResult ): KuzuFlatTuple =
|
||||
## Consume and return the next tuple result, or raise a KuzuIndexError
|
||||
## if at the end of the result set.
|
||||
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( KuzuIndexException, &"Query iteration past end." )
|
||||
raise newException( KuzuIndexError, &"Query iteration past end." )
|
||||
|
||||
|
||||
proc rewind*( query: KuzuQueryResult ) =
|
||||
func rewind*( query: KuzuQueryResult ) =
|
||||
## Reset query iteration back to the beginning.
|
||||
kuzu_query_result_reset_iterator( addr query.handle )
|
||||
|
||||
|
|
|
|||
|
|
@ -3,22 +3,25 @@
|
|||
proc `=destroy`*( tpl: KuzuFlatTupleObj ) =
|
||||
## Graceful cleanup for out of scope tuples.
|
||||
if tpl.valid:
|
||||
when defined( debug ): echo &"Destroying tuple: {tpl}"
|
||||
kuzu_flat_tuple_destroy( addr tpl.handle )
|
||||
|
||||
|
||||
proc `$`*( tpl: KuzuFlatTuple ): string =
|
||||
func `$`*( 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+.
|
||||
func `[]`*( 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
|
||||
|
||||
result.getType()
|
||||
else:
|
||||
raise newException( KuzuIndexException,
|
||||
raise newException( KuzuIndexError,
|
||||
&"Unable to fetch tuple value at idx {idx}. ({tpl.num_columns} column(s).)" )
|
||||
|
||||
|
|
|
|||
|
|
@ -39,9 +39,11 @@ type
|
|||
KuzuValueObj = object
|
||||
handle: kuzu_value
|
||||
valid = false
|
||||
kind*: kuzu_data_type_id
|
||||
KuzuValue* = ref KuzuValueObj
|
||||
|
||||
KuzuException* = object of CatchableError
|
||||
KuzuQueryException* = object of KuzuException
|
||||
KuzuIndexException* = object of KuzuException
|
||||
KuzuQueryError* = object of KuzuException
|
||||
KuzuIndexError* = object of KuzuException
|
||||
KuzuTypeError* = object of KuzuException
|
||||
|
||||
|
|
|
|||
|
|
@ -3,41 +3,28 @@
|
|||
proc `=destroy`*( value: KuzuValueObj ) =
|
||||
## Graceful cleanup for out of scope values.
|
||||
if value.valid:
|
||||
when defined( debug ): echo &"Destroying value: {value}"
|
||||
kuzu_value_destroy( addr value.handle )
|
||||
|
||||
|
||||
proc `$`*( value: KuzuValue ): string =
|
||||
func `$`*( value: KuzuValue ): string =
|
||||
## Stringify a value.
|
||||
result = $kuzu_value_to_string( addr value.handle )
|
||||
|
||||
|
||||
proc kind*( value: KuzuValue ): kuzu_data_type_id =
|
||||
## Find and return the native Kuzu type of this value.
|
||||
func getType( value: KuzuValue ) =
|
||||
## Find and set the native Kuzu type of this value.
|
||||
var logical_type: kuzu_logical_type
|
||||
kuzu_value_get_data_type( addr value.handle, addr logical_type )
|
||||
result = kuzu_data_type_get_id( addr logical_type )
|
||||
# var num: uint64
|
||||
# discard kuzu_data_type_get_num_elements_in_array( addr logical_type, addr num )
|
||||
# echo "HMMM ", $num
|
||||
value.kind = kuzu_data_type_get_id( addr logical_type )
|
||||
kuzu_data_type_destroy( addr logical_type )
|
||||
|
||||
# enum_kuzu_data_type_id_570425857* {.size: sizeof(cuint).} = enum
|
||||
# KUZU_ANY = 0, KUZU_NODE = 10, KUZU_REL = 11, KUZU_RECURSIVE_REL = 12,
|
||||
# KUZU_SERIAL = 13, KUZU_BOOL = 22, KUZU_INT64 = 23, KUZU_INT32 = 24,
|
||||
# KUZU_INT16 = 25, KUZU_INT8 = 26, KUZU_UINT64 = 27, KUZU_UINT32 = 28,
|
||||
# KUZU_UINT16 = 29, KUZU_UINT8 = 30, KUZU_INT128 = 31, KUZU_DOUBLE = 32,
|
||||
# KUZU_FLOAT = 33, KUZU_DATE = 34, KUZU_TIMESTAMP = 35,
|
||||
# KUZU_TIMESTAMP_SEC = 36, KUZU_TIMESTAMP_MS = 37, KUZU_TIMESTAMP_NS = 38,
|
||||
# KUZU_TIMESTAMP_TZ = 39, KUZU_INTERVAL = 40, KUZU_DECIMAL = 41,
|
||||
# KUZU_INTERNAL_ID = 42, KUZU_STRING = 50, KUZU_BLOB = 51, KUZU_LIST = 52,
|
||||
# KUZU_ARRAY = 53, KUZU_STRUCT = 54, KUZU_MAP = 55, KUZU_UNION = 56,
|
||||
# KUZU_POINTER = 58, KUZU_UUID = 59
|
||||
|
||||
# proc getValue*( value: KuzuValue ):
|
||||
#
|
||||
# FIXME: type checks and conversions from supported kuzu
|
||||
# types to supported Nim types.
|
||||
#
|
||||
# Currently the value can only be stringified via `$`.
|
||||
#
|
||||
func toInt8*( value: KuzuValue ): int8 =
|
||||
if value.kind != KUZU_INT8:
|
||||
raise newException( KuzuTypeError, &"Mismatched types: {value.kind} != int8" )
|
||||
assert(
|
||||
kuzu_value_get_int8( addr value.handle, addr result ) ==
|
||||
KuzuSuccess
|
||||
)
|
||||
|
||||
|
|
|
|||
55
tests/queries/t_can_bind_various_datatypes.nim
Normal file
55
tests/queries/t_can_bind_various_datatypes.nim
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# vim: set et sta sw=4 ts=4 :
|
||||
|
||||
discard """
|
||||
output: "0|-222222|128|True|Stuff!|3.344903|239.299923|a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11|2025-03-29"
|
||||
"""
|
||||
|
||||
import kuzu
|
||||
|
||||
let db = newKuzuDatabase()
|
||||
let conn = db.connect
|
||||
|
||||
var q = conn.query( """CREATE NODE TABLE Doop (
|
||||
id SERIAL,
|
||||
num INT,
|
||||
unum UINT8,
|
||||
woo BOOL,
|
||||
thing STRING,
|
||||
float FLOAT,
|
||||
double DOUBLE,
|
||||
uuid UUID,
|
||||
date DATE,
|
||||
PRIMARY KEY(id)
|
||||
)""" )
|
||||
assert typeOf( q ) is KuzuQueryResult
|
||||
|
||||
|
||||
var stmt = conn.prepare( """CREATE (d:Doop {
|
||||
woo: $woo,
|
||||
thing: $thing,
|
||||
num: $num,
|
||||
unum: $unum,
|
||||
float: $float,
|
||||
double: $double,
|
||||
uuid: UUID($uuid),
|
||||
date: DATE($date)
|
||||
})""" )
|
||||
assert typeOf( stmt ) is KuzuPreparedStatement
|
||||
|
||||
|
||||
q = stmt.execute((
|
||||
woo: true,
|
||||
thing: "Stuff!",
|
||||
num: -222222,
|
||||
unum: 128,
|
||||
float: 3.34490345039450345,
|
||||
double: 239.299922883992,
|
||||
uuid: "A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11",
|
||||
date: "2025-03-29"
|
||||
))
|
||||
assert typeOf( q ) is KuzuQueryResult
|
||||
|
||||
|
||||
q = conn.query( "MATCH (d:Doop) RETURN d.*" )
|
||||
echo $q.getNext
|
||||
|
||||
17
tests/queries/t_knows_the_column_names.nim
Normal file
17
tests/queries/t_knows_the_column_names.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# 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( "CREATE (d:Doop {thing: 'okay!'})" )
|
||||
q = conn.query( "MATCH (d:Doop) RETURN d.id AS IDENTIFIER, d.thing AS THING" )
|
||||
|
||||
assert q.column_names.len == 2
|
||||
assert q.column_names[0] == "IDENTIFIER"
|
||||
assert q.column_names[1] == "THING"
|
||||
|
||||
17
tests/queries/t_knows_the_column_types.nim
Normal file
17
tests/queries/t_knows_the_column_types.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# 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( "CREATE (d:Doop {thing: 'okay!'})" )
|
||||
q = conn.query( "MATCH (d:Doop) RETURN d.id AS IDENTIFIER, d.thing AS THING" )
|
||||
|
||||
assert q.column_types.len == 2
|
||||
assert $q.column_types[0] == "KUZU_SERIAL"
|
||||
assert $q.column_types[1] == "KUZU_STRING"
|
||||
|
||||
|
|
@ -9,6 +9,6 @@ let conn = db.connect
|
|||
|
||||
try:
|
||||
discard conn.query( "NOPE NOPE NOPE" )
|
||||
except KuzuQueryException as err:
|
||||
assert err.msg.contains( re"""Error running query:.*extraneous input 'NOPE'""" )
|
||||
except KuzuQueryError as err:
|
||||
assert err.msg.contains( re"""Parser exception: extraneous input 'NOPE'""" )
|
||||
|
||||
|
|
|
|||
31
tests/queries/t_raises_on_invalid_varbind.nim
Normal file
31
tests/queries/t_raises_on_invalid_varbind.nim
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# 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, created DATE, PRIMARY KEY(id) )" )
|
||||
assert typeOf( q ) is KuzuQueryResult
|
||||
|
||||
var p = conn.prepare( "CREATE (d:Doop {created: $created})" )
|
||||
assert typeOf( p ) is KuzuPreparedStatement
|
||||
|
||||
# Typecast binding failure
|
||||
#
|
||||
try:
|
||||
discard p.execute( (created: "1111-1111") )
|
||||
except KuzuQueryError as err:
|
||||
assert err.msg.contains( re"""Expression \$created has data type STRING but expected DATE.""" )
|
||||
|
||||
# Invalid value for typecast
|
||||
#
|
||||
p = conn.prepare( "CREATE (d:Doop {created: DATE($created)})" )
|
||||
try:
|
||||
discard p.execute( (created: "1111-1111") )
|
||||
except KuzuQueryError as err:
|
||||
assert err.msg.contains( re"""Given: "1111-1111". Expected format: \(YYYY-MM-DD\)""" )
|
||||
|
||||
|
||||
|
|
@ -14,7 +14,7 @@ assert typeOf( p ) is KuzuPreparedStatement
|
|||
|
||||
try:
|
||||
discard p.execute( (nope: "undefined var in statement!") )
|
||||
except KuzuQueryException as err:
|
||||
except KuzuQueryError as err:
|
||||
assert err.msg.contains( re"""Parameter nope not found.""" )
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ assert typeOf( p ) is KuzuPreparedStatement
|
|||
|
||||
try:
|
||||
discard p.execute
|
||||
except KuzuQueryException as err:
|
||||
assert err.msg.contains( re""".*Error executing prepared statement:.*CREAET""" )
|
||||
except KuzuQueryError as err:
|
||||
assert err.msg.contains( re"""Parser exception: extraneous input 'CREAET'""" )
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,6 @@ q = conn.query( "MATCH (d:Doop) RETURN d.thing" )
|
|||
|
||||
try:
|
||||
discard q.getNext
|
||||
except KuzuIndexException as err:
|
||||
except KuzuIndexError as err:
|
||||
assert err.msg.contains( re"""Query iteration past end.""" )
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@ let tup = q.getNext
|
|||
|
||||
try:
|
||||
echo tup[22]
|
||||
except KuzuIndexException as err:
|
||||
except KuzuIndexError as err:
|
||||
assert err.msg.contains( re"""Unable to fetch tuple value at idx 22.""" )
|
||||
|
||||
|
|
|
|||
21
tests/values/t_can_return_a_type.nim
Normal file
21
tests/values/t_can_return_a_type.nim
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# 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) )" )
|
||||
|
||||
q = conn.query( "CREATE (d:Doop {thing: 'okay!'})" )
|
||||
q = conn.query( "MATCH (d:Doop) RETURN d.id, d.thing, d" )
|
||||
|
||||
var row = q.getNext
|
||||
var id = row[0]
|
||||
var thing = row[1]
|
||||
var node = row[2]
|
||||
|
||||
assert id.kind == KUZU_INT64
|
||||
assert thing.kind == KUZU_STRING
|
||||
assert node.kind == KUZU_NODE
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue