github.com/apache/arrow/go/v14@v14.0.1/parquet/schema/schema_element_test.go (about) 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 schema 18 19 import ( 20 "testing" 21 22 "github.com/apache/arrow/go/v14/parquet" 23 format "github.com/apache/arrow/go/v14/parquet/internal/gen-go/parquet" 24 "github.com/stretchr/testify/assert" 25 "github.com/stretchr/testify/suite" 26 ) 27 28 type schemaElementConstruction struct { 29 node Node 30 element *format.SchemaElement 31 name string 32 expectConverted bool 33 converted ConvertedType 34 expectLogical bool 35 checkLogical func(*format.SchemaElement) bool 36 } 37 38 type decimalSchemaElementConstruction struct { 39 schemaElementConstruction 40 precision int 41 scale int 42 } 43 44 type temporalSchemaElementConstruction struct { 45 schemaElementConstruction 46 adjusted bool 47 unit TimeUnitType 48 getUnit func(*format.SchemaElement) *format.TimeUnit 49 } 50 51 type intSchemaElementConstruction struct { 52 schemaElementConstruction 53 width int8 54 signed bool 55 } 56 57 type legacySchemaElementConstructArgs struct { 58 name string 59 physical parquet.Type 60 len int 61 expectConverted bool 62 converted ConvertedType 63 expectLogical bool 64 checkLogical func(*format.SchemaElement) bool 65 } 66 67 type schemaElementConstructArgs struct { 68 name string 69 logical LogicalType 70 physical parquet.Type 71 len int 72 expectConverted bool 73 converted ConvertedType 74 expectLogical bool 75 checkLogical func(*format.SchemaElement) bool 76 } 77 type SchemaElementConstructionSuite struct { 78 suite.Suite 79 } 80 81 func (s *SchemaElementConstructionSuite) reconstruct(c schemaElementConstructArgs) *schemaElementConstruction { 82 ret := &schemaElementConstruction{ 83 node: MustPrimitive(NewPrimitiveNodeLogical(c.name, parquet.Repetitions.Required, c.logical, c.physical, c.len, -1)), 84 name: c.name, 85 expectConverted: c.expectConverted, 86 converted: c.converted, 87 expectLogical: c.expectLogical, 88 checkLogical: c.checkLogical, 89 } 90 ret.element = ret.node.toThrift() 91 return ret 92 } 93 94 func (s *SchemaElementConstructionSuite) legacyReconstruct(c legacySchemaElementConstructArgs) *schemaElementConstruction { 95 ret := &schemaElementConstruction{ 96 node: MustPrimitive(NewPrimitiveNodeConverted(c.name, parquet.Repetitions.Required, c.physical, c.converted, c.len, 0, 0, -1)), 97 name: c.name, 98 expectConverted: c.expectConverted, 99 converted: c.converted, 100 expectLogical: c.expectLogical, 101 checkLogical: c.checkLogical, 102 } 103 ret.element = ret.node.toThrift() 104 return ret 105 } 106 107 func (s *SchemaElementConstructionSuite) inspect(c *schemaElementConstruction) { 108 if c.expectConverted { 109 s.True(c.element.IsSetConvertedType()) 110 s.Equal(c.converted, ConvertedType(*c.element.ConvertedType)) 111 } else { 112 s.False(c.element.IsSetConvertedType()) 113 } 114 if c.expectLogical { 115 s.True(c.element.IsSetLogicalType()) 116 s.True(c.checkLogical(c.element)) 117 } else { 118 s.False(c.element.IsSetLogicalType()) 119 } 120 } 121 122 func (s *SchemaElementConstructionSuite) TestSimple() { 123 checkNone := func(*format.SchemaElement) bool { return true } 124 125 tests := []struct { 126 name string 127 args *schemaElementConstructArgs 128 legacy *legacySchemaElementConstructArgs 129 }{ 130 {"string", &schemaElementConstructArgs{ 131 "string", StringLogicalType{}, parquet.Types.ByteArray, -1, true, ConvertedTypes.UTF8, true, 132 func(e *format.SchemaElement) bool { return e.LogicalType.IsSetSTRING() }, 133 }, nil}, 134 {"enum", &schemaElementConstructArgs{ 135 "enum", EnumLogicalType{}, parquet.Types.ByteArray, -1, true, ConvertedTypes.Enum, true, 136 func(e *format.SchemaElement) bool { return e.LogicalType.IsSetENUM() }, 137 }, nil}, 138 {"date", &schemaElementConstructArgs{ 139 "date", DateLogicalType{}, parquet.Types.Int32, -1, true, ConvertedTypes.Date, true, 140 func(e *format.SchemaElement) bool { return e.LogicalType.IsSetDATE() }, 141 }, nil}, 142 {"interval", &schemaElementConstructArgs{ 143 "interval", IntervalLogicalType{}, parquet.Types.FixedLenByteArray, 12, true, ConvertedTypes.Interval, false, 144 checkNone, 145 }, nil}, 146 {"null", &schemaElementConstructArgs{ 147 "null", NullLogicalType{}, parquet.Types.Double, -1, false, ConvertedTypes.NA, true, 148 func(e *format.SchemaElement) bool { return e.LogicalType.IsSetUNKNOWN() }, 149 }, nil}, 150 {"json", &schemaElementConstructArgs{ 151 "json", JSONLogicalType{}, parquet.Types.ByteArray, -1, true, ConvertedTypes.JSON, true, 152 func(e *format.SchemaElement) bool { return e.LogicalType.IsSetJSON() }, 153 }, nil}, 154 {"bson", &schemaElementConstructArgs{ 155 "bson", BSONLogicalType{}, parquet.Types.ByteArray, -1, true, ConvertedTypes.BSON, true, 156 func(e *format.SchemaElement) bool { return e.LogicalType.IsSetBSON() }, 157 }, nil}, 158 {"uuid", &schemaElementConstructArgs{ 159 "uuid", UUIDLogicalType{}, parquet.Types.FixedLenByteArray, 16, false, ConvertedTypes.NA, true, 160 func(e *format.SchemaElement) bool { return e.LogicalType.IsSetUUID() }, 161 }, nil}, 162 {"none", &schemaElementConstructArgs{ 163 "none", NoLogicalType{}, parquet.Types.Int64, -1, false, ConvertedTypes.NA, false, 164 checkNone, 165 }, nil}, 166 {"unknown", &schemaElementConstructArgs{ 167 "unknown", UnknownLogicalType{}, parquet.Types.Int64, -1, true, ConvertedTypes.NA, false, 168 checkNone, 169 }, nil}, 170 {"timestamp_ms", nil, &legacySchemaElementConstructArgs{ 171 "timestamp_ms", parquet.Types.Int64, -1, true, ConvertedTypes.TimestampMillis, false, checkNone}}, 172 {"timestamp_us", nil, &legacySchemaElementConstructArgs{ 173 "timestamp_us", parquet.Types.Int64, -1, true, ConvertedTypes.TimestampMicros, false, checkNone}}, 174 } 175 for _, tt := range tests { 176 s.Run(tt.name, func() { 177 var sc *schemaElementConstruction 178 if tt.args != nil { 179 sc = s.reconstruct(*tt.args) 180 } else { 181 sc = s.legacyReconstruct(*tt.legacy) 182 } 183 s.Equal(tt.name, sc.element.Name) 184 s.inspect(sc) 185 }) 186 } 187 } 188 189 func (s *SchemaElementConstructionSuite) reconstructDecimal(c schemaElementConstructArgs) *decimalSchemaElementConstruction { 190 ret := s.reconstruct(c) 191 dec := c.logical.(*DecimalLogicalType) 192 return &decimalSchemaElementConstruction{*ret, int(dec.Precision()), int(dec.Scale())} 193 } 194 195 func (s *SchemaElementConstructionSuite) inspectDecimal(d *decimalSchemaElementConstruction) { 196 s.inspect(&d.schemaElementConstruction) 197 s.EqualValues(d.precision, d.element.GetPrecision()) 198 s.EqualValues(d.scale, d.element.GetScale()) 199 s.EqualValues(d.precision, d.element.LogicalType.DECIMAL.Precision) 200 s.EqualValues(d.scale, d.element.LogicalType.DECIMAL.Scale) 201 } 202 203 func (s *SchemaElementConstructionSuite) TestDecimal() { 204 checkDecimal := func(p *format.SchemaElement) bool { return p.LogicalType.IsSetDECIMAL() } 205 206 tests := []schemaElementConstructArgs{ 207 { 208 name: "decimal16_6", logical: NewDecimalLogicalType(16 /* precision */, 6 /* scale */), 209 physical: parquet.Types.Int64, len: -1, expectConverted: true, converted: ConvertedTypes.Decimal, 210 expectLogical: true, checkLogical: checkDecimal, 211 }, 212 { 213 name: "decimal1_0", logical: NewDecimalLogicalType(1 /* precision */, 0 /* scale */), 214 physical: parquet.Types.Int32, len: -1, expectConverted: true, converted: ConvertedTypes.Decimal, 215 expectLogical: true, checkLogical: checkDecimal, 216 }, 217 { 218 name: "decimal10", logical: NewDecimalLogicalType(10 /* precision */, 0 /* scale */), 219 physical: parquet.Types.Int64, len: -1, expectConverted: true, converted: ConvertedTypes.Decimal, 220 expectLogical: true, checkLogical: checkDecimal, 221 }, 222 { 223 name: "decimal11_11", logical: NewDecimalLogicalType(11 /* precision */, 11 /* scale */), 224 physical: parquet.Types.Int64, len: -1, expectConverted: true, converted: ConvertedTypes.Decimal, 225 expectLogical: true, checkLogical: checkDecimal, 226 }, 227 } 228 for _, tt := range tests { 229 s.Run(tt.name, func() { 230 d := s.reconstructDecimal(tt) 231 s.Equal(tt.name, d.element.Name) 232 s.inspectDecimal(d) 233 }) 234 } 235 } 236 237 func (s *SchemaElementConstructionSuite) reconstructTemporal(c schemaElementConstructArgs, getUnit func(*format.SchemaElement) *format.TimeUnit) *temporalSchemaElementConstruction { 238 base := s.reconstruct(c) 239 t := c.logical.(TemporalLogicalType) 240 return &temporalSchemaElementConstruction{ 241 *base, 242 t.IsAdjustedToUTC(), 243 t.TimeUnit(), 244 getUnit, 245 } 246 } 247 248 func (s *SchemaElementConstructionSuite) inspectTemporal(t *temporalSchemaElementConstruction) { 249 s.inspect(&t.schemaElementConstruction) 250 switch t.unit { 251 case TimeUnitMillis: 252 s.True(t.getUnit(t.element).IsSetMILLIS()) 253 case TimeUnitMicros: 254 s.True(t.getUnit(t.element).IsSetMICROS()) 255 case TimeUnitNanos: 256 s.True(t.getUnit(t.element).IsSetNANOS()) 257 case TimeUnitUnknown: 258 fallthrough 259 default: 260 s.Fail("invalid time unit in test case") 261 } 262 } 263 264 func (s *SchemaElementConstructionSuite) TestTemporal() { 265 checkTime := func(p *format.SchemaElement) bool { 266 return p.LogicalType.IsSetTIME() 267 } 268 checkTimestamp := func(p *format.SchemaElement) bool { 269 return p.LogicalType.IsSetTIMESTAMP() 270 } 271 272 getTimeUnit := func(p *format.SchemaElement) *format.TimeUnit { 273 return p.LogicalType.TIME.Unit 274 } 275 getTimestampUnit := func(p *format.SchemaElement) *format.TimeUnit { 276 return p.LogicalType.TIMESTAMP.Unit 277 } 278 279 timeTests := []schemaElementConstructArgs{ 280 { 281 name: "time_T_ms", logical: NewTimeLogicalType(true, TimeUnitMillis), physical: parquet.Types.Int32, len: -1, 282 expectConverted: true, converted: ConvertedTypes.TimeMillis, expectLogical: true, checkLogical: checkTime, 283 }, 284 { 285 name: "time_F_ms", logical: NewTimeLogicalType(false, TimeUnitMillis), physical: parquet.Types.Int32, len: -1, 286 expectConverted: false, converted: ConvertedTypes.NA, expectLogical: true, checkLogical: checkTime, 287 }, 288 { 289 name: "time_T_us", logical: NewTimeLogicalType(true, TimeUnitMicros), physical: parquet.Types.Int64, len: -1, 290 expectConverted: true, converted: ConvertedTypes.TimeMicros, expectLogical: true, checkLogical: checkTime, 291 }, 292 { 293 name: "time_F_us", logical: NewTimeLogicalType(false, TimeUnitMicros), physical: parquet.Types.Int64, len: -1, 294 expectConverted: false, converted: ConvertedTypes.NA, expectLogical: true, checkLogical: checkTime, 295 }, 296 { 297 name: "time_T_ns", logical: NewTimeLogicalType(true, TimeUnitNanos), physical: parquet.Types.Int64, len: -1, 298 expectConverted: false, converted: ConvertedTypes.NA, expectLogical: true, checkLogical: checkTime, 299 }, 300 { 301 name: "time_F_ns", logical: NewTimeLogicalType(false, TimeUnitNanos), physical: parquet.Types.Int64, len: -1, 302 expectConverted: false, converted: ConvertedTypes.NA, expectLogical: true, checkLogical: checkTime, 303 }, 304 } 305 timeStampTests := []schemaElementConstructArgs{ 306 { 307 name: "timestamp_T_ms", logical: NewTimestampLogicalType(true, TimeUnitMillis), physical: parquet.Types.Int64, len: -1, 308 expectConverted: true, converted: ConvertedTypes.TimestampMillis, expectLogical: true, checkLogical: checkTimestamp, 309 }, 310 { 311 name: "timestamp_F_ms", logical: NewTimestampLogicalType(false, TimeUnitMillis), physical: parquet.Types.Int64, len: -1, 312 expectConverted: false, converted: ConvertedTypes.NA, expectLogical: true, checkLogical: checkTimestamp, 313 }, 314 { 315 name: "timestamp_F_ms_force", logical: NewTimestampLogicalTypeForce(false, TimeUnitMillis), physical: parquet.Types.Int64, len: -1, 316 expectConverted: true, converted: ConvertedTypes.TimestampMillis, expectLogical: true, checkLogical: checkTimestamp, 317 }, 318 { 319 name: "timestamp_T_us", logical: NewTimestampLogicalType(true, TimeUnitMicros), physical: parquet.Types.Int64, len: -1, 320 expectConverted: true, converted: ConvertedTypes.TimestampMicros, expectLogical: true, checkLogical: checkTimestamp, 321 }, 322 { 323 name: "timestamp_F_us", logical: NewTimestampLogicalType(false, TimeUnitMicros), physical: parquet.Types.Int64, len: -1, 324 expectConverted: false, converted: ConvertedTypes.NA, expectLogical: true, checkLogical: checkTimestamp, 325 }, 326 { 327 name: "timestamp_F_us_force", logical: NewTimestampLogicalTypeForce(false, TimeUnitMicros), physical: parquet.Types.Int64, len: -1, 328 expectConverted: true, converted: ConvertedTypes.TimestampMicros, expectLogical: true, checkLogical: checkTimestamp, 329 }, 330 { 331 name: "timestamp_T_ns", logical: NewTimestampLogicalType(true, TimeUnitNanos), physical: parquet.Types.Int64, len: -1, 332 expectConverted: false, converted: ConvertedTypes.NA, expectLogical: true, checkLogical: checkTimestamp, 333 }, 334 { 335 name: "timestamp_F_ns", logical: NewTimestampLogicalType(false, TimeUnitNanos), physical: parquet.Types.Int64, len: -1, 336 expectConverted: false, converted: ConvertedTypes.NA, expectLogical: true, checkLogical: checkTimestamp, 337 }, 338 } 339 340 for _, tt := range timeTests { 341 s.Run(tt.name, func() { 342 t := s.reconstructTemporal(tt, getTimeUnit) 343 s.Equal(t.adjusted, t.element.LogicalType.TIME.IsAdjustedToUTC) 344 s.inspectTemporal(t) 345 }) 346 } 347 for _, tt := range timeStampTests { 348 s.Run(tt.name, func() { 349 t := s.reconstructTemporal(tt, getTimestampUnit) 350 s.Equal(t.adjusted, t.element.LogicalType.TIMESTAMP.IsAdjustedToUTC) 351 s.inspectTemporal(t) 352 }) 353 } 354 } 355 356 func (s *SchemaElementConstructionSuite) reconstructInteger(c schemaElementConstructArgs) *intSchemaElementConstruction { 357 base := s.reconstruct(c) 358 l := c.logical.(*IntLogicalType) 359 return &intSchemaElementConstruction{ 360 *base, 361 l.BitWidth(), 362 l.IsSigned(), 363 } 364 } 365 366 func (s *SchemaElementConstructionSuite) inspectInt(i *intSchemaElementConstruction) { 367 s.inspect(&i.schemaElementConstruction) 368 s.Equal(i.width, i.element.LogicalType.INTEGER.BitWidth) 369 s.Equal(i.signed, i.element.LogicalType.INTEGER.IsSigned) 370 } 371 372 func (s *SchemaElementConstructionSuite) TestIntegerCases() { 373 checkInt := func(p *format.SchemaElement) bool { return p.LogicalType.IsSetINTEGER() } 374 375 tests := []schemaElementConstructArgs{ 376 { 377 name: "uint8", logical: NewIntLogicalType(8, false), physical: parquet.Types.Int32, len: -1, 378 expectConverted: true, converted: ConvertedTypes.Uint8, expectLogical: true, checkLogical: checkInt, 379 }, 380 { 381 name: "uint16", logical: NewIntLogicalType(16, false), physical: parquet.Types.Int32, len: -1, 382 expectConverted: true, converted: ConvertedTypes.Uint16, expectLogical: true, checkLogical: checkInt, 383 }, 384 { 385 name: "uint32", logical: NewIntLogicalType(32, false), physical: parquet.Types.Int32, len: -1, 386 expectConverted: true, converted: ConvertedTypes.Uint32, expectLogical: true, checkLogical: checkInt, 387 }, 388 { 389 name: "uint64", logical: NewIntLogicalType(64, false), physical: parquet.Types.Int64, len: -1, 390 expectConverted: true, converted: ConvertedTypes.Uint64, expectLogical: true, checkLogical: checkInt, 391 }, 392 { 393 name: "int8", logical: NewIntLogicalType(8, true), physical: parquet.Types.Int32, len: -1, 394 expectConverted: true, converted: ConvertedTypes.Int8, expectLogical: true, checkLogical: checkInt, 395 }, 396 { 397 name: "int16", logical: NewIntLogicalType(16, true), physical: parquet.Types.Int32, len: -1, 398 expectConverted: true, converted: ConvertedTypes.Int16, expectLogical: true, checkLogical: checkInt, 399 }, 400 { 401 name: "int32", logical: NewIntLogicalType(32, true), physical: parquet.Types.Int32, len: -1, 402 expectConverted: true, converted: ConvertedTypes.Int32, expectLogical: true, checkLogical: checkInt, 403 }, 404 { 405 name: "int64", logical: NewIntLogicalType(64, true), physical: parquet.Types.Int64, len: -1, 406 expectConverted: true, converted: ConvertedTypes.Int64, expectLogical: true, checkLogical: checkInt, 407 }, 408 } 409 for _, tt := range tests { 410 s.Run(tt.name, func() { 411 t := s.reconstructInteger(tt) 412 s.inspectInt(t) 413 }) 414 } 415 } 416 417 func TestSchemaElementNestedSerialization(t *testing.T) { 418 // confirm that the intermediate thrift objects created during node serialization 419 // contain correct ConvertedType and ConvertedType information 420 421 strNode := MustPrimitive(NewPrimitiveNodeLogical("string" /*name */, parquet.Repetitions.Required, StringLogicalType{}, parquet.Types.ByteArray, -1 /* type len */, -1 /* fieldID */)) 422 dateNode := MustPrimitive(NewPrimitiveNodeLogical("date" /*name */, parquet.Repetitions.Required, DateLogicalType{}, parquet.Types.Int32, -1 /* type len */, -1 /* fieldID */)) 423 jsonNode := MustPrimitive(NewPrimitiveNodeLogical("json" /*name */, parquet.Repetitions.Required, JSONLogicalType{}, parquet.Types.ByteArray, -1 /* type len */, -1 /* fieldID */)) 424 uuidNode := MustPrimitive(NewPrimitiveNodeLogical("uuid" /*name */, parquet.Repetitions.Required, UUIDLogicalType{}, parquet.Types.FixedLenByteArray, 16 /* type len */, - /* fieldID */ 1)) 425 timestampNode := MustPrimitive(NewPrimitiveNodeLogical("timestamp" /*name */, parquet.Repetitions.Required, NewTimestampLogicalType(false /* adjustedToUTC */, TimeUnitNanos), parquet.Types.Int64, -1 /* type len */, -1 /* fieldID */)) 426 intNode := MustPrimitive(NewPrimitiveNodeLogical("int" /*name */, parquet.Repetitions.Required, NewIntLogicalType(64 /* bitWidth */, false /* signed */), parquet.Types.Int64, -1 /* type len */, -1 /* fieldID */)) 427 decimalNode := MustPrimitive(NewPrimitiveNodeLogical("decimal" /*name */, parquet.Repetitions.Required, NewDecimalLogicalType(16 /* precision */, 6 /* scale */), parquet.Types.Int64, -1 /* type len */, -1 /* fieldID */)) 428 listNode := MustGroup(NewGroupNodeLogical("list" /*name */, parquet.Repetitions.Repeated, []Node{strNode, dateNode, jsonNode, uuidNode, timestampNode, intNode, decimalNode}, NewListLogicalType(), -1 /* fieldID */)) 429 430 listElems := ToThrift(listNode) 431 assert.Equal(t, "list", listElems[0].Name) 432 assert.True(t, listElems[0].IsSetConvertedType()) 433 assert.True(t, listElems[0].IsSetLogicalType()) 434 assert.Equal(t, format.ConvertedType(ConvertedTypes.List), listElems[0].GetConvertedType()) 435 assert.True(t, listElems[0].LogicalType.IsSetLIST()) 436 assert.True(t, listElems[1].LogicalType.IsSetSTRING()) 437 assert.True(t, listElems[2].LogicalType.IsSetDATE()) 438 assert.True(t, listElems[3].LogicalType.IsSetJSON()) 439 assert.True(t, listElems[4].LogicalType.IsSetUUID()) 440 assert.True(t, listElems[5].LogicalType.IsSetTIMESTAMP()) 441 assert.True(t, listElems[6].LogicalType.IsSetINTEGER()) 442 assert.True(t, listElems[7].LogicalType.IsSetDECIMAL()) 443 444 mapNode := MustGroup(NewGroupNodeLogical("map" /* name */, parquet.Repetitions.Required, []Node{}, MapLogicalType{}, -1 /* fieldID */)) 445 mapElems := ToThrift(mapNode) 446 assert.Equal(t, "map", mapElems[0].Name) 447 assert.True(t, mapElems[0].IsSetConvertedType()) 448 assert.True(t, mapElems[0].IsSetLogicalType()) 449 assert.Equal(t, format.ConvertedType(ConvertedTypes.Map), mapElems[0].GetConvertedType()) 450 assert.True(t, mapElems[0].LogicalType.IsSetMAP()) 451 } 452 453 func TestLogicalTypeSerializationRoundTrip(t *testing.T) { 454 tests := []struct { 455 name string 456 logical LogicalType 457 physical parquet.Type 458 len int 459 }{ 460 {"string", StringLogicalType{}, parquet.Types.ByteArray, -1}, 461 {"enum", EnumLogicalType{}, parquet.Types.ByteArray, -1}, 462 {"decimal", NewDecimalLogicalType(16, 6), parquet.Types.Int64, -1}, 463 {"date", DateLogicalType{}, parquet.Types.Int32, -1}, 464 {"time_T_ms", NewTimeLogicalType(true, TimeUnitMillis), parquet.Types.Int32, -1}, 465 {"time_T_us", NewTimeLogicalType(true, TimeUnitMicros), parquet.Types.Int64, -1}, 466 {"time_T_ns", NewTimeLogicalType(true, TimeUnitNanos), parquet.Types.Int64, -1}, 467 {"time_F_ms", NewTimeLogicalType(false, TimeUnitMillis), parquet.Types.Int32, -1}, 468 {"time_F_us", NewTimeLogicalType(false, TimeUnitMicros), parquet.Types.Int64, -1}, 469 {"time_F_ns", NewTimeLogicalType(false, TimeUnitNanos), parquet.Types.Int64, -1}, 470 {"timestamp_T_ms", NewTimestampLogicalType(true, TimeUnitMillis), parquet.Types.Int64, -1}, 471 {"timestamp_T_us", NewTimestampLogicalType(true, TimeUnitMicros), parquet.Types.Int64, -1}, 472 {"timestamp_T_ns", NewTimestampLogicalType(true, TimeUnitNanos), parquet.Types.Int64, -1}, 473 {"timestamp_F_ms", NewTimestampLogicalType(false, TimeUnitMillis), parquet.Types.Int64, -1}, 474 {"timestamp_F_us", NewTimestampLogicalType(false, TimeUnitMicros), parquet.Types.Int64, -1}, 475 {"timestamp_F_ns", NewTimestampLogicalType(false, TimeUnitNanos), parquet.Types.Int64, -1}, 476 {"interval", IntervalLogicalType{}, parquet.Types.FixedLenByteArray, 12}, 477 {"uint8", NewIntLogicalType(8, false), parquet.Types.Int32, -1}, 478 {"uint16", NewIntLogicalType(16, false), parquet.Types.Int32, -1}, 479 {"uint32", NewIntLogicalType(32, false), parquet.Types.Int32, -1}, 480 {"uint64", NewIntLogicalType(64, false), parquet.Types.Int64, -1}, 481 {"int8", NewIntLogicalType(8, true), parquet.Types.Int32, -1}, 482 {"int16", NewIntLogicalType(16, true), parquet.Types.Int32, -1}, 483 {"int32", NewIntLogicalType(32, true), parquet.Types.Int32, -1}, 484 {"int64", NewIntLogicalType(64, true), parquet.Types.Int64, -1}, 485 {"null", NullLogicalType{}, parquet.Types.Boolean, -1}, 486 {"json", JSONLogicalType{}, parquet.Types.ByteArray, -1}, 487 {"bson", BSONLogicalType{}, parquet.Types.ByteArray, -1}, 488 {"uuid", UUIDLogicalType{}, parquet.Types.FixedLenByteArray, 16}, 489 {"none", NoLogicalType{}, parquet.Types.Boolean, -1}, 490 } 491 492 for _, tt := range tests { 493 t.Run(tt.name, func(t *testing.T) { 494 n := MustPrimitive(NewPrimitiveNodeLogical("something" /* name */, parquet.Repetitions.Required, tt.logical, tt.physical, tt.len, -1 /* fieldID */)) 495 elem := n.toThrift() 496 recover := MustPrimitive(PrimitiveNodeFromThrift(elem)) 497 assert.True(t, n.Equals(recover)) 498 }) 499 } 500 501 n := MustGroup(NewGroupNodeLogical("map" /* name */, parquet.Repetitions.Required, []Node{}, MapLogicalType{}, -1 /* fieldID */)) 502 elem := n.toThrift() 503 recover := MustGroup(GroupNodeFromThrift(elem, []Node{})) 504 assert.True(t, recover.Equals(n)) 505 506 n = MustGroup(NewGroupNodeLogical("list" /* name */, parquet.Repetitions.Required, []Node{}, ListLogicalType{}, -1 /* fieldID */)) 507 elem = n.toThrift() 508 recover = MustGroup(GroupNodeFromThrift(elem, []Node{})) 509 assert.True(t, recover.Equals(n)) 510 } 511 512 func TestSchemaElementConstruction(t *testing.T) { 513 suite.Run(t, new(SchemaElementConstructionSuite)) 514 }