]>
Commit | Line | Data |
---|---|---|
1d09f67e TL |
1 | // Licensed to the Apache Software Foundation (ASF) under one |
2 | // or more contributor license agreements. See the NOTICE file | |
3 | // distributed with this work for additional information | |
4 | // regarding copyright ownership. The ASF licenses this file | |
5 | // to you under the Apache License, Version 2.0 (the | |
6 | // "License"); you may not use this file except in compliance | |
7 | // with the License. You may obtain a copy of the License at | |
8 | // | |
9 | // http://www.apache.org/licenses/LICENSE-2.0 | |
10 | // | |
11 | // Unless required by applicable law or agreed to in writing, software | |
12 | // distributed under the License is distributed on an "AS IS" BASIS, | |
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | // See the License for the specific language governing permissions and | |
15 | // limitations under the License. | |
16 | ||
17 | package arrow | |
18 | ||
19 | import ( | |
20 | "fmt" | |
21 | "strings" | |
22 | ) | |
23 | ||
24 | // ListType describes a nested type in which each array slot contains | |
25 | // a variable-size sequence of values, all having the same relative type. | |
26 | type ListType struct { | |
27 | elem Field | |
28 | } | |
29 | ||
30 | func ListOfField(f Field) *ListType { | |
31 | if f.Type == nil { | |
32 | panic("arrow: nil type for list field") | |
33 | } | |
34 | return &ListType{elem: f} | |
35 | } | |
36 | ||
37 | // ListOf returns the list type with element type t. | |
38 | // For example, if t represents int32, ListOf(t) represents []int32. | |
39 | // | |
40 | // ListOf panics if t is nil or invalid. NullableElem defaults to true | |
41 | func ListOf(t DataType) *ListType { | |
42 | if t == nil { | |
43 | panic("arrow: nil DataType") | |
44 | } | |
45 | return &ListType{elem: Field{Name: "item", Type: t, Nullable: true}} | |
46 | } | |
47 | ||
48 | // ListOfNonNullable is like ListOf but NullableElem defaults to false, indicating | |
49 | // that the child type should be marked as non-nullable. | |
50 | func ListOfNonNullable(t DataType) *ListType { | |
51 | if t == nil { | |
52 | panic("arrow: nil DataType") | |
53 | } | |
54 | return &ListType{elem: Field{Name: "item", Type: t, Nullable: false}} | |
55 | } | |
56 | ||
57 | func (*ListType) ID() Type { return LIST } | |
58 | func (*ListType) Name() string { return "list" } | |
59 | ||
60 | func (t *ListType) String() string { | |
61 | if t.elem.Nullable { | |
62 | return fmt.Sprintf("list<%s: %s, nullable>", t.elem.Name, t.elem.Type) | |
63 | } | |
64 | return fmt.Sprintf("list<%s: %s>", t.elem.Name, t.elem.Type) | |
65 | } | |
66 | ||
67 | func (t *ListType) Fingerprint() string { | |
68 | child := t.elem.Type.Fingerprint() | |
69 | if len(child) > 0 { | |
70 | return typeFingerprint(t) + "{" + child + "}" | |
71 | } | |
72 | return "" | |
73 | } | |
74 | ||
75 | func (t *ListType) SetElemMetadata(md Metadata) { t.elem.Metadata = md } | |
76 | ||
77 | func (t *ListType) SetElemNullable(n bool) { t.elem.Nullable = n } | |
78 | ||
79 | // Elem returns the ListType's element type. | |
80 | func (t *ListType) Elem() DataType { return t.elem.Type } | |
81 | ||
82 | func (t *ListType) ElemField() Field { | |
83 | return t.elem | |
84 | } | |
85 | ||
86 | // FixedSizeListType describes a nested type in which each array slot contains | |
87 | // a fixed-size sequence of values, all having the same relative type. | |
88 | type FixedSizeListType struct { | |
89 | n int32 // number of elements in the list | |
90 | elem Field | |
91 | } | |
92 | ||
93 | func FixedSizeListOfField(n int32, f Field) *FixedSizeListType { | |
94 | if f.Type == nil { | |
95 | panic("arrow: nil DataType") | |
96 | } | |
97 | if n <= 0 { | |
98 | panic("arrow: invalid size") | |
99 | } | |
100 | return &FixedSizeListType{n: n, elem: f} | |
101 | } | |
102 | ||
103 | // FixedSizeListOf returns the list type with element type t. | |
104 | // For example, if t represents int32, FixedSizeListOf(10, t) represents [10]int32. | |
105 | // | |
106 | // FixedSizeListOf panics if t is nil or invalid. | |
107 | // FixedSizeListOf panics if n is <= 0. | |
108 | // NullableElem defaults to true | |
109 | func FixedSizeListOf(n int32, t DataType) *FixedSizeListType { | |
110 | if t == nil { | |
111 | panic("arrow: nil DataType") | |
112 | } | |
113 | if n <= 0 { | |
114 | panic("arrow: invalid size") | |
115 | } | |
116 | return &FixedSizeListType{n: n, elem: Field{Name: "item", Type: t, Nullable: true}} | |
117 | } | |
118 | ||
119 | // FixedSizeListOfNonNullable is like FixedSizeListOf but NullableElem defaults to false | |
120 | // indicating that the child type should be marked as non-nullable. | |
121 | func FixedSizeListOfNonNullable(n int32, t DataType) *FixedSizeListType { | |
122 | if t == nil { | |
123 | panic("arrow: nil DataType") | |
124 | } | |
125 | if n <= 0 { | |
126 | panic("arrow: invalid size") | |
127 | } | |
128 | return &FixedSizeListType{n: n, elem: Field{Name: "item", Type: t, Nullable: false}} | |
129 | } | |
130 | ||
131 | func (*FixedSizeListType) ID() Type { return FIXED_SIZE_LIST } | |
132 | func (*FixedSizeListType) Name() string { return "fixed_size_list" } | |
133 | func (t *FixedSizeListType) String() string { | |
134 | if t.elem.Nullable { | |
135 | return fmt.Sprintf("fixed_size_list<%s: %s, nullable>[%d]", t.elem.Name, t.elem.Type, t.n) | |
136 | } | |
137 | return fmt.Sprintf("fixed_size_list<%s: %s>[%d]", t.elem.Name, t.elem.Type, t.n) | |
138 | } | |
139 | ||
140 | // Elem returns the FixedSizeListType's element type. | |
141 | func (t *FixedSizeListType) Elem() DataType { return t.elem.Type } | |
142 | ||
143 | // Len returns the FixedSizeListType's size. | |
144 | func (t *FixedSizeListType) Len() int32 { return t.n } | |
145 | ||
146 | func (t *FixedSizeListType) ElemField() Field { | |
147 | return t.elem | |
148 | } | |
149 | ||
150 | func (t *FixedSizeListType) Fingerprint() string { | |
151 | child := t.elem.Type.Fingerprint() | |
152 | if len(child) > 0 { | |
153 | return fmt.Sprintf("%s[%d]{%s}", typeFingerprint(t), t.n, child) | |
154 | } | |
155 | return "" | |
156 | } | |
157 | ||
158 | // StructType describes a nested type parameterized by an ordered sequence | |
159 | // of relative types, called its fields. | |
160 | type StructType struct { | |
161 | fields []Field | |
162 | index map[string]int | |
163 | meta Metadata | |
164 | } | |
165 | ||
166 | // StructOf returns the struct type with fields fs. | |
167 | // | |
168 | // StructOf panics if there are duplicated fields. | |
169 | // StructOf panics if there is a field with an invalid DataType. | |
170 | func StructOf(fs ...Field) *StructType { | |
171 | n := len(fs) | |
172 | if n == 0 { | |
173 | return &StructType{} | |
174 | } | |
175 | ||
176 | t := &StructType{ | |
177 | fields: make([]Field, n), | |
178 | index: make(map[string]int, n), | |
179 | } | |
180 | for i, f := range fs { | |
181 | if f.Type == nil { | |
182 | panic("arrow: field with nil DataType") | |
183 | } | |
184 | t.fields[i] = Field{ | |
185 | Name: f.Name, | |
186 | Type: f.Type, | |
187 | Nullable: f.Nullable, | |
188 | Metadata: f.Metadata.clone(), | |
189 | } | |
190 | if _, dup := t.index[f.Name]; dup { | |
191 | panic(fmt.Errorf("arrow: duplicate field with name %q", f.Name)) | |
192 | } | |
193 | t.index[f.Name] = i | |
194 | } | |
195 | ||
196 | return t | |
197 | } | |
198 | ||
199 | func (*StructType) ID() Type { return STRUCT } | |
200 | func (*StructType) Name() string { return "struct" } | |
201 | ||
202 | func (t *StructType) String() string { | |
203 | o := new(strings.Builder) | |
204 | o.WriteString("struct<") | |
205 | for i, f := range t.fields { | |
206 | if i > 0 { | |
207 | o.WriteString(", ") | |
208 | } | |
209 | o.WriteString(fmt.Sprintf("%s: %v", f.Name, f.Type)) | |
210 | } | |
211 | o.WriteString(">") | |
212 | return o.String() | |
213 | } | |
214 | ||
215 | func (t *StructType) Fields() []Field { return t.fields } | |
216 | func (t *StructType) Field(i int) Field { return t.fields[i] } | |
217 | ||
218 | func (t *StructType) FieldByName(name string) (Field, bool) { | |
219 | i, ok := t.index[name] | |
220 | if !ok { | |
221 | return Field{}, false | |
222 | } | |
223 | return t.fields[i], true | |
224 | } | |
225 | ||
226 | func (t *StructType) FieldIdx(name string) (int, bool) { | |
227 | i, ok := t.index[name] | |
228 | return i, ok | |
229 | } | |
230 | ||
231 | func (t *StructType) Fingerprint() string { | |
232 | var b strings.Builder | |
233 | b.WriteString(typeFingerprint(t)) | |
234 | b.WriteByte('{') | |
235 | for _, c := range t.fields { | |
236 | child := c.Fingerprint() | |
237 | if len(child) == 0 { | |
238 | return "" | |
239 | } | |
240 | b.WriteString(child) | |
241 | b.WriteByte(';') | |
242 | } | |
243 | b.WriteByte('}') | |
244 | return b.String() | |
245 | } | |
246 | ||
247 | type MapType struct { | |
248 | value *ListType | |
249 | KeysSorted bool | |
250 | } | |
251 | ||
252 | func MapOf(key, item DataType) *MapType { | |
253 | if key == nil || item == nil { | |
254 | panic("arrow: nil key or item type for MapType") | |
255 | } | |
256 | ||
257 | return &MapType{value: ListOf(StructOf(Field{Name: "key", Type: key}, Field{Name: "value", Type: item, Nullable: true}))} | |
258 | } | |
259 | ||
260 | func (*MapType) ID() Type { return MAP } | |
261 | func (*MapType) Name() string { return "map" } | |
262 | ||
263 | func (t *MapType) String() string { | |
264 | var o strings.Builder | |
265 | o.WriteString(fmt.Sprintf("map<%s, %s", | |
266 | t.value.Elem().(*StructType).Field(0).Type, | |
267 | t.value.Elem().(*StructType).Field(1).Type)) | |
268 | if t.KeysSorted { | |
269 | o.WriteString(", keys_sorted") | |
270 | } | |
271 | o.WriteString(">") | |
272 | return o.String() | |
273 | } | |
274 | ||
275 | func (t *MapType) KeyField() Field { return t.value.Elem().(*StructType).Field(0) } | |
276 | func (t *MapType) KeyType() DataType { return t.KeyField().Type } | |
277 | func (t *MapType) ItemField() Field { return t.value.Elem().(*StructType).Field(1) } | |
278 | func (t *MapType) ItemType() DataType { return t.ItemField().Type } | |
279 | func (t *MapType) ValueType() *StructType { return t.value.Elem().(*StructType) } | |
280 | func (t *MapType) ValueField() Field { | |
281 | return Field{ | |
282 | Name: "entries", | |
283 | Type: t.ValueType(), | |
284 | } | |
285 | } | |
286 | ||
287 | func (t *MapType) SetItemNullable(nullable bool) { | |
288 | t.value.Elem().(*StructType).fields[1].Nullable = nullable | |
289 | } | |
290 | ||
291 | func (t *MapType) Fingerprint() string { | |
292 | keyFingerprint := t.KeyType().Fingerprint() | |
293 | itemFingerprint := t.ItemType().Fingerprint() | |
294 | if keyFingerprint == "" || itemFingerprint == "" { | |
295 | return "" | |
296 | } | |
297 | ||
298 | fingerprint := typeFingerprint(t) | |
299 | if t.KeysSorted { | |
300 | fingerprint += "s" | |
301 | } | |
302 | return fingerprint + "{" + keyFingerprint + itemFingerprint + "}" | |
303 | } | |
304 | ||
305 | type Field struct { | |
306 | Name string // Field name | |
307 | Type DataType // The field's data type | |
308 | Nullable bool // Fields can be nullable | |
309 | Metadata Metadata // The field's metadata, if any | |
310 | } | |
311 | ||
312 | func (f Field) Fingerprint() string { | |
313 | typeFingerprint := f.Type.Fingerprint() | |
314 | if typeFingerprint == "" { | |
315 | return "" | |
316 | } | |
317 | ||
318 | var b strings.Builder | |
319 | b.WriteByte('F') | |
320 | if f.Nullable { | |
321 | b.WriteByte('n') | |
322 | } else { | |
323 | b.WriteByte('N') | |
324 | } | |
325 | b.WriteString(f.Name) | |
326 | b.WriteByte('{') | |
327 | b.WriteString(typeFingerprint) | |
328 | b.WriteByte('}') | |
329 | return b.String() | |
330 | } | |
331 | ||
332 | func (f Field) HasMetadata() bool { return f.Metadata.Len() != 0 } | |
333 | ||
334 | func (f Field) Equal(o Field) bool { | |
335 | switch { | |
336 | case f.Name != o.Name: | |
337 | return false | |
338 | case f.Nullable != o.Nullable: | |
339 | return false | |
340 | case !TypeEqual(f.Type, o.Type, CheckMetadata()): | |
341 | return false | |
342 | case !f.Metadata.Equal(o.Metadata): | |
343 | return false | |
344 | } | |
345 | return true | |
346 | } | |
347 | ||
348 | func (f Field) String() string { | |
349 | o := new(strings.Builder) | |
350 | nullable := "" | |
351 | if f.Nullable { | |
352 | nullable = ", nullable" | |
353 | } | |
354 | fmt.Fprintf(o, "%s: type=%v%v", f.Name, f.Type, nullable) | |
355 | if f.HasMetadata() { | |
356 | fmt.Fprintf(o, "\n%*.smetadata: %v", len(f.Name)+2, "", f.Metadata) | |
357 | } | |
358 | return o.String() | |
359 | } | |
360 | ||
361 | var ( | |
362 | _ DataType = (*ListType)(nil) | |
363 | _ DataType = (*StructType)(nil) | |
364 | _ DataType = (*MapType)(nil) | |
365 | ) |