Skip to content

Commit a503b28

Browse files
committed
Implement new syntax for INSERT and UPSERT.
1 parent 80cfe15 commit a503b28

19 files changed

+33973
-20706
lines changed

algebra/insert.go

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,27 +17,29 @@ import (
1717
type Insert struct {
1818
keyspace *KeyspaceRef `json:"keyspace"`
1919
key expression.Expression `json:"key"`
20-
values expression.Expression `json:"values"`
20+
value expression.Expression `json:"value"`
21+
values Pairs `json:"values"`
2122
query *Select `json:"select"`
2223
returning *Projection `json:"returning"`
2324
}
2425

25-
func NewInsertValues(keyspace *KeyspaceRef, key expression.Expression,
26-
values expression.Expression, returning *Projection) *Insert {
26+
func NewInsertValues(keyspace *KeyspaceRef, values Pairs, returning *Projection) *Insert {
2727
return &Insert{
2828
keyspace: keyspace,
29-
key: key,
29+
key: nil,
30+
value: nil,
3031
values: values,
3132
query: nil,
3233
returning: returning,
3334
}
3435
}
3536

36-
func NewInsertSelect(keyspace *KeyspaceRef, key expression.Expression,
37+
func NewInsertSelect(keyspace *KeyspaceRef, key, value expression.Expression,
3738
query *Select, returning *Projection) *Insert {
3839
return &Insert{
3940
keyspace: keyspace,
4041
key: key,
42+
value: value,
4143
values: nil,
4244
query: query,
4345
returning: returning,
@@ -64,8 +66,15 @@ func (this *Insert) MapExpressions(mapper expression.Mapper) (err error) {
6466
}
6567
}
6668

69+
if this.value != nil {
70+
this.value, err = mapper.Map(this.value)
71+
if err != nil {
72+
return
73+
}
74+
}
75+
6776
if this.values != nil {
68-
this.values, err = mapper.Map(this.values)
77+
err = this.values.MapExpressions(mapper)
6978
if err != nil {
7079
return
7180
}
@@ -87,7 +96,8 @@ func (this *Insert) MapExpressions(mapper expression.Mapper) (err error) {
8796

8897
func (this *Insert) Formalize() (err error) {
8998
if this.values != nil {
90-
this.values, err = expression.NewFormalizer().Map(this.values)
99+
f := expression.NewFormalizer()
100+
err = this.values.MapExpressions(f)
91101
if err != nil {
92102
return
93103
}
@@ -120,7 +130,11 @@ func (this *Insert) Key() expression.Expression {
120130
return this.key
121131
}
122132

123-
func (this *Insert) Values() expression.Expression {
133+
func (this *Insert) Value() expression.Expression {
134+
return this.value
135+
}
136+
137+
func (this *Insert) Values() Pairs {
124138
return this.values
125139
}
126140

algebra/pair.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright (c) 2014 Couchbase, Inc.
2+
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
3+
// except in compliance with the License. You may obtain a copy of the License at
4+
// http://www.apache.org/licenses/LICENSE-2.0
5+
// Unless required by applicable law or agreed to in writing, software distributed under the
6+
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
7+
// either express or implied. See the License for the specific language governing permissions
8+
// and limitations under the License.
9+
10+
package algebra
11+
12+
import (
13+
"fmt"
14+
15+
"github.com/couchbaselabs/query/expression"
16+
)
17+
18+
type Pairs []*Pair
19+
20+
type Pair struct {
21+
Key expression.Expression
22+
Value expression.Expression
23+
}
24+
25+
func (this *Pair) MapExpressions(mapper expression.Mapper) (err error) {
26+
this.Key, err = mapper.Map(this.Key)
27+
if err != nil {
28+
return
29+
}
30+
31+
this.Value, err = mapper.Map(this.Value)
32+
return
33+
}
34+
35+
func (this *Pair) Expression() expression.Expression {
36+
return expression.NewArrayConstruct(this.Key, this.Value)
37+
}
38+
39+
func (this *Pair) MarshalJSON() ([]byte, error) {
40+
return this.Expression().MarshalJSON()
41+
}
42+
43+
func (this Pairs) MapExpressions(mapper expression.Mapper) (err error) {
44+
for _, pair := range this {
45+
err = pair.MapExpressions(mapper)
46+
if err != nil {
47+
return
48+
}
49+
}
50+
51+
return
52+
}
53+
54+
func (this Pairs) Expression() expression.Expression {
55+
exprs := make(expression.Expressions, len(this))
56+
57+
for i, pair := range this {
58+
exprs[i] = pair.Expression()
59+
}
60+
61+
return expression.NewArrayConstruct(exprs...)
62+
}
63+
64+
func (this Pairs) MarshalJSON() ([]byte, error) {
65+
return this.Expression().MarshalJSON()
66+
}
67+
68+
func NewPairs(array *expression.ArrayConstruct) (pairs Pairs, err error) {
69+
operands := array.Operands()
70+
pairs = make(Pairs, len(operands))
71+
for i, op := range operands {
72+
pairs[i], err = NewPair(op)
73+
if err != nil {
74+
return nil, err
75+
}
76+
}
77+
78+
return
79+
}
80+
81+
func NewPair(expr expression.Expression) (*Pair, error) {
82+
array, ok := expr.(*expression.ArrayConstruct)
83+
if !ok {
84+
return nil, fmt.Errorf("Invalid VALUES expression %s", expr.String())
85+
}
86+
87+
operands := array.Operands()
88+
if len(operands) != 2 {
89+
return nil, fmt.Errorf("Invalid VALUES expression %s", expr.String())
90+
}
91+
92+
pair := &Pair{
93+
Key: operands[0],
94+
Value: operands[1],
95+
}
96+
97+
return pair, nil
98+
}

algebra/upsert.go

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,27 +17,29 @@ import (
1717
type Upsert struct {
1818
keyspace *KeyspaceRef `json:"keyspace"`
1919
key expression.Expression `json:"key"`
20-
values expression.Expression `json:"values"`
20+
value expression.Expression `json:"value"`
21+
values Pairs `json:"values"`
2122
query *Select `json:"select"`
2223
returning *Projection `json:"returning"`
2324
}
2425

25-
func NewUpsertValues(keyspace *KeyspaceRef, key expression.Expression,
26-
values expression.Expression, returning *Projection) *Upsert {
26+
func NewUpsertValues(keyspace *KeyspaceRef, values Pairs, returning *Projection) *Upsert {
2727
return &Upsert{
2828
keyspace: keyspace,
29-
key: key,
29+
key: nil,
30+
value: nil,
3031
values: values,
3132
query: nil,
3233
returning: returning,
3334
}
3435
}
3536

36-
func NewUpsertSelect(keyspace *KeyspaceRef, key expression.Expression,
37+
func NewUpsertSelect(keyspace *KeyspaceRef, key, value expression.Expression,
3738
query *Select, returning *Projection) *Upsert {
3839
return &Upsert{
3940
keyspace: keyspace,
4041
key: key,
42+
value: value,
4143
values: nil,
4244
query: query,
4345
returning: returning,
@@ -64,8 +66,15 @@ func (this *Upsert) MapExpressions(mapper expression.Mapper) (err error) {
6466
}
6567
}
6668

69+
if this.value != nil {
70+
this.value, err = mapper.Map(this.value)
71+
if err != nil {
72+
return
73+
}
74+
}
75+
6776
if this.values != nil {
68-
this.values, err = mapper.Map(this.values)
77+
err = this.values.MapExpressions(mapper)
6978
if err != nil {
7079
return
7180
}
@@ -87,7 +96,8 @@ func (this *Upsert) MapExpressions(mapper expression.Mapper) (err error) {
8796

8897
func (this *Upsert) Formalize() (err error) {
8998
if this.values != nil {
90-
this.values, err = expression.NewFormalizer().Map(this.values)
99+
f := expression.NewFormalizer()
100+
err = this.values.MapExpressions(f)
91101
if err != nil {
92102
return
93103
}
@@ -120,7 +130,11 @@ func (this *Upsert) Key() expression.Expression {
120130
return this.key
121131
}
122132

123-
func (this *Upsert) Values() expression.Expression {
133+
func (this *Upsert) Value() expression.Expression {
134+
return this.value
135+
}
136+
137+
func (this *Upsert) Values() Pairs {
124138
return this.values
125139
}
126140

docs/n1ql-dml.ebnf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ merge ::= 'MERGE' 'INTO' keyspace-ref 'USING' merge-source 'ON' key-clause merge
5252

5353
merge-source ::= from-path ('AS'? alias)? | '(' select ')' 'AS'? alias
5454

55+
key-clause ::= PRIMARY? KEY expr
56+
5557
merge-actions ::= merge-update? merge-delete? merge-insert?
5658

5759
merge-update ::= 'WHEN' 'MATCHED' 'THEN' 'UPDATE' set-clause? unset-clause? where-clause?

docs/n1ql-dml.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
+ Status: DRAFT/PROPOSAL
44
+ Latest: [n1ql-dml](https://github.com/couchbaselabs/query/blob/master/docs/n1ql-dml.md)
5-
+ Modified: 2014-12-15
5+
+ Modified: 2014-12-21
66

77
## Introduction
88

@@ -118,6 +118,10 @@ _merge-source:_
118118

119119
![](diagram/merge-source.png)
120120

121+
_key-clause:_
122+
123+
![](diagram/key-clause.png)
124+
121125
_merge-actions:_
122126

123127
![](diagram/merge-actions.png)
@@ -285,6 +289,8 @@ Generator](http://railroad.my28msec.com/) ![](diagram/.png)
285289
* Allow keys to exist outside of values
286290
* 2014-12-15 - INSERT / UPSERT syntax
287291
* Refine INSERT / UPSERT syntax
292+
* 2014-12-21 - MERGE syntax
293+
* Include key-clause in MERGE syntax diagrams
288294

289295
### Open Issues
290296

execution/delete_send.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,13 @@ func (this *SendDelete) flushBatch(context *Context) bool {
9898
}
9999

100100
deleted_keys, e := this.plan.Keyspace().Delete(keys)
101+
102+
// Update mutation count with number of deleted docs:
103+
context.AddMutationCount(uint64(len(deleted_keys)))
104+
101105
if e != nil {
102106
context.Error(e)
103-
this.batch = nil
104-
return false
105107
}
106-
// Update mutation count with number of deleted docs:
107-
context.AddMutationCount(uint64(len(deleted_keys)))
108108

109109
for _, av := range this.batch {
110110
if !this.sendItem(av) {

0 commit comments

Comments
 (0)