Repository: upper/db (go)

Issue:
sqlite.New panics
reading the docs for [sqlite.New](https://pkg.go.dev/github.com/upper/db/v4@v4.2.0/adapter/sqlite#New), I'm not sure if I'm misunderstanding the docs, or if there's a bug.

From the function signature I expect this code to work:

```
package main

import (
        "database/sql"

        _ "github.com/mattn/go-sqlite3"

        "github.com/upper/db/v4/adapter/sqlite"
)

func test() {
        h, err := sql.Open("sqlite3", "file:test.db?mode=memory")
        if err != nil {
                panic(err)
        }

        sess, err := sqlite.New(h) // this panics
        if err != nil {
                panic(err)
        }

        if err := sess.Close(); err != nil {
                panic(err)
        }
}
```

but it does in fact panic:

```
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x7c3fdf]

goroutine 1 [running]:
github.com/upper/db/v4/adapter/sqlite.(*database).LookupName(0xd8c490, 0xa00af0, 0xc00026d930, 0x0, 0x0, 0xc0001ff680, 0xc0001ff5f0)
        $GOPATH/pkg/mod/github.com/upper/db/v4@v4.2.0/adapter/sqlite/database.go:100 +0x3f
github.com/upper/db/v4/internal/sqladapter.(*session).BindDB(0xc00026d930, 0xc00026d860, 0x9fcf98, 0xd8c490)
        $GOPATH/pkg/mod/github.com/upper/db/v4@v4.2.0/internal/sqladapter/session.go:518 +0xf2
github.com/upper/db/v4/internal/sqladapter.(*sqlAdapterWrapper).New(0xc0002a6220, 0xc00026d860, 0x97ed69, 0x18, 0xc00026d860, 0x0)
        $GOPATH/pkg/mod/github.com/upper/db/v4@v4.2.0/internal/sqladapter/sqladapter.go:72 +0x72
github.com/upper/db/v4/adapter/sqlite.New(...)
        $GOPATH/pkg/mod/github.com/upper/db/v4@v4.2.0/adapter/sqlite/sqlite.go:51
main.test()
        $PWD/test.go:17 +0x96
main.main()
        $PWD/main.go:151 +0x25
```

it seems to be looking for the connection URL, which isn't available because Open was not called?

The reason why I'm trying to do this is because I have a database migration tool which is in charge of creating tables, etc, but since database is in memory, if I close the `sql.DB` handle that I used to run the migrations, the database is lost.

I have figured out a solution for that problem (use `sqlite.ParseURL` to obtain a `ConnectionURL`, use the resulting DSN with `sql.Open`, and pass it as the settings argument to `sqlite.Open` _before_ closing the connection, so that the database is reused). What I'm wondering here is if the above program is supposed to work or not, and if not, why not?

Pull request:
Fix sqlite.New panic
Hi!

When using `sqlite.New(sqldb)` to create db session, `sess.ConnectionURL()` is `nil`. Therefore a nil-pointer panic throwed.

I'm using `PRAGMA database_list` to get database name, [here is the document about it](https://www.sqlite.org/pragma.html#pragma_database_list) .

Fix #633 

Patch:
diff --git a/adapter/sqlite/database.go b/adapter/sqlite/database.go
index 5a24614..4235524 100644
--- a/adapter/sqlite/database.go
+++ b/adapter/sqlite/database.go
@@ -97,11 +97,33 @@ func (*database) NewCollection() sqladapter.CollectionAdapter {
 }
 
 func (*database) LookupName(sess sqladapter.Session) (string, error) {
-	connURL, err := ParseURL(sess.ConnectionURL().String())
+	connURL := sess.ConnectionURL()
+	if connURL != nil {
+		connURL, err := ParseURL(connURL.String())
+		if err != nil {
+			return "", err
+		}
+		return connURL.Database, nil
+	}
+
+	// sess.ConnectionURL() is nil if using sqlite.New
+	rows, err := sess.SQL().Query(exql.RawSQL("PRAGMA database_list"))
 	if err != nil {
 		return "", err
 	}
-	return connURL.Database, nil
+	dbInfo := struct {
+		Name string `db:"name"`
+		File string `db:"file"`
+	}{}
+
+	if err := sess.SQL().NewIterator(rows).One(&dbInfo); err != nil {
+		return "", err
+	}
+	if dbInfo.File != "" {
+		return dbInfo.File, nil
+	}
+	// dbInfo.File is empty if in memory mode
+	return dbInfo.Name, nil
 }
 
 func (*database) TableExists(sess sqladapter.Session, name string) error {


Test patch:
diff --git a/adapter/sqlite/sqlite_test.go b/adapter/sqlite/sqlite_test.go
new file mode 100644
index 0000000..6274af3
--- /dev/null
+++ b/adapter/sqlite/sqlite_test.go
@@ -0,0 +1,55 @@
+package sqlite
+
+import (
+	"path/filepath"
+	"testing"
+
+	"database/sql"
+
+	"github.com/stretchr/testify/suite"
+	"github.com/upper/db/v4/internal/testsuite"
+)
+
+type AdapterTests struct {
+	testsuite.Suite
+}
+
+func (s *AdapterTests) SetupSuite() {
+	s.Helper = &Helper{}
+}
+
+func (s *AdapterTests) Test_Issue633_OpenSession() {
+	sess, err := Open(settings)
+	s.NoError(err)
+	defer sess.Close()
+
+	absoluteName, _ := filepath.Abs(settings.Database)
+	s.Equal(absoluteName, sess.Name())
+}
+
+func (s *AdapterTests) Test_Issue633_NewAdapterWithFile() {
+	sqldb, err := sql.Open("sqlite3", settings.Database)
+	s.NoError(err)
+
+	sess, err := New(sqldb)
+	s.NoError(err)
+	defer sess.Close()
+
+	absoluteName, _ := filepath.Abs(settings.Database)
+	s.Equal(absoluteName, sess.Name())
+}
+
+func (s *AdapterTests) Test_Issue633_NewAdapterWithMemory() {
+	sqldb, err := sql.Open("sqlite3", ":memory:")
+	s.NoError(err)
+
+	sess, err := New(sqldb)
+	s.NoError(err)
+	defer sess.Close()
+
+	s.Equal("main", sess.Name())
+}
+
+func TestAdapter(t *testing.T) {
+	suite.Run(t, &AdapterTests{})
+}