[wip] #1 prototype for using iterator from nodejs addon
Signed-off-by: Anton Nesterov <anton@demiurg.io>
This commit is contained in:
parent
e4fdd426a8
commit
9150d3faf6
|
@ -7,17 +7,34 @@ static void _InitSQLite(const Napi::CallbackInfo& args) {
|
||||||
InitSQLite(charstr);
|
InitSQLite(charstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Napi::Value Handle(const Napi::CallbackInfo& args) {
|
static Napi::Object RowIterator(const Napi::CallbackInfo& args) {
|
||||||
|
Napi::Env env = args.Env();
|
||||||
|
Napi::Object it = Napi::Object::New( env );
|
||||||
Napi::Buffer<uint8_t> buf = args[0].As<Napi::Buffer<uint8_t>>();
|
Napi::Buffer<uint8_t> buf = args[0].As<Napi::Buffer<uint8_t>>();
|
||||||
GoSlice input = {reinterpret_cast<void *>(buf.Data()), long(buf.Length()), long(buf.Length())};
|
GoSlice input = {reinterpret_cast<void *>(buf.Data()), long(buf.Length()), long(buf.Length())};
|
||||||
GoSlice result = HandleQuery(input);
|
int iter = CreateRowIterator(input);
|
||||||
return Napi::Buffer<char>::Copy(args.Env(), reinterpret_cast<char *>(result.data), result.len);
|
auto next_row = [=](const Napi::CallbackInfo& a){
|
||||||
|
void* next = NextRow(iter);
|
||||||
|
if (next == nullptr) {
|
||||||
|
FreeIter(iter);
|
||||||
|
return Napi::Buffer<uint8_t>::New(env, 0);
|
||||||
|
}
|
||||||
|
Napi::Buffer<uint8_t> val = Napi::Buffer<uint8_t>::Copy(env, reinterpret_cast<uint8_t *>(next), GetLen(iter));
|
||||||
|
free(next);
|
||||||
|
return val;
|
||||||
|
};
|
||||||
|
auto free_iter = [=](const Napi::CallbackInfo& a){
|
||||||
|
FreeIter(iter);
|
||||||
|
};
|
||||||
|
it.Set("next", Napi::Function::New(env, next_row));
|
||||||
|
it.Set("free", Napi::Function::New(env, free_iter));
|
||||||
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
static Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
||||||
exports["InitSQLite"] = Napi::Function::New(env, _InitSQLite);
|
exports["InitSQLite"] = Napi::Function::New(env, _InitSQLite);
|
||||||
exports["Handle"] = Napi::Function::New(env, Handle);
|
exports["RowIterator"] = Napi::Function::New(env, RowIterator);
|
||||||
return exports;
|
return exports;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,64 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <stdio.h>
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/nesterow/dal/pkg/facade"
|
"github.com/nesterow/dal/pkg/facade"
|
||||||
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var iterators = make(map[int]*facade.RowsIter)
|
||||||
|
var itersize = make(map[int]C.int)
|
||||||
|
|
||||||
//export InitSQLite
|
//export InitSQLite
|
||||||
func InitSQLite(pragmas string) {
|
func InitSQLite(pragmas string) {
|
||||||
pragmasArray := strings.Split(pragmas, ";")
|
pragmasArray := strings.Split(pragmas, ";")
|
||||||
facade.InitSQLite(pragmasArray)
|
facade.InitSQLite(pragmasArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export HandleQuery
|
//export CreateRowIterator
|
||||||
func HandleQuery(input []byte) []byte {
|
func CreateRowIterator(input []byte) C.int {
|
||||||
var out []byte
|
var it = &facade.RowsIter{}
|
||||||
facade.HandleQuery(&input, &out)
|
it.Exec(input)
|
||||||
return out
|
ptr := C.int(len(iterators))
|
||||||
|
iterators[len(iterators)] = it
|
||||||
|
defer fmt.Println(ptr)
|
||||||
|
return ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
//export NextRow
|
||||||
|
func NextRow(itid C.int) unsafe.Pointer {
|
||||||
|
it := iterators[int(itid)]
|
||||||
|
if it.Result != nil {
|
||||||
|
itersize[int(itid)] = C.int(len(it.Result))
|
||||||
|
return C.CBytes(it.Result)
|
||||||
|
}
|
||||||
|
data := it.Next()
|
||||||
|
if data == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
itersize[int(itid)] = C.int(len(data))
|
||||||
|
res := C.CBytes(data)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
//export GetLen
|
||||||
|
func GetLen(idx C.int) C.int {
|
||||||
|
return itersize[int(idx)]
|
||||||
|
}
|
||||||
|
|
||||||
|
//export FreeIter
|
||||||
|
func FreeIter(itid C.int) {
|
||||||
|
it := iterators[int(itid)]
|
||||||
|
it.Close()
|
||||||
|
delete(iterators, int(itid))
|
||||||
|
delete(itersize, int(itid))
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {}
|
func main() {}
|
||||||
|
|
|
@ -19,6 +19,11 @@ typedef struct { const char *p; ptrdiff_t n; } _GoString_;
|
||||||
/* Start of preamble from import "C" comments. */
|
/* Start of preamble from import "C" comments. */
|
||||||
|
|
||||||
|
|
||||||
|
#line 3 "dal.go"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#line 1 "cgo-generated-wrapper"
|
||||||
|
|
||||||
|
|
||||||
/* End of preamble from import "C" comments. */
|
/* End of preamble from import "C" comments. */
|
||||||
|
@ -75,7 +80,10 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void InitSQLite(GoString pragmas);
|
extern void InitSQLite(GoString pragmas);
|
||||||
extern GoSlice HandleQuery(GoSlice input);
|
extern int CreateRowIterator(GoSlice input);
|
||||||
|
extern void* NextRow(int itid);
|
||||||
|
extern int GetLen(int idx);
|
||||||
|
extern void FreeIter(int itid);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ require (
|
||||||
github.com/nesterow/dal/pkg/adapter v0.0.0-20240820192515-7a408c994181 // indirect
|
github.com/nesterow/dal/pkg/adapter v0.0.0-20240820192515-7a408c994181 // indirect
|
||||||
github.com/nesterow/dal/pkg/builder v0.0.0-20240820192515-7a408c994181 // indirect
|
github.com/nesterow/dal/pkg/builder v0.0.0-20240820192515-7a408c994181 // indirect
|
||||||
github.com/nesterow/dal/pkg/filters v0.0.0-20240820192515-7a408c994181 // indirect
|
github.com/nesterow/dal/pkg/filters v0.0.0-20240820192515-7a408c994181 // indirect
|
||||||
github.com/nesterow/dal/pkg/handler v0.0.0-20240820192515-7a408c994181 // indirect
|
github.com/nesterow/dal/pkg/handler v0.0.0-20240823050743-ae641b7ee894 // indirect
|
||||||
github.com/nesterow/dal/pkg/proto v0.0.0-20240820230328-f8e28d2a2e42 // indirect
|
github.com/nesterow/dal/pkg/proto v0.0.0-20240820230328-f8e28d2a2e42 // indirect
|
||||||
github.com/nesterow/dal/pkg/utils v0.0.0-20240820192515-7a408c994181 // indirect
|
github.com/nesterow/dal/pkg/utils v0.0.0-20240820192515-7a408c994181 // indirect
|
||||||
github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986 // indirect
|
github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986 // indirect
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { test, expect } from "bun:test";
|
import { test, expect } from "bun:test";
|
||||||
import DAL from "../Builder";
|
import {DAL} from "..";
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
database: "test.sqlite",
|
database: "test.sqlite",
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const dal = require("../../build/Release/dal.node");
|
const dal = require("../../build/Release/dal.node");
|
||||||
dal.InitSQLite(Buffer.from([]));
|
//dal.InitSQLite(Buffer.from([]));
|
||||||
const buf = fs.readFileSync("./pkg/__test__/proto_test.msgpack");
|
const buf = fs.readFileSync("./pkg/__test__/proto_test.msgpack");
|
||||||
data = dal.Handle(buf);
|
//console.log(dal.Handle(buf));
|
||||||
console.log(data);
|
const iter = dal.RowIterator(buf);
|
||||||
|
console.log(iter);
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const b = iter.next();
|
||||||
|
if (b.length === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
console.log(b.toString());
|
||||||
|
}
|
||||||
|
iter.free();
|
Binary file not shown.
|
@ -1,6 +1,7 @@
|
||||||
package facade
|
package facade
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/nesterow/dal/pkg/adapter"
|
"github.com/nesterow/dal/pkg/adapter"
|
||||||
|
@ -25,6 +26,73 @@ func InitSQLite(pragmas []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RowsIter struct {
|
||||||
|
Result []byte
|
||||||
|
rows *sql.Rows
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RowsIter) Exec(input []byte) {
|
||||||
|
InitSQLite([]string{})
|
||||||
|
req := proto.Request{}
|
||||||
|
_, e := req.UnmarshalMsg(input)
|
||||||
|
query, err := req.Parse(adapter.GetDialect(db.Type))
|
||||||
|
if err != nil || e != nil {
|
||||||
|
res := proto.Response{
|
||||||
|
Msg: "failed to unmarshal request",
|
||||||
|
}
|
||||||
|
r.Result, _ = res.MarshalMsg(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if query.Exec {
|
||||||
|
result, err := db.Exec(query)
|
||||||
|
if err != nil {
|
||||||
|
res := proto.Response{
|
||||||
|
Msg: err.Error(),
|
||||||
|
}
|
||||||
|
r.Result, _ = res.MarshalMsg(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ra, _ := result.RowsAffected()
|
||||||
|
la, _ := result.LastInsertId()
|
||||||
|
res := proto.Response{
|
||||||
|
Id: 0,
|
||||||
|
RowsAffected: ra,
|
||||||
|
LastInsertId: la,
|
||||||
|
}
|
||||||
|
r.Result, _ = res.MarshalMsg(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rows, err := db.Query(query)
|
||||||
|
if err != nil {
|
||||||
|
res := proto.Response{
|
||||||
|
Msg: err.Error(),
|
||||||
|
}
|
||||||
|
r.Result, _ = res.MarshalMsg(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.rows = rows
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RowsIter) Close() {
|
||||||
|
if r.rows == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.rows.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RowsIter) Next() []byte {
|
||||||
|
columns, _ := r.rows.Columns()
|
||||||
|
types, _ := r.rows.ColumnTypes()
|
||||||
|
data := make([]interface{}, len(columns))
|
||||||
|
for i := range data {
|
||||||
|
typ := reflect.New(types[i].ScanType()).Interface()
|
||||||
|
data[i] = &typ
|
||||||
|
}
|
||||||
|
r.rows.Scan(data...)
|
||||||
|
cols, _ := proto.MarshalRow(data)
|
||||||
|
return cols
|
||||||
|
}
|
||||||
|
|
||||||
func HandleQuery(input *[]byte, output *[]byte) int {
|
func HandleQuery(input *[]byte, output *[]byte) int {
|
||||||
InitSQLite([]string{})
|
InitSQLite([]string{})
|
||||||
req := proto.Request{}
|
req := proto.Request{}
|
||||||
|
@ -83,6 +151,7 @@ func HandleQuery(input *[]byte, output *[]byte) int {
|
||||||
*output, _ = res.MarshalMsg(nil)
|
*output, _ = res.MarshalMsg(nil)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
defer rows.Close()
|
||||||
columns, _ := rows.Columns()
|
columns, _ := rows.Columns()
|
||||||
types, _ := rows.ColumnTypes()
|
types, _ := rows.ColumnTypes()
|
||||||
cols, _ := proto.MarshalRow(columns)
|
cols, _ := proto.MarshalRow(columns)
|
||||||
|
|
Loading…
Reference in a new issue