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
10package plan
11
12import (
13	"encoding/json"
14
15	"github.com/couchbase/query/algebra"
16	"github.com/couchbase/query/datastore"
17	"github.com/couchbase/query/errors"
18	"github.com/couchbase/query/value"
19)
20
21// Alter index
22type AlterIndex struct {
23	readwrite
24	index    datastore.Index
25	indexer  datastore.Indexer
26	node     *algebra.AlterIndex
27	keyspace datastore.Keyspace
28}
29
30func NewAlterIndex(index datastore.Index, indexer datastore.Indexer, node *algebra.AlterIndex,
31	keyspace datastore.Keyspace) *AlterIndex {
32	return &AlterIndex{
33		index:    index,
34		indexer:  indexer,
35		node:     node,
36		keyspace: keyspace,
37	}
38}
39
40func (this *AlterIndex) Accept(visitor Visitor) (interface{}, error) {
41	return visitor.VisitAlterIndex(this)
42}
43
44func (this *AlterIndex) New() Operator {
45	return &AlterIndex{}
46}
47
48func (this *AlterIndex) Index() datastore.Index {
49	return this.index
50}
51
52func (this *AlterIndex) Node() *algebra.AlterIndex {
53	return this.node
54}
55
56func (this *AlterIndex) Keyspace() datastore.Keyspace {
57	return this.keyspace
58}
59
60func (this *AlterIndex) MarshalJSON() ([]byte, error) {
61	return json.Marshal(this.MarshalBase(nil))
62}
63
64func (this *AlterIndex) MarshalBase(f func(map[string]interface{})) map[string]interface{} {
65	r := map[string]interface{}{"#operator": "AlterIndex"}
66	r["index"] = this.index.Name()
67	r["index_id"] = this.index.Id()
68	r["keyspace"] = this.keyspace.Name()
69	r["namespace"] = this.keyspace.NamespaceId()
70	r["using"] = this.node.Using()
71
72	if this.node.With() != nil {
73		r["with"] = this.node.With()
74	}
75
76	if f != nil {
77		f(r)
78	}
79	return r
80}
81
82func (this *AlterIndex) UnmarshalJSON(body []byte) error {
83	var _unmarshalled struct {
84		_       string              `json:"#operator"`
85		Index   string              `json:"index"`
86		IndexId string              `json:"index_id"`
87		Keys    string              `json:"keyspace"`
88		Names   string              `json:"namespace"`
89		Using   datastore.IndexType `json:"using"`
90		With    json.RawMessage     `json:"with"`
91	}
92
93	err := json.Unmarshal(body, &_unmarshalled)
94	if err != nil {
95		return err
96	}
97
98	// Build the node
99	// Get the keyspace ref (namespace:keyspace)
100	ksref := algebra.NewKeyspaceRef(_unmarshalled.Names, _unmarshalled.Keys, "")
101
102	// Get the with clause
103	var with value.Value
104	if len(_unmarshalled.With) > 0 {
105		with = value.NewValue([]byte(_unmarshalled.With))
106	}
107
108	this.node = algebra.NewAlterIndex(ksref, _unmarshalled.Index, _unmarshalled.Using, with)
109
110	// Build the index
111	this.keyspace, err = datastore.GetKeyspace(_unmarshalled.Names, _unmarshalled.Keys)
112	if err != nil {
113		return err
114	}
115
116	// Alter Index is only supported by GSI and doesnt support a USING clause
117	indexer, err := this.keyspace.Indexer(_unmarshalled.Using)
118	if err != nil {
119		return err
120	}
121
122	index, err := indexer.IndexById(_unmarshalled.IndexId)
123	if err != nil {
124		return err
125	}
126
127	if _, ok := index.(datastore.Index3); !ok {
128		return errors.NewAlterIndexError()
129	}
130
131	this.index = index
132	this.indexer = indexer
133
134	return nil
135}
136
137func (this *AlterIndex) verify(prepared *Prepared) bool {
138	return verifyIndex(this.index, this.indexer, prepared)
139}
140