eaigner / jet Goto Github PK
View Code? Open in Web Editor NEWJet is a super-flexible and lightweight SQL interface for Go
License: MIT License
Jet is a super-flexible and lightweight SQL interface for Go
License: MIT License
Is this not necessary when working with Postgres
import "github.com/lib/pq"
This code below works: what driver is being used?
package db
import (
"fmt"
"github.com/eaigner/jet"
//_ "github.com/lib/pq"
)
func OpenPg() *jet.Db {
db, err := jet.Open("postgres", "dbname=mobifit_dev user=postgres password=password host=localhost sslmode=disable")
if err != nil {
panic(err)
}
if err := db.Ping(); err != nil {
panic(err)
}
db.LogFunc = func(queryId, query string, args ...interface{}) {
fmt.Printf("JET: %s ARG: %v\n", query, args)
}
return db
}
// Elsewhere
db := OpenPg()
var amount int
db.Query("SELECT 2").Rows(&amount)
fmt.Println(amount) // = 2
Line 72 in ae59b2c
In the case of a transaction, jet always creates a prepared statement but never deallocate them. It looks like postgres automatically clears prepared statement when the session is reset, MySQL doesn't. When using this feature for too long, MySQL quickly reaches the max amount of created statements.
I'm not quite sure what the right behavior should be but deallocation should at least be doable by the users (currently the statement isn't exposed).
becaues the gen.Intn
are not thread safe
package main
import (
"math/rand"
"runtime"
"sync"
"time"
)
var (
gen = rand.New(rand.NewSource(time.Now().UnixNano()))
)
func main() {
runtime.GOMAXPROCS(2)
g := sync.WaitGroup{}
for i := 0; i < 2; i++ {
g.Add(1)
go func() {
_ = gen.Int()
g.Done()
}()
}
g.Wait()
}
WARNING: DATA RACE
Write by goroutine 5:
math/rand.(_rngSource).Int63()
/usr/local/go/src/pkg/math/rand/rng.go:233 +0x3a
math/rand.(_Rand).Int63()
/usr/local/go/src/pkg/math/rand/rand.go:37 +0x48
math/rand.(*Rand).Int()
/usr/local/go/src/pkg/math/rand/rand.go:47 +0x32
main.func·001()
/project/works/open/src/example/main.go:45 +0x4f
gosched0()
/usr/local/go/src/pkg/runtime/proc.c:1218 +0x9f
Previous write by goroutine 4:
math/rand.(_rngSource).Int63()
/usr/local/go/src/pkg/math/rand/rng.go:233 +0x3a
math/rand.(_Rand).Int63()
/usr/local/go/src/pkg/math/rand/rand.go:37 +0x48
math/rand.(*Rand).Int()
/usr/local/go/src/pkg/math/rand/rand.go:47 +0x32
main.func·001()
/project/works/open/src/example/main.go:45 +0x4f
gosched0()
/usr/local/go/src/pkg/runtime/proc.c:1218 +0x9f
Goroutine 5 (running) created at:
main.main()
/project/works/open/src/example/main.go:47 +0x145
runtime.main()
/usr/local/go/src/pkg/runtime/proc.c:182 +0x91
Goroutine 4 (finished) created at:
main.main()
/project/works/open/src/example/main.go:47 +0x145
runtime.main()
/usr/local/go/src/pkg/runtime/proc.c:182 +0x91
It is now: github.com/lib/pq
db_test.go:4: _ "github.com/bmizerany/pq"
tx_test.go:4: _ "github.com/bmizerany/pq"
I see seldom errors like this one:
sql: expected 12 arguments, got 1
When logging the query that triggered the error, I can see that the query is actually the wrong one:
Query: &jet.runner{db:(*sql.DB)(0xc2000d02a0), tx:(*sql.Tx)(nil), stmt:(*sql.Stmt)(0xc20165d600), qo:(*sql.DB)(0xc2000d02a0), conv:(*jet.snakeConv)(0x8e0a88), expand:false, txnId:"", query:"select * from users WHERE authentication_token = ? limit 1", lastErr:error(nil), args:[]interface {}{"XXXXXX"}, logger:(*jet.Logger)(nil), lru:(*jet.lruCache)(0xc2000c1820)}
So for some reason, Jet gets confused and uses the wrong statement which then fails since the passed arguments don't match.
Any idea what's going on?
Couldn't successfully query a table containing columns of type decimal. I thought I was doing something wrong, but looking through the tests and source leaves me doubting whether there is support at all.
Does Jet have support for returning multiple result sets?
E.g in one query select * from x; select * from y
, and then you iterate through the results. This would be useful for eager loading.
As far as I can see there is no way of getting this from a result. I see in your tests you use some PostgreSQL specific queries to work around the issue.
Often if I have a bad SQL query and the mapping failsI don't get the root error, because instead I get a Panic from the q.stmt.close() (query.go:36)
A simple fix was to either prevent the panic q.stmt.close() or this seem to work too:
if q.db.LRUCache == nil && q.stmt != nil {
q.stmt.Close()
}
Running: [go, test]
warning: building out-of-date packages:
github.com/eaigner/jet
github.com/tcolar/phpserializer
installing these packages with 'go test -i' will speed future tests.
2013/09/12 14:10:22 drupsway_test.go:27: Test Start
--- FAIL: TestProducts (0.00 seconds)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x28 pc=0x4b883d]
goroutine 4 [running]:
testing.func·004()
/usr/local/go/src/pkg/testing/testing.go:348 +0xcd
sync/atomic.CompareAndSwapUint32()
/usr/local/go/src/pkg/sync/atomic/asm_amd64.s:14 +0xd
sync.(_Mutex).Lock(0x28)
/usr/local/go/src/pkg/sync/mutex.go:43 +0x35
sync.(_RWMutex).Lock(0x28)
/usr/local/go/src/pkg/sync/rwmutex.go:78 +0x25
database/sql.(_Stmt).Close(0x0, 0x0, 0x0)
/usr/local/go/src/pkg/database/sql/sql.go:1241 +0x3c
github.com/eaigner/jet.func·001()
/home/tcolar/DEV/go/src/github.com/eaigner/jet/query.go:36 +0x4c
github.com/eaigner/jet.(_query).Rows(0xc20016bc40, 0x6bf840, 0xc20012a960, 0x0, 0x0, ...)
/home/tcolar/DEV/go/src/github.com/eaigner/jet/query.go:42 +0xb9
......
goroutine 2 [syscall]:
exit status 2
FAIL 0.034s
Hi, just curious if this is supposed to work with MySQL?
I tried to use it like this:
Jet, err = jet.Open("mysql", spec)
rowNum := 500
var w World
Jet.Query(worldSelect, rowNum).Value(&w)
For the query, I tried these:
const worldSelect = "SELECT id,randomNumber FROM World where id = ?"
const worldSelect = "SELECT id,randomNumber FROM World where id = $1"
const worldSelect = "SELECT id,randomNumber FROM World where id = "
but all failed, with these various error messages:
SQL: 2013/05/08 00:12:46 SELECT id,randomNumber FROM World where id = $1 ["8082"]
Error scanning world row: Error 1054: Unknown column '$1' in 'where clause'
SQL: 2013/05/08 00:13:04 SELECT id,randomNumber FROM World where id = ? ["8082"]
Error scanning world row: Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?$1' at line 1
SQL: 2013/05/08 00:13:20 SELECT id,randomNumber FROM World where id = ["8082"]
Error scanning world row: Error 1054: Unknown column '$1' in 'where clause'
Upacking to a struct like this
type Result struct {
*TypeB
Name string
}
Results in a reflection error
I must be missing something obvious, but I can't figure out how to create prepared statements. Here is what I expected:
db.Query(`SELECT * FROM users WHERE username = ? LIMIT 1`, "eaigner").Rows(&user)
I'm expecting the API to match http://golang.org/pkg/database/sql/#DB.Query am I wrong?
My PostgreSQL table is:
CREATE TABLE users (
id serial primary key,
username varchar(64),
password varchar(128),
email varchar(64),
firstname varchar(64),
lastname varchar(128),
activated boolean
);
Unfortunately, the following code returns 2014/01/03 17:28:05 Query failed; pq: syntax error at or near "$6"
db, err := jet.Open("postgres", cfg.Database.ConnectionString)
if err != nil {
log.Fatalf("Error while connecting to the database; %s", err)
}
err = db.Query(`
INSERT INTO "users" (
"username",
"password",
"email",
"firstname",
"activated"
)
VALUES (
$1,
$2,
$3,
$4,
$5
)`,
"admin",
utils.HashPassword(admin),
"[email protected]",
"John",
"Doe",
true
).Run()
if err != nil {
log.Fatalf("Query failed; %s", err)
}
Am I doing something wrong or is it an issue with the latest version of jet?
I tried to look at Hood and how I could add this feature but I got stuck in mapper.go
land.
I'm not quite sure how to unmap a timestamp value coming from MySql into a time.Time
value. This MySql driver seems to be doing the conversion for you (optionally) https://github.com/go-sql-driver/mysql#timetime-support but I didn't manage a way to get the unmapping to work if the data comes as a byte array or another type.
As far as I can tell, the challenge is that unpackStruct
tries to handle the timestamp value and we end up with a blank time value,
func (m *mapper) unpackStruct(keys []string, values []interface{}, out reflect.Value) error
I really wish I could help, but I'm stuck :(
I have a model like this:
type User struct {
Id int
Email string
HashedPassword []byte
CreatedAt time.Time
ConfirmedAt pq.NullTime
}
and if I write some code to fetch a value from the database where the time has already been set:
func (u *User) GetByEmail(email string) error {
pg := db.OpenPg()
defer pg.Close()
err := pg.Query("SELECT * FROM _users__get_by_email($1);",
email).
Rows(u)
fmt.Println(u)
if u.Id == 0 {
err = db.EntityNotFound
}
return err
}
I get this error below:
[martini] PANIC: reflect.Value.Convert: value of type time.Time cannot be converted to type pq.NullTime
/home/lee/Code/gocode/src/github.com/codegangsta/martini/recovery.go:48 (0x468046)
com/codegangsta/martini.func.003: log.Printf("PANIC: %s\n%s", err, debug.Stack())
/home/lee/.gvm/gos/go1.2/src/pkg/runtime/panic.c:248 (0x414ee6)
panic: runtime·newstackcall(d->fn, (byte*)d->args, d->siz);
/home/lee/.gvm/gos/go1.2/src/pkg/reflect/value.go:2210 (0x55454f)
Value.Convert: panic("reflect.Value.Convert: value of type " + v.typ.String() + " cannot be converted to type " + t.String())
/home/lee/Code/gocode/src/github.com/eaigner/jet/mapper.go:119 (0x59a6af)
com/eaigner/jet.convertAndSet: to.Set(from.Convert(to.Type()))
/home/lee/Code/gocode/src/github.com/eaigner/jet/mapper.go:202 (0x59bb7a)
com/eaigner/jet.setValueFromTime: convertAndSet(t, to)
/home/lee/Code/gocode/src/github.com/eaigner/jet/mapper.go:136 (0x59abcd)
com/eaigner/jet.setValue: setValueFromTime(t, to)
/home/lee/Code/gocode/src/github.com/eaigner/jet/mapper.go:112 (0x59a5b1)
com/eaigner/jet.(*mapper).unpackSimple: setValue(reflect.Indirect(reflect.ValueOf(values[0])), out)
/home/lee/Code/gocode/src/github.com/eaigner/jet/mapper.go:75 (0x599e05)
com/eaigner/jet.(*mapper).unpackStruct: return m.unpackSimple(nil, values, out)
/home/lee/Code/gocode/src/github.com/eaigner/jet/mapper.go:51 (0x599ace)
com/eaigner/jet.(*mapper).unpackValue: return m.unpackStruct(keys, values, out)
/home/lee/Code/gocode/src/github.com/eaigner/jet/mapper.go:86 (0x59a039)
com/eaigner/jet.(*mapper).unpackStruct: m.unpackValue(nil, values[i:i+1], field)
/home/lee/Code/gocode/src/github.com/eaigner/jet/mapper.go:51 (0x599ace)
com/eaigner/jet.(*mapper).unpackValue: return m.unpackStruct(keys, values, out)
/home/lee/Code/gocode/src/github.com/eaigner/jet/mapper.go:43 (0x599956)
com/eaigner/jet.(*mapper).unpackValue: return m.unpackValue(keys, values, reflect.Indirect(out))
/home/lee/Code/gocode/src/github.com/eaigner/jet/mapper.go:20 (0x599246)
com/eaigner/jet.(*mapper).unpack: return m.unpackValue(keys, values, val)
/home/lee/Code/gocode/src/github.com/eaigner/jet/query.go:118 (0x59c581)
com/eaigner/jet.(*jetQuery).Rows: err = colMapper.unpack(cols, cont, v)
/home/lee/Code/gocode/src/mobifit/app/models/user.go:130 (0x4292fd)
(*User).GetByEmail: Rows(u)
/home/lee/Code/gocode/src/mobifit/app/controllers/page_controller.go:12 (0x427d73)
PageContact: err := u.GetByEmail("[email protected]")
/home/lee/.gvm/gos/go1.2/src/pkg/runtime/asm_amd64.s:338 (0x425922)
call16: CALLFN(call16, 16)
/home/lee/.gvm/gos/go1.2/src/pkg/reflect/value.go:474 (0x54e2eb)
Value.call: call(fn, ptr, uint32(size))
/home/lee/.gvm/gos/go1.2/src/pkg/reflect/value.go:345 (0x54d3dd)
Value.Call: return v.call("Call", in)
/home/lee/Code/gocode/src/github.com/codegangsta/inject/inject.go:98 (0x546214)
com/codegangsta/inject.(*injector).Invoke: return reflect.ValueOf(f).Call(in), nil
/home/lee/Code/gocode/src/github.com/codegangsta/martini/env.go:1 (0x46991c)
com/codegangsta/martini.(*context).Invoke: package martini
/home/lee/Code/gocode/src/github.com/codegangsta/martini/router.go:244 (0x467707)
com/codegangsta/martini.(*routeContext).run: vals, err := r.Invoke(handler)
/home/lee/Code/gocode/src/github.com/codegangsta/martini/router.go:178 (0x467164)
com/codegangsta/martini.(*route).Handle: context.run()
/home/lee/Code/gocode/src/github.com/codegangsta/martini/router.go:91 (0x46863e)
com/codegangsta/martini.*route.Handle.fm: _, err := context.Invoke(route.Handle)
/home/lee/.gvm/gos/go1.2/src/pkg/runtime/asm_amd64.s:339 (0x425982)
call32: CALLFN(call32, 32)
/home/lee/.gvm/gos/go1.2/src/pkg/reflect/value.go:474 (0x54e2eb)
Value.call: call(fn, ptr, uint32(size))
/home/lee/.gvm/gos/go1.2/src/pkg/reflect/value.go:345 (0x54d3dd)
Value.Call: return v.call("Call", in)
/home/lee/Code/gocode/src/github.com/codegangsta/inject/inject.go:98 (0x546214)
com/codegangsta/inject.(*injector).Invoke: return reflect.ValueOf(f).Call(in), nil
/home/lee/Code/gocode/src/github.com/codegangsta/martini/env.go:1 (0x46991c)
com/codegangsta/martini.(*context).Invoke: package martini
/home/lee/Code/gocode/src/github.com/codegangsta/martini/router.go:91 (0x466689)
com/codegangsta/martini.(*router).Handle: _, err := context.Invoke(route.Handle)
/home/lee/Code/gocode/src/github.com/codegangsta/martini/martini.go:104 (0x467fb0)
com/codegangsta/martini.Router.Handle.fm: m.Action(r.Handle)
/home/lee/.gvm/gos/go1.2/src/pkg/runtime/asm_amd64.s:340 (0x4259e2)
call64: CALLFN(call64, 64)
/home/lee/.gvm/gos/go1.2/src/pkg/reflect/value.go:474 (0x54e2eb)
Value.call: call(fn, ptr, uint32(size))
/home/lee/.gvm/gos/go1.2/src/pkg/reflect/value.go:345 (0x54d3dd)
Value.Call: return v.call("Call", in)
/home/lee/Code/gocode/src/github.com/codegangsta/inject/inject.go:98 (0x546214)
com/codegangsta/inject.(*injector).Invoke: return reflect.ValueOf(f).Call(in), nil
/home/lee/Code/gocode/src/github.com/codegangsta/martini/martini.go:147 (0x465748)
com/codegangsta/martini.(*context).run: _, err := c.Invoke(c.handlers[c.index])
/home/lee/Code/gocode/src/github.com/codegangsta/martini/martini.go:138 (0x46568b)
com/codegangsta/martini.(*context).Next: c.run()
/home/lee/Code/gocode/src/github.com/martini-contrib/sessions/sessions.go:93 (0x470af4)
com/martini-contrib/sessions.func.002: c.Next()
/home/lee/.gvm/gos/go1.2/src/pkg/runtime/asm_amd64.s:340 (0x4259e2)
call64: CALLFN(call64, 64)
/home/lee/.gvm/gos/go1.2/src/pkg/reflect/value.go:474 (0x54e2eb)
Value.call: call(fn, ptr, uint32(size))
/home/lee/.gvm/gos/go1.2/src/pkg/reflect/value.go:345 (0x54d3dd)
Value.Call: return v.call("Call", in)
/home/lee/Code/gocode/src/github.com/codegangsta/inject/inject.go:98 (0x546214)
com/codegangsta/inject.(*injector).Invoke: return reflect.ValueOf(f).Call(in), nil
/home/lee/Code/gocode/src/github.com/codegangsta/martini/martini.go:147 (0x465748)
com/codegangsta/martini.(*context).run: _, err := c.Invoke(c.handlers[c.index])
/home/lee/Code/gocode/src/github.com/codegangsta/martini/martini.go:138 (0x46568b)
com/codegangsta/martini.(*context).Next: c.run()
/home/lee/Code/gocode/src/github.com/codegangsta/martini/recovery.go:57 (0x468366)
com/codegangsta/martini.func.004: c.Next()
/home/lee/.gvm/gos/go1.2/src/pkg/runtime/asm_amd64.s:340 (0x4259e2)
call64: CALLFN(call64, 64)
/home/lee/.gvm/gos/go1.2/src/pkg/reflect/value.go:474 (0x54e2eb)
Value.call: call(fn, ptr, uint32(size))
/home/lee/.gvm/gos/go1.2/src/pkg/reflect/value.go:345 (0x54d3dd)
Value.Call: return v.call("Call", in)
/home/lee/Code/gocode/src/github.com/codegangsta/inject/inject.go:98 (0x546214)
com/codegangsta/inject.(*injector).Invoke: return reflect.ValueOf(f).Call(in), nil
/home/lee/Code/gocode/src/github.com/codegangsta/martini/martini.go:147 (0x465748)
com/codegangsta/martini.(*context).run: _, err := c.Invoke(c.handlers[c.index])
/home/lee/Code/gocode/src/github.com/codegangsta/martini/martini.go:138 (0x46568b)
com/codegangsta/martini.(*context).Next: c.run()
/home/lee/Code/gocode/src/github.com/codegangsta/martini/logger.go:16 (0x467d78)
com/codegangsta/martini.func.001: c.Next()
/home/lee/.gvm/gos/go1.2/src/pkg/runtime/asm_amd64.s:340 (0x4259e2)
call64: CALLFN(call64, 64)
/home/lee/.gvm/gos/go1.2/src/pkg/reflect/value.go:474 (0x54e2eb)
Value.call: call(fn, ptr, uint32(size))
/home/lee/.gvm/gos/go1.2/src/pkg/reflect/value.go:345 (0x54d3dd)
Value.Call: return v.call("Call", in)
/home/lee/Code/gocode/src/github.com/codegangsta/inject/inject.go:98 (0x546214)
com/codegangsta/inject.(*injector).Invoke: return reflect.ValueOf(f).Call(in), nil
/home/lee/Code/gocode/src/github.com/codegangsta/martini/martini.go:147 (0x465748)
com/codegangsta/martini.(*context).run: _, err := c.Invoke(c.handlers[c.index])
/home/lee/Code/gocode/src/github.com/codegangsta/martini/martini.go:68 (0x464c73)
com/codegangsta/martini.(*Martini).ServeHTTP: m.createContext(res, req).run()
/home/lee/.gvm/gos/go1.2/src/pkg/net/http/server.go:1597 (0x43d4fe)
serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/home/lee/.gvm/gos/go1.2/src/pkg/net/http/server.go:1167 (0x43b507)
(*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/home/lee/.gvm/gos/go1.2/src/pkg/runtime/proc.c:1394 (0x4191e0)
goexit: runtime·goexit(void)
[martini] Completed 500 Internal Server Error in 136.896358ms
Due to a bug in Go https://code.google.com/p/go/issues/detail?id=5718 autoreconnection doesn't work with prepared statements. It sometimes leads to issues and bad connections. I would be nice if Jet could expose an interface to handle errors and let the developers reconnect and retry the query.
I noticed this method, but it's not currently exported so I can't hook into it.
https://github.com/eaigner/jet/blob/master/query.go#L132
Thanks
I must be missing something simple here! Can someone point it out to me?
err := DB.Query(`INSERT INTO "users" ( "email" ) VALUES ( $1 )`, "[email protected]").Run()
fmt.Println(err)
typ := reflect.TypeOf(err)
fmt.Println(typ)
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
for i := 0; i < typ.NumField(); i++ {
p := typ.Field(i)
if !p.Anonymous {
fmt.Println(p.Name, "--", p.Type)
}
}
Yields, as expected:
pq: duplicate key value violates unique constraint "unique_email"
*pq.Error
Severity -- string
Code -- pq.ErrorCode
Message -- string
Detail -- string
Hint -- string
Position -- string
InternalPosition -- string
InternalQuery -- string
Where -- string
Schema -- string
Table -- string
Column -- string
DataTypeName -- string
Constraint -- string
File -- string
Line -- string
Routine -- string
But if I add:
fmt.Println(err.Code)
I get this when I build:
err.Code undefined (type error has no field or method Code)
Much thanks!
Here is my implementation of a MySQL time encoder/decoder: https://gist.github.com/mattetti/6692464
I'm having an issue where I have a User type like this:
type User struct {
Id int
Name string
Email string
CreatedAt DbTime
}
When I save the record, everything works fine, the encoder seems to work. But when I retrieve the row, the decoder reports properly decoding the object (from the output) but the user object itself has a zeroed CreatedAt
value.
I'm very confused and I'm not sure if that's an issue due to the way I use the interface, or an actual bug.
My test is very simple:
func TestUserDbTime(t *testing.T) {
var user User
u := User{Name: "matt", CreatedAt: DbTime{String:"2013-07-17 06:08:04 +0000 UTC"}}
u.Create()
err := Db.Query(`select * from users limit 1`).Rows(&user)
assert.Nil(t, err)
t.Logf("user: %#v", user)
assert.False(t, user.CreatedAt.IsZero())
}
Whatever I do, the user.CreatedAt
value is zeroed. What am I missing?
In the following example, I would like the User field of the Post struct to be filled in with the user data from the query. Is such a thing possible? Currently, I am running two select statements. First getting the post and then getting the user.
type User struct {
Id int64
Username string
}
type Post struct {
Id int64
Text string
User *User
}
func GetPost(id int64) {
var post Post
db.Query(`SELECT * FROM "post" LEFT JOIN "user" ON user.id = post.user_id`).Rows(&post)
}
Using MySQL I wasn't able to map a tinyint to a go boolean type.
I would like to be able to do that:
type Project struct {
Id int
Name string
Public bool
Active bool
}
var project Project
_ := Db.Query(`select * from projects WHERE id = ? limit 1`, id).Rows(&project)
➜ ~ go version
go version go1.1.2 linux/amd64
➜ ~ go get github.com/eaigner/jet
gopath/src/github.com/eaigner/jet/lru.go:84: undefined: sha1.Sum
Since yesterday I've been fighting a serious issue since updating to the latest jet (using go 1.2 amd64).
Symptom is that when I do any kind of "update" query, that query "deadlocks" and never returns.
After much debugging I found the following:
In jet query.Rows() the defer that contains "q.m.Unlock()" was not being called.
Took a while to find why, it turns out another defer, the one for "rows.Close()" is hanging.
I'm still not getting why rows.Close() is hanging however, i was thinking that maybe it was nil and casing a panic but that doesn't seem to be the case.
If I take out the "defer rows.Close()" then all works properly although I would think that's probably not the right thing to do.
I haven't found yet what might be causing rows.close to hang however .... any ideas ?
Jet does not include a LICENSE file. Can you clarify which license Jet is licensed under?
This is a great lightweight framework, but I wish it had the ability to read one row at a time. I have some larger queries that I can't afford to pull completely into memory. Maybe something like a callback where a false return means "I'm done fetching rows now"?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.