Skip to content

Commit

Permalink
Merge pull request #947 from go-kivik/Query2
Browse files Browse the repository at this point in the history
More query support
  • Loading branch information
flimzy committed Apr 25, 2024
2 parents a146daa + afbddfb commit 0f1c059
Show file tree
Hide file tree
Showing 11 changed files with 692 additions and 137 deletions.
39 changes: 35 additions & 4 deletions x/sqlite/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@
package sqlite

import (
"bytes"
"context"
"crypto/md5"
"database/sql"
"fmt"
"log"
"os"
"regexp"
"strings"
"testing"

"github.com/go-kivik/kivik/v4/driver"
Expand All @@ -41,6 +45,7 @@ type DB interface {
type testDB struct {
t *testing.T
DB
logs *bytes.Buffer
}

func (tdb *testDB) underlying() *sql.DB {
Expand Down Expand Up @@ -94,23 +99,49 @@ func newDB(t *testing.T) *testDB {
dsn = fmt.Sprintf("file:%x?mode=memory&cache=shared", md5sum.Sum(nil))
}
d := drv{}
client, err := d.NewClient(dsn, mock.NilOption)
buf := &bytes.Buffer{}
logger := log.New(buf, "", 0)
client, err := d.NewClient(dsn, OptionLogger(logger))
if err != nil {
t.Fatal(err)
}
if err := client.CreateDB(context.Background(), "test", nil); err != nil {
t.Fatal(err)
}
db, err := client.DB("test", nil)
db, err := client.DB("test", mock.NilOption)
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
_ = db.Close()
})
return &testDB{
DB: db.(DB),
t: t,
DB: db.(DB),
t: t,
logs: buf,
}
}

func (tdb *testDB) checkLogs(want []string) {
tdb.t.Helper()
if want == nil {
return
}
got := strings.Split(tdb.logs.String(), "\n")
if len(got) > 0 && got[len(got)-1] == "" {
got = got[:len(got)-1]
}
for i := 0; i < len(got) && i < len(want); i++ {
re := regexp.MustCompile(want[i])
if !re.MatchString(got[i]) {
tdb.t.Errorf("Unexpected log line: %d. Want /%s/,\n\t Got %s", i+1, want[i], got[i])
}
}
if len(got) > len(want) {
tdb.t.Errorf("Got %d more logs than expected: %s", len(got)-len(want), strings.Join(got[len(want):], "\n"))
}
if len(got) < len(want) {
tdb.t.Errorf("Got %d fewer logs than expected", len(want)-len(got))
}
}

Expand Down
14 changes: 13 additions & 1 deletion x/sqlite/designdocs.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import (
)

func (d *db) updateDesignDoc(ctx context.Context, tx *sql.Tx, rev revision, data *docData) error {
if !data.IsDesignDoc() {
return nil
}
stmt, err := tx.PrepareContext(ctx, d.query(`
INSERT INTO {{ .Design }} (id, rev, rev_id, language, func_type, func_name, func_body, auto_update)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
Expand All @@ -32,7 +35,7 @@ func (d *db) updateDesignDoc(ctx context.Context, tx *sql.Tx, rev revision, data
if _, err := stmt.ExecContext(ctx, data.ID, rev.rev, rev.id, data.DesignFields.Language, "map", name, view.Map, data.DesignFields.AutoUpdate); err != nil {
return err
}
if _, err := tx.ExecContext(ctx, d.ddocQuery(data.ID, name, viewMapTable)); err != nil {
if err := d.createViewMap(ctx, tx, data.ID, name, rev.String()); err != nil {
return err
}
}
Expand All @@ -59,3 +62,12 @@ func (d *db) updateDesignDoc(ctx context.Context, tx *sql.Tx, rev revision, data
}
return nil
}

func (d *db) createViewMap(ctx context.Context, tx *sql.Tx, ddoc, name, rev string) error {
for _, query := range viewMapSchema {
if _, err := tx.ExecContext(ctx, d.ddocQuery(ddoc, name, rev, query)); err != nil {
return err
}
}
return nil
}
51 changes: 51 additions & 0 deletions x/sqlite/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// http:https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

package sqlite

import (
"errors"
"strings"

"modernc.org/sqlite"
)

const (
// https://www.sqlite.org/rescode.html
codeSQLiteError = 1
)

func errIsAlreadyExists(err error) bool {
if err == nil {
return false
}
sqliteErr := new(sqlite.Error)
if errors.As(err, &sqliteErr) &&
sqliteErr.Code() == codeSQLiteError &&
strings.Contains(sqliteErr.Error(), "already exists") {
return true
}
return false
}

func errIsNoSuchTable(err error) bool {
if err == nil {
return false
}
sqliteErr := new(sqlite.Error)
if errors.As(err, &sqliteErr) &&
sqliteErr.Code() == codeSQLiteError &&
strings.Contains(sqliteErr.Error(), "no such table") {
return true
}
return false
}
21 changes: 20 additions & 1 deletion x/sqlite/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,13 @@ func jsonMarshal(s interface{}) []byte {
return j
}

// toMap produces a map from the fullDoc. It only considers a few of the
// meta fields; those used by map/reduce functions:
//
// - _id
// - _rev
// - _deleted
// - _attachments
func (d *fullDoc) toMap() map[string]interface{} {
var result map[string]interface{}
if err := json.Unmarshal(d.Doc, &result); err != nil {
Expand All @@ -424,13 +431,25 @@ func (d *fullDoc) toMap() map[string]interface{} {
if d.Deleted {
result["_deleted"] = true
}
if len(d.Attachments) > 0 {
attachments := make(map[string]interface{}, len(d.Attachments))
for name, att := range d.Attachments {
attachments[name] = map[string]interface{}{
"content_type": att.ContentType,
"digest": att.Digest.Digest(),
"length": att.Length,
"revpos": att.RevPos,
"stub": att.Stub,
}
}
result["_attachments"] = attachments
}
/*
Conflicts []string `json:"_conflicts,omitempty"`
DeletedConflicts []string `json:"_deleted_conflicts,omitempty"`
RevsInfo []map[string]string `json:"_revs_info,omitempty"`
Revisions *revsInfo `json:"_revisions,omitempty"`
LocalSeq int `json:"_local_seq,omitempty"`
Attachments map[string]*attachment `json:"_attachments,omitempty"`
*/
return result
}
2 changes: 1 addition & 1 deletion x/sqlite/put_designdocs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func TestDBPut_designDocs(t *testing.T) {
SELECT COUNT(*)
FROM sqlite_master
WHERE type = 'table'
AND name LIKE 'foo_map_bar_%'
AND name LIKE 'foo_%_map_bar_%'
`).Scan(&viewCount)
if err != nil {
t.Fatal(err)
Expand Down
Loading

0 comments on commit 0f1c059

Please sign in to comment.