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 expression
11
12import (
13	"github.com/couchbase/query/value"
14)
15
16/*
17Identifier flags
18*/
19const (
20	IDENT_IS_UNKNOWN      = 1 << iota // unknown
21	IDENT_IS_KEYSPACE                 // keyspace or its alias or equivalent (e.g. subquery term)
22	IDENT_IS_VARIABLE                 // binding variable
23	IDENT_IS_PROJ_ALIAS               // alias used in projection
24	IDENT_IS_UNNEST_ALIAS             // UNNEST alias
25)
26
27/*
28An identifier is a symbolic reference to a particular value
29in the current context.
30*/
31type Identifier struct {
32	ExpressionBase
33	identifier      string
34	caseInsensitive bool
35	parenthesis     bool
36	identFlags      uint32
37}
38
39func NewIdentifier(identifier string) *Identifier {
40	rv := &Identifier{
41		identifier: identifier,
42	}
43
44	rv.expr = rv
45	return rv
46}
47
48/*
49Visitor pattern.
50*/
51func (this *Identifier) Accept(visitor Visitor) (interface{}, error) {
52	return visitor.VisitIdentifier(this)
53}
54
55func (this *Identifier) Type() value.Type { return value.JSON }
56
57/*
58Evaluate this as a top-level identifier.
59*/
60func (this *Identifier) Evaluate(item value.Value, context Context) (value.Value, error) {
61	rv, _ := item.Field(this.identifier)
62	return rv, nil
63}
64
65/*
66Value() returns the static / constant value of this Expression, or
67nil. Expressions that depend on data, clocks, or random numbers must
68return nil.
69*/
70func (this *Identifier) Value() value.Value {
71	return nil
72}
73
74func (this *Identifier) Static() Expression {
75	return nil
76}
77
78func (this *Identifier) Alias() string {
79	return this.identifier
80}
81
82/*
83An identifier can be used as an index. Hence return true.
84*/
85func (this *Identifier) Indexable() bool {
86	return true
87}
88
89func (this *Identifier) EquivalentTo(other Expression) bool {
90	switch other := other.(type) {
91	case *Identifier:
92		return (this.identifier == other.identifier) &&
93			(this.caseInsensitive == other.caseInsensitive)
94	default:
95		return false
96	}
97}
98
99func (this *Identifier) CoveredBy(keyspace string, exprs Expressions, options coveredOptions) Covered {
100	// MB-25317, if this is not the right keyspace, ignore the expression altogether
101	// MB-25370 this only applies for keyspace terms, not variables!
102	if (this.IsKeyspaceAlias() && this.identifier != keyspace) ||
103		this.IsProjectionAlias() || (!options.hasCoverBindVar() && this.IsBindingVariable()) {
104		return CoveredSkip
105	}
106
107	for _, expr := range exprs {
108		if this.EquivalentTo(expr) {
109			switch eType := expr.(type) {
110			case *Identifier:
111				if options.hasCoverBindVar() && this.IsBindingVariable() {
112					if eType.identifier == keyspace {
113						return CoveredTrue
114					} else {
115						return CoveredSkip
116					}
117				} else {
118					if !this.IsKeyspaceAlias() {
119						return CoveredTrue
120					} else if eType.identifier != keyspace {
121						return CoveredSkip
122					}
123				}
124			default:
125				return CoveredTrue
126			}
127		}
128	}
129
130	return CoveredFalse
131}
132
133func (this *Identifier) Children() Expressions {
134	return nil
135}
136
137func (this *Identifier) MapChildren(mapper Mapper) error {
138	return nil
139}
140
141func (this *Identifier) Copy() Expression {
142	return this
143}
144
145func (this *Identifier) SurvivesGrouping(groupKeys Expressions, allowed *value.ScopeValue) (
146	bool, Expression) {
147	for _, key := range groupKeys {
148		if this.EquivalentTo(key) {
149			return true, nil
150		}
151	}
152
153	flags, found := allowed.Field(this.identifier)
154	if found {
155		allow_flags := uint32(flags.ActualForIndex().(int64))
156		if (allow_flags & IDENT_IS_PROJ_ALIAS) != 0 {
157			this.SetProjectionAlias(true)
158		} else if (allow_flags & IDENT_IS_VARIABLE) != 0 {
159			this.SetBindingVariable(true)
160		}
161		return true, nil
162	}
163
164	return false, this
165}
166
167func (this *Identifier) Set(item, val value.Value, context Context) bool {
168	er := item.SetField(this.identifier, val)
169	return er == nil
170}
171
172func (this *Identifier) Unset(item value.Value, context Context) bool {
173	er := item.UnsetField(this.identifier)
174	return er == nil
175}
176
177func (this *Identifier) Identifier() string {
178	return this.identifier
179}
180
181func (this *Identifier) CaseInsensitive() bool {
182	return this.caseInsensitive
183}
184
185func (this *Identifier) SetCaseInsensitive(insensitive bool) {
186	this.caseInsensitive = insensitive
187}
188
189func (this *Identifier) Parenthesis() bool {
190	return this.parenthesis
191}
192
193func (this *Identifier) SetParenthesis(parenthesis bool) {
194	this.parenthesis = parenthesis
195}
196
197func (this *Identifier) IsKeyspaceAlias() bool {
198	return (this.identFlags & IDENT_IS_KEYSPACE) != 0
199}
200
201func (this *Identifier) SetKeyspaceAlias(keyspaceAlias bool) {
202	if keyspaceAlias {
203		this.identFlags |= IDENT_IS_KEYSPACE
204	} else {
205		this.identFlags &^= IDENT_IS_KEYSPACE
206	}
207}
208
209func (this *Identifier) IsBindingVariable() bool {
210	return (this.identFlags & IDENT_IS_VARIABLE) != 0
211}
212
213func (this *Identifier) SetBindingVariable(bindingVariable bool) {
214	if bindingVariable {
215		this.identFlags |= IDENT_IS_VARIABLE
216	} else {
217		this.identFlags &^= IDENT_IS_VARIABLE
218	}
219}
220
221func (this *Identifier) IsProjectionAlias() bool {
222	return (this.identFlags & IDENT_IS_PROJ_ALIAS) != 0
223}
224
225func (this *Identifier) SetProjectionAlias(projectionAlias bool) {
226	if projectionAlias {
227		this.identFlags |= IDENT_IS_PROJ_ALIAS
228	} else {
229		this.identFlags &^= IDENT_IS_PROJ_ALIAS
230	}
231}
232
233func (this *Identifier) IsUnnestAlias() bool {
234	return (this.identFlags & IDENT_IS_UNNEST_ALIAS) != 0
235}
236
237func (this *Identifier) SetUnnestAlias(unnestAlias bool) {
238	if unnestAlias {
239		this.identFlags |= IDENT_IS_UNNEST_ALIAS
240	} else {
241		this.identFlags &^= IDENT_IS_UNNEST_ALIAS
242	}
243}
244
245func (this *Identifier) SetIdentFlags(aliases map[string]bool, flags uint32) {
246	if aliases != nil {
247		if _, ok := aliases[this.identifier]; ok {
248			this.identFlags |= flags
249		}
250	}
251}
252