1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.modeshape.graph.query.validate;
25
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.LinkedList;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Set;
36 import net.jcip.annotations.Immutable;
37 import org.modeshape.graph.query.model.SelectorName;
38 import org.modeshape.graph.query.validate.Schemata.Column;
39 import org.modeshape.graph.query.validate.Schemata.Key;
40 import org.modeshape.graph.query.validate.Schemata.Table;
41
42 @Immutable
43 class ImmutableTable implements Table {
44 private final SelectorName name;
45 private final Map<String, Column> columnsByName;
46 private final List<Column> columns;
47 private final Set<Key> keys;
48 private final boolean extraColumns;
49 private final List<Column> selectStarColumns;
50 private final Map<String, Column> selectStarColumnsByName;
51
52 protected ImmutableTable( SelectorName name,
53 Iterable<Column> columns,
54 boolean extraColumns ) {
55 this(name, columns, extraColumns, (Iterable<Column>[])null);
56 }
57
58 protected ImmutableTable( SelectorName name,
59 Iterable<Column> columns,
60 boolean extraColumns,
61 Iterable<Column>... keyColumns ) {
62 this.name = name;
63
64 List<Column> columnList = new ArrayList<Column>();
65 Map<String, Column> columnMap = new HashMap<String, Column>();
66 for (Column column : columns) {
67 Column old = columnMap.put(column.getName(), column);
68 if (old != null) {
69 columnList.set(columnList.indexOf(old), column);
70 } else {
71 columnList.add(column);
72 }
73 }
74 this.columnsByName = Collections.unmodifiableMap(columnMap);
75 this.columns = Collections.unmodifiableList(columnList);
76
77 if (keyColumns != null) {
78 Set<Key> keys = new HashSet<Key>();
79 for (Iterable<Column> keyColumnSet : keyColumns) {
80 if (keyColumnSet != null) {
81 Key key = new ImmutableKey(keyColumnSet);
82 keys.add(key);
83 }
84 }
85 this.keys = Collections.unmodifiableSet(keys);
86 } else {
87 this.keys = Collections.emptySet();
88 }
89 this.extraColumns = extraColumns;
90 this.selectStarColumns = this.columns;
91 this.selectStarColumnsByName = this.columnsByName;
92 }
93
94 protected ImmutableTable( SelectorName name,
95 Map<String, Column> columnsByName,
96 List<Column> columns,
97 Set<Key> keys,
98 boolean extraColumns,
99 Map<String, Column> selectStarColumnsByName,
100 List<Column> selectStarColumns ) {
101 this.name = name;
102 this.columns = columns;
103 this.columnsByName = columnsByName;
104 this.keys = keys;
105 this.extraColumns = extraColumns;
106 assert selectStarColumns != null;
107 assert selectStarColumnsByName != null;
108 assert selectStarColumns.size() == selectStarColumnsByName.size();
109 this.selectStarColumns = selectStarColumns;
110 this.selectStarColumnsByName = selectStarColumnsByName;
111 }
112
113
114
115
116
117
118 public SelectorName getName() {
119 return name;
120 }
121
122
123
124
125
126
127 public Column getColumn( String name ) {
128 return columnsByName.get(name);
129 }
130
131
132
133
134
135
136 public List<Column> getColumns() {
137 return columns;
138 }
139
140
141
142
143
144
145 public List<Column> getSelectAllColumns() {
146 return selectStarColumns;
147 }
148
149
150
151
152
153
154 public Map<String, Column> getSelectAllColumnsByName() {
155 return selectStarColumnsByName;
156 }
157
158
159
160
161
162
163 public Map<String, Column> getColumnsByName() {
164 return columnsByName;
165 }
166
167
168
169
170
171
172 public Collection<Key> getKeys() {
173 return keys;
174 }
175
176 protected Set<Key> getKeySet() {
177 return keys;
178 }
179
180
181
182
183
184
185 public Key getKey( Column... columns ) {
186 for (Key key : keys) {
187 if (key.hasColumns(columns)) return key;
188 }
189 return null;
190 }
191
192
193
194
195
196
197 public Key getKey( Iterable<Column> columns ) {
198 for (Key key : keys) {
199 if (key.hasColumns(columns)) return key;
200 }
201 return null;
202 }
203
204
205
206
207
208
209 public boolean hasKey( Column... columns ) {
210 return getKey(columns) != null;
211 }
212
213
214
215
216
217
218 public boolean hasKey( Iterable<Column> columns ) {
219 return getKey(columns) != null;
220 }
221
222
223
224
225
226
227 public boolean hasExtraColumns() {
228 return extraColumns;
229 }
230
231 public ImmutableTable withColumn( String name,
232 String type ) {
233 return withColumn(name, type, ImmutableColumn.DEFAULT_FULL_TEXT_SEARCHABLE);
234 }
235
236 public ImmutableTable withColumn( String name,
237 String type,
238 boolean fullTextSearchable ) {
239
240 Column newColumn = new ImmutableColumn(name, type, fullTextSearchable);
241
242 List<Column> newColumns = new LinkedList<Column>(columns);
243 newColumns.add(newColumn);
244 List<Column> selectStarColumns = new LinkedList<Column>(this.selectStarColumns);
245 Map<String, Column> selectStarColumnMap = new HashMap<String, Column>(this.selectStarColumnsByName);
246 Map<String, Column> columnMap = new HashMap<String, Column>(columnsByName);
247 Column existing = columnMap.put(newColumn.getName(), newColumn);
248 if (existing != null) {
249 newColumns.remove(existing);
250 if (selectStarColumnMap.containsKey(existing.getName())) {
251
252 selectStarColumnMap.put(newColumn.getName(), newColumn);
253 selectStarColumns.add(newColumn);
254 }
255 }
256 return new ImmutableTable(getName(), columnMap, newColumns, keys, extraColumns, selectStarColumnMap, selectStarColumns);
257 }
258
259 public ImmutableTable withColumns( Iterable<Column> columns ) {
260
261 List<Column> newColumns = new LinkedList<Column>(this.getColumns());
262 List<Column> selectStarColumns = new LinkedList<Column>(this.selectStarColumns);
263 Map<String, Column> selectStarColumnMap = new HashMap<String, Column>(this.selectStarColumnsByName);
264 Map<String, Column> columnMap = new HashMap<String, Column>(columnsByName);
265 for (Column column : columns) {
266 Column newColumn = new ImmutableColumn(column.getName(), column.getPropertyType(), column.isFullTextSearchable());
267 newColumns.add(newColumn);
268 Column existing = columnMap.put(newColumn.getName(), newColumn);
269 if (existing != null) {
270 newColumns.remove(existing);
271 if (selectStarColumnMap.containsKey(existing.getName())) {
272
273 selectStarColumnMap.put(newColumn.getName(), newColumn);
274 selectStarColumns.add(newColumn);
275 }
276 }
277 }
278 return new ImmutableTable(getName(), columnMap, newColumns, keys, extraColumns, selectStarColumnMap, selectStarColumns);
279 }
280
281 public ImmutableTable with( SelectorName name ) {
282 return new ImmutableTable(name, columnsByName, columns, keys, extraColumns, selectStarColumnsByName, selectStarColumns);
283 }
284
285 public ImmutableTable withKey( Iterable<Column> keyColumns ) {
286 Set<Key> keys = new HashSet<Key>(this.keys);
287 for (Column keyColumn : keyColumns) {
288 assert columns.contains(keyColumn);
289 }
290 if (!keys.add(new ImmutableKey(keyColumns))) return this;
291 return new ImmutableTable(name, columnsByName, columns, keys, extraColumns, selectStarColumnsByName, selectStarColumns);
292 }
293
294 public ImmutableTable withKey( Column... keyColumns ) {
295 return withKey(Arrays.asList(keyColumns));
296 }
297
298 public ImmutableTable withExtraColumns() {
299 return extraColumns ? this : new ImmutableTable(name, columnsByName, columns, keys, true, selectStarColumnsByName,
300 selectStarColumns);
301 }
302
303 public ImmutableTable withoutExtraColumns() {
304 return !extraColumns ? this : new ImmutableTable(name, columnsByName, columns, keys, false, selectStarColumnsByName,
305 selectStarColumns);
306 }
307
308 public ImmutableTable withColumnNotInSelectStar( String name ) {
309 Column column = columnsByName.get(name);
310 if (column == null) return this;
311 if (!getSelectAllColumnsByName().containsKey(name)) {
312 return this;
313 }
314 List<Column> selectStarColumns = new LinkedList<Column>(this.selectStarColumns);
315 Map<String, Column> selectStarColumnsByName = new HashMap<String, Column>(this.selectStarColumnsByName);
316 selectStarColumns.remove(column);
317 selectStarColumnsByName.remove(name);
318 return new ImmutableTable(this.name, columnsByName, columns, keys, extraColumns, selectStarColumnsByName,
319 selectStarColumns);
320 }
321
322
323
324
325
326
327 @Override
328 public String toString() {
329 StringBuilder sb = new StringBuilder(name.name());
330 sb.append('(');
331 boolean first = true;
332 for (Column column : columns) {
333 if (first) first = false;
334 else sb.append(", ");
335 sb.append(column);
336 }
337 sb.append(')');
338 if (!keys.isEmpty()) {
339 sb.append(" with keys ");
340 first = true;
341 for (Key key : keys) {
342 if (first) first = false;
343 else sb.append(", ");
344 sb.append(key);
345 }
346 }
347 return sb.toString();
348 }
349 }