...

Source file src/github.com/go-kivik/kivik/v4/pouchdb/find_test.go

Documentation: github.com/go-kivik/kivik/v4/pouchdb

     1  // Licensed under the Apache License, Version 2.0 (the "License"); you may not
     2  // use this file except in compliance with the License. You may obtain a copy of
     3  // the License at
     4  //
     5  //  http://www.apache.org/licenses/LICENSE-2.0
     6  //
     7  // Unless required by applicable law or agreed to in writing, software
     8  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     9  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    10  // License for the specific language governing permissions and limitations under
    11  // the License.
    12  
    13  //go:build js
    14  
    15  package pouchdb
    16  
    17  import (
    18  	"context"
    19  	"encoding/json"
    20  	"fmt"
    21  	"runtime"
    22  	"strconv"
    23  	"strings"
    24  	"testing"
    25  
    26  	"github.com/gopherjs/gopherjs/js"
    27  	"gitlab.com/flimzy/testy"
    28  
    29  	"github.com/go-kivik/kivik/v4/driver"
    30  	"github.com/go-kivik/kivik/v4/pouchdb/bindings"
    31  	"github.com/go-kivik/kivik/v4/pouchdb/internal"
    32  )
    33  
    34  func init() {
    35  	memPouch := js.Global.Get("PouchDB").Call("defaults", map[string]interface{}{
    36  		"db": js.Global.Call("require", "memdown"),
    37  	})
    38  	js.Global.Set("PouchDB", memPouch)
    39  }
    40  
    41  func TestBuildIndex(t *testing.T) {
    42  	tests := []struct {
    43  		Ddoc     string
    44  		Name     string
    45  		Index    interface{}
    46  		Expected string
    47  	}{
    48  		{Expected: `{}`},
    49  		{Index: `{"fields":["foo"]}`, Expected: `{"fields":["foo"]}`},
    50  		{Index: `{"fields":["foo"]}`, Name: "test", Expected: `{"fields":["foo"],"name":"test"}`},
    51  		{Index: `{"fields":["foo"]}`, Name: "test", Ddoc: "_foo", Expected: `{"fields":["foo"],"name":"test","ddoc":"_foo"}`},
    52  	}
    53  	for i, test := range tests {
    54  		t.Run(strconv.Itoa(i), func(t *testing.T) {
    55  			result, err := buildIndex(test.Ddoc, test.Name, test.Index)
    56  			if err != nil {
    57  				t.Errorf("Build Index failed: %s", err)
    58  			}
    59  			r := js.Global.Get("JSON").Call("stringify", result).String()
    60  			if d := testy.DiffJSON([]byte(test.Expected), []byte(r)); d != nil {
    61  				t.Errorf("BuildIndex result differs:\n%s\n", d)
    62  			}
    63  		})
    64  	}
    65  }
    66  
    67  func TestExplain(t *testing.T) {
    68  	defaultLimit := int64(0)
    69  	if ver := internal.PouchDBVersion(t); strings.HasPrefix(ver, "9") {
    70  		defaultLimit = 25
    71  	}
    72  	type test struct {
    73  		db       *db
    74  		query    interface{}
    75  		expected *driver.QueryPlan
    76  		err      string
    77  	}
    78  	tests := testy.NewTable()
    79  	tests.Add("query error", test{
    80  		db:    &db{db: bindings.GlobalPouchDB().New("foo", nil)},
    81  		query: nil,
    82  		err:   "TypeError: Cannot read propert",
    83  	})
    84  	tests.Add("simple selector", func(t *testing.T) interface{} {
    85  		options := map[string]interface{}{
    86  			"bookmark":  "nil",
    87  			"conflicts": false,
    88  			"r":         []interface{}{49},
    89  			"sort":      map[string]interface{}{},
    90  			"use_index": []interface{}{},
    91  		}
    92  		if defaultLimit > 0 {
    93  			options["limit"] = defaultLimit
    94  		}
    95  
    96  		return test{
    97  			db:    &db{db: bindings.GlobalPouchDB().New("foo", nil)},
    98  			query: map[string]interface{}{"selector": map[string]interface{}{"_id": "foo"}},
    99  			expected: &driver.QueryPlan{
   100  				DBName: "foo",
   101  				Limit:  defaultLimit,
   102  				Index: map[string]interface{}{
   103  					"ddoc": nil,
   104  					"def": map[string]interface{}{
   105  						"fields": []interface{}{map[string]interface{}{"_id": "asc"}},
   106  					},
   107  					"name": "_all_docs",
   108  					"type": "special",
   109  				},
   110  				Options:  options,
   111  				Selector: map[string]interface{}{"_id": map[string]interface{}{"$eq": "foo"}},
   112  				Fields: func() []interface{} {
   113  					fmt.Println(runtime.Version())
   114  					if ver := runtime.Version(); strings.HasPrefix(ver, "go1.16") {
   115  						return []interface{}{}
   116  					}
   117  					// From GopherJS 17 on, null arrays are properly converted to nil
   118  					return nil
   119  				}(),
   120  				Range: map[string]interface{}{},
   121  			},
   122  		}
   123  	})
   124  	tests.Add("fields list", func(t *testing.T) interface{} {
   125  		options := map[string]interface{}{
   126  			"bookmark":  "nil",
   127  			"conflicts": false,
   128  			"fields":    []interface{}{"_id", map[string]interface{}{"type": "desc"}},
   129  			"r":         []interface{}{49},
   130  			"sort":      map[string]interface{}{},
   131  			"use_index": []interface{}{},
   132  		}
   133  		if defaultLimit > 0 {
   134  			options["limit"] = defaultLimit
   135  		}
   136  
   137  		return test{
   138  			db: &db{db: bindings.GlobalPouchDB().New("foo", nil)},
   139  			query: map[string]interface{}{
   140  				"selector": map[string]interface{}{"_id": "foo"},
   141  				"fields":   []interface{}{"_id", map[string]interface{}{"type": "desc"}},
   142  			},
   143  			expected: &driver.QueryPlan{
   144  				DBName: "foo",
   145  				Limit:  defaultLimit,
   146  				Index: map[string]interface{}{
   147  					"ddoc": nil,
   148  					"def": map[string]interface{}{
   149  						"fields": []interface{}{map[string]interface{}{"_id": "asc"}},
   150  					},
   151  					"name": "_all_docs",
   152  					"type": "special",
   153  				},
   154  				Options:  options,
   155  				Selector: map[string]interface{}{"_id": map[string]interface{}{"$eq": "foo"}},
   156  				Fields:   []interface{}{"_id", map[string]interface{}{"type": "desc"}},
   157  				Range:    map[string]interface{}{},
   158  			},
   159  		}
   160  	})
   161  	tests.Run(t, func(t *testing.T, tt test) {
   162  		result, err := tt.db.Explain(context.Background(), tt.query, nil)
   163  		if !testy.ErrorMatchesRE(tt.err, err) {
   164  			t.Errorf("Unexpected error: %s", err)
   165  		}
   166  		if err != nil {
   167  			return
   168  		}
   169  		if d := testy.DiffAsJSON(tt.expected, result); d != nil {
   170  			t.Error(d)
   171  		}
   172  	})
   173  }
   174  
   175  func TestUnmarshalQueryPlan(t *testing.T) {
   176  	tests := []struct {
   177  		name     string
   178  		input    string
   179  		expected *queryPlan
   180  		err      string
   181  	}{
   182  		{
   183  			name:  "non-array",
   184  			input: `{"fields":{}}`,
   185  			err:   "json: cannot unmarshal object into Go",
   186  		},
   187  		{
   188  			name:     "all_fields",
   189  			input:    `{"fields":"all_fields","dbname":"foo"}`,
   190  			expected: &queryPlan{DBName: "foo"},
   191  		},
   192  		{
   193  			name:     "simple field list",
   194  			input:    `{"fields":["foo","bar"],"dbname":"foo"}`,
   195  			expected: &queryPlan{Fields: []interface{}{"foo", "bar"}, DBName: "foo"},
   196  		},
   197  		{
   198  			name:  "complex field list",
   199  			input: `{"dbname":"foo", "fields":[{"foo":"asc"},{"bar":"desc"}]}`,
   200  			expected: &queryPlan{
   201  				DBName: "foo",
   202  				Fields: []interface{}{
   203  					map[string]interface{}{"foo": "asc"},
   204  					map[string]interface{}{"bar": "desc"},
   205  				},
   206  			},
   207  		},
   208  		{
   209  			name:  "invalid bare string",
   210  			input: `{"fields":"not_all_fields"}`,
   211  			err:   "json: cannot unmarshal string into Go",
   212  		},
   213  	}
   214  	for _, test := range tests {
   215  		t.Run(test.name, func(t *testing.T) {
   216  			result := new(queryPlan)
   217  			err := json.Unmarshal([]byte(test.input), &result)
   218  			if !testy.ErrorMatchesRE(test.err, err) {
   219  				t.Errorf("Unexpected error: %s", err)
   220  			}
   221  			if err != nil {
   222  				return
   223  			}
   224  			if d := testy.DiffInterface(test.expected, result); d != nil {
   225  				t.Error(d)
   226  			}
   227  		})
   228  	}
   229  }
   230  

View as plain text