Skip to content

Commit

Permalink
Merge pull request #1770 from couchbase/feature/issue_1769
Browse files Browse the repository at this point in the history
Allows channels to be a single string channel vale in default sync function
  • Loading branch information
adamcfraser committed May 16, 2016
2 parents a20985c + 02a6acf commit 7461744
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 33 deletions.
20 changes: 20 additions & 0 deletions base/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,3 +396,23 @@ func SyncSourceFromURL(u *url.URL) string {

return buf.String()
}

//Convert string or array into a string array, otherwise return nil
func ValueToStringArray(value interface{}) []string {
switch valueType := value.(type) {
case string:
return []string{valueType}
case []string:
return valueType
case []interface{}:
result := make([]string, 0, len(valueType))
for _, item := range valueType {
if str, ok := item.(string); ok {
result = append(result, str)
}
}
return result
default:
return nil
}
}
11 changes: 11 additions & 0 deletions base/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,15 @@ func TestSyncSourceFromURL(t *testing.T) {
assert.True(t, err == nil)
result = SyncSourceFromURL(u)
assert.Equals(t, result, "")
}

func TestValueToStringArray(t *testing.T) {
result := ValueToStringArray("foobar")
assert.DeepEquals(t, result, []string{"foobar"})

result = ValueToStringArray([]string{"foobar","moocar"})
assert.DeepEquals(t, result, []string{"foobar","moocar"})

result = ValueToStringArray([]interface{}{"foobar",1,true})
assert.DeepEquals(t, result, []string{"foobar"})
}
25 changes: 7 additions & 18 deletions channels/sync_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,23 +207,12 @@ func compileAccessMap(input map[string][]string, prefix string) (AccessMap, erro
// Converts a JS string or array into a Go string array.
func ottoValueToStringArray(value otto.Value) []string {
nativeValue, _ := value.Export()
switch nativeValue := nativeValue.(type) {
case string:
return []string{nativeValue}
case []string:
return nativeValue
case []interface{}:
result := make([]string, 0, len(nativeValue))
for _, item := range nativeValue {
if str, ok := item.(string); ok {
result = append(result, str)
}
}
return result
default:
if !value.IsNull() && !value.IsUndefined() {
base.Warn("SyncRunner: Non-string, non-array passed to JS callback: %s", value)
}
return nil

result := base.ValueToStringArray(nativeValue)

if result == nil && !value.IsNull() && !value.IsUndefined() {
base.Warn("SyncRunner: Non-string, non-array passed to JS callback: %s", value)
}

return result
}
10 changes: 2 additions & 8 deletions db/crud.go
Original file line number Diff line number Diff line change
Expand Up @@ -819,15 +819,9 @@ func (db *Database) getChannelsAndAccess(doc *document, body Body, revID string)

} else {
// No ChannelMapper so by default use the "channels" property:
value, _ := body["channels"].([]interface{})
value := body["channels"]
if value != nil {
array := make([]string, 0, len(value))
for _, channel := range value {
channelStr, ok := channel.(string)
if ok && len(channelStr) > 0 {
array = append(array, channelStr)
}
}
array := base.ValueToStringArray(value)
result, err = channels.SetFromArray(array, channels.KeepStar)
}
}
Expand Down
18 changes: 11 additions & 7 deletions rest/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1180,6 +1180,7 @@ func testAccessControl(t *testing.T, rt indexTester) {
assertStatus(t, rt.sendRequest("PUT", "/db/doc2", `{"channels":["CBS"]}`), 201)
assertStatus(t, rt.sendRequest("PUT", "/db/doc3", `{"channels":["CBS", "Cinemax"]}`), 201)
assertStatus(t, rt.sendRequest("PUT", "/db/doc4", `{"channels":["WB", "Cinemax"]}`), 201)
assertStatus(t, rt.sendRequest("PUT", "/db/doc5", `{"channels":"Cinemax"}`), 201)

guest.SetDisabled(true)
err = a.Save(guest)
Expand Down Expand Up @@ -1210,11 +1211,13 @@ func testAccessControl(t *testing.T, rt indexTester) {
log.Printf("Response = %s", response.Body.Bytes())
err = json.Unmarshal(response.Body.Bytes(), &allDocsResult)
assert.Equals(t, err, nil)
assert.Equals(t, len(allDocsResult.Rows), 2)
assert.Equals(t, len(allDocsResult.Rows), 3)
assert.Equals(t, allDocsResult.Rows[0].ID, "doc3")
assert.DeepEquals(t, allDocsResult.Rows[0].Value.Channels, []string{"Cinemax"})
assert.Equals(t, allDocsResult.Rows[1].ID, "doc4")
assert.DeepEquals(t, allDocsResult.Rows[1].Value.Channels, []string{"Cinemax"})
assert.Equals(t, allDocsResult.Rows[2].ID, "doc5")
assert.DeepEquals(t, allDocsResult.Rows[2].Value.Channels, []string{"Cinemax"})

//Check all docs limit option
request, _ = http.NewRequest("GET", "/db/_all_docs?limit=1&channels=true", nil)
Expand All @@ -1230,7 +1233,7 @@ func testAccessControl(t *testing.T, rt indexTester) {
assert.DeepEquals(t, allDocsResult.Rows[0].Value.Channels, []string{"Cinemax"})

//Check all docs startkey option
request, _ = http.NewRequest("GET", "/db/_all_docs?startkey=doc4&channels=true", nil)
request, _ = http.NewRequest("GET", "/db/_all_docs?startkey=doc5&channels=true", nil)
request.SetBasicAuth("alice", "letmein")
response = rt.send(request)
assertStatus(t, response, 200)
Expand All @@ -1239,11 +1242,11 @@ func testAccessControl(t *testing.T, rt indexTester) {
err = json.Unmarshal(response.Body.Bytes(), &allDocsResult)
assert.Equals(t, err, nil)
assert.Equals(t, len(allDocsResult.Rows), 1)
assert.Equals(t, allDocsResult.Rows[0].ID, "doc4")
assert.Equals(t, allDocsResult.Rows[0].ID, "doc5")
assert.DeepEquals(t, allDocsResult.Rows[0].Value.Channels, []string{"Cinemax"})

//Check all docs startkey option with double quote
request, _ = http.NewRequest("GET", `/db/_all_docs?startkey="doc4"&channels=true`, nil)
request, _ = http.NewRequest("GET", `/db/_all_docs?startkey="doc5"&channels=true`, nil)
request.SetBasicAuth("alice", "letmein")
response = rt.send(request)
assertStatus(t, response, 200)
Expand All @@ -1252,7 +1255,7 @@ func testAccessControl(t *testing.T, rt indexTester) {
err = json.Unmarshal(response.Body.Bytes(), &allDocsResult)
assert.Equals(t, err, nil)
assert.Equals(t, len(allDocsResult.Rows), 1)
assert.Equals(t, allDocsResult.Rows[0].ID, "doc4")
assert.Equals(t, allDocsResult.Rows[0].ID, "doc5")
assert.DeepEquals(t, allDocsResult.Rows[0].Value.Channels, []string{"Cinemax"})

//Check all docs endkey option
Expand Down Expand Up @@ -1290,9 +1293,10 @@ func testAccessControl(t *testing.T, rt indexTester) {
log.Printf("Response = %s", response.Body.Bytes())
err = json.Unmarshal(response.Body.Bytes(), &allDocsResult)
assert.Equals(t, err, nil)
assert.Equals(t, len(allDocsResult.Rows), 2)
assert.Equals(t, len(allDocsResult.Rows), 3)
assert.Equals(t, allDocsResult.Rows[0].ID, "doc3")
assert.Equals(t, allDocsResult.Rows[1].ID, "doc4")
assert.Equals(t, allDocsResult.Rows[2].ID, "doc5")

// Check POST to _all_docs:
body := `{"keys": ["doc4", "doc1", "doc3", "b0gus"]}`
Expand Down Expand Up @@ -1357,7 +1361,7 @@ func testAccessControl(t *testing.T, rt indexTester) {
log.Printf("Admin response = %s", response.Body.Bytes())
err = json.Unmarshal(response.Body.Bytes(), &allDocsResult)
assert.Equals(t, err, nil)
assert.Equals(t, len(allDocsResult.Rows), 4)
assert.Equals(t, len(allDocsResult.Rows), 5)
assert.Equals(t, allDocsResult.Rows[0].ID, "doc1")
assert.Equals(t, allDocsResult.Rows[1].ID, "doc2")

Expand Down

0 comments on commit 7461744

Please sign in to comment.