| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package serialize | 5 package serialize |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "bytes" | 8 "bytes" |
| 9 "errors" | 9 "errors" |
| 10 "fmt" | 10 "fmt" |
| 11 "sort" | 11 "sort" |
| 12 "time" | 12 "time" |
| 13 | 13 |
| 14 "github.com/luci/gae/service/blobstore" | 14 "github.com/luci/gae/service/blobstore" |
| 15 ds "github.com/luci/gae/service/datastore" | 15 ds "github.com/luci/gae/service/datastore" |
| 16 "github.com/luci/gae/service/datastore/dskey" | |
| 17 "github.com/luci/luci-go/common/cmpbin" | 16 "github.com/luci/luci-go/common/cmpbin" |
| 18 ) | 17 ) |
| 19 | 18 |
| 20 // MaxIndexColumns is the maximum number of sort columns (e.g. sort orders) that | 19 // MaxIndexColumns is the maximum number of sort columns (e.g. sort orders) that |
| 21 // ReadIndexDefinition is willing to deserialize. 64 was chosen as | 20 // ReadIndexDefinition is willing to deserialize. 64 was chosen as |
| 22 // a likely-astronomical number. | 21 // a likely-astronomical number. |
| 23 const MaxIndexColumns = 64 | 22 const MaxIndexColumns = 64 |
| 24 | 23 |
| 25 // WritePropertyMapDeterministic allows tests to make WritePropertyMap | 24 // WritePropertyMapDeterministic allows tests to make WritePropertyMap |
| 26 // deterministic. | 25 // deterministic. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 44 | 43 |
| 45 // With- and WithoutContext indicate if the serialization method should include | 44 // With- and WithoutContext indicate if the serialization method should include |
| 46 // context for Keys. See KeyContext for more information. | 45 // context for Keys. See KeyContext for more information. |
| 47 const ( | 46 const ( |
| 48 WithContext KeyContext = true | 47 WithContext KeyContext = true |
| 49 WithoutContext = false | 48 WithoutContext = false |
| 50 ) | 49 ) |
| 51 | 50 |
| 52 // WriteKey encodes a key to the buffer. If context is WithContext, then this | 51 // WriteKey encodes a key to the buffer. If context is WithContext, then this |
| 53 // encoded value will include the appid and namespace of the key. | 52 // encoded value will include the appid and namespace of the key. |
| 54 func WriteKey(buf Buffer, context KeyContext, k ds.Key) (err error) { | 53 func WriteKey(buf Buffer, context KeyContext, k *ds.Key) (err error) { |
| 55 // [appid ++ namespace]? ++ [1 ++ token]* ++ NULL | 54 // [appid ++ namespace]? ++ [1 ++ token]* ++ NULL |
| 56 defer recoverTo(&err) | 55 defer recoverTo(&err) |
| 57 » appid, namespace, toks := dskey.Split(k) | 56 » appid, namespace, toks := k.Split() |
| 58 if context == WithContext { | 57 if context == WithContext { |
| 59 panicIf(buf.WriteByte(1)) | 58 panicIf(buf.WriteByte(1)) |
| 60 _, e := cmpbin.WriteString(buf, appid) | 59 _, e := cmpbin.WriteString(buf, appid) |
| 61 panicIf(e) | 60 panicIf(e) |
| 62 _, e = cmpbin.WriteString(buf, namespace) | 61 _, e = cmpbin.WriteString(buf, namespace) |
| 63 panicIf(e) | 62 panicIf(e) |
| 64 } else { | 63 } else { |
| 65 panicIf(buf.WriteByte(0)) | 64 panicIf(buf.WriteByte(0)) |
| 66 } | 65 } |
| 67 for _, tok := range toks { | 66 for _, tok := range toks { |
| 68 panicIf(buf.WriteByte(1)) | 67 panicIf(buf.WriteByte(1)) |
| 69 panicIf(WriteKeyTok(buf, tok)) | 68 panicIf(WriteKeyTok(buf, tok)) |
| 70 } | 69 } |
| 71 return buf.WriteByte(0) | 70 return buf.WriteByte(0) |
| 72 } | 71 } |
| 73 | 72 |
| 74 // ReadKey deserializes a key from the buffer. The value of context must match | 73 // ReadKey deserializes a key from the buffer. The value of context must match |
| 75 // the value of context that was passed to WriteKey when the key was encoded. | 74 // the value of context that was passed to WriteKey when the key was encoded. |
| 76 // If context == WithoutContext, then the appid and namespace parameters are | 75 // If context == WithoutContext, then the appid and namespace parameters are |
| 77 // used in the decoded Key. Otherwise they're ignored. | 76 // used in the decoded Key. Otherwise they're ignored. |
| 78 func ReadKey(buf Buffer, context KeyContext, appid, namespace string) (ret ds.Ke
y, err error) { | 77 func ReadKey(buf Buffer, context KeyContext, appid, namespace string) (ret *ds.K
ey, err error) { |
| 79 defer recoverTo(&err) | 78 defer recoverTo(&err) |
| 80 actualCtx, e := buf.ReadByte() | 79 actualCtx, e := buf.ReadByte() |
| 81 panicIf(e) | 80 panicIf(e) |
| 82 | 81 |
| 83 actualAid, actualNS := "", "" | 82 actualAid, actualNS := "", "" |
| 84 if actualCtx == 1 { | 83 if actualCtx == 1 { |
| 85 actualAid, _, e = cmpbin.ReadString(buf) | 84 actualAid, _, e = cmpbin.ReadString(buf) |
| 86 panicIf(e) | 85 panicIf(e) |
| 87 actualNS, _, e = cmpbin.ReadString(buf) | 86 actualNS, _, e = cmpbin.ReadString(buf) |
| 88 panicIf(e) | 87 panicIf(e) |
| (...skipping 21 matching lines...) Expand all Loading... |
| 110 ReadKeyNumToksReasonableLimit) | 109 ReadKeyNumToksReasonableLimit) |
| 111 return | 110 return |
| 112 } | 111 } |
| 113 | 112 |
| 114 tok, e := ReadKeyTok(buf) | 113 tok, e := ReadKeyTok(buf) |
| 115 panicIf(e) | 114 panicIf(e) |
| 116 | 115 |
| 117 toks = append(toks, tok) | 116 toks = append(toks, tok) |
| 118 } | 117 } |
| 119 | 118 |
| 120 » return dskey.NewToks(actualAid, actualNS, toks), nil | 119 » return ds.NewKeyToks(actualAid, actualNS, toks), nil |
| 121 } | 120 } |
| 122 | 121 |
| 123 // WriteKeyTok writes a KeyTok to the buffer. You usually want WriteKey | 122 // WriteKeyTok writes a KeyTok to the buffer. You usually want WriteKey |
| 124 // instead of this. | 123 // instead of this. |
| 125 func WriteKeyTok(buf Buffer, tok ds.KeyTok) (err error) { | 124 func WriteKeyTok(buf Buffer, tok ds.KeyTok) (err error) { |
| 126 // tok.kind ++ typ ++ [tok.stringID || tok.intID] | 125 // tok.kind ++ typ ++ [tok.stringID || tok.intID] |
| 127 defer recoverTo(&err) | 126 defer recoverTo(&err) |
| 128 _, e := cmpbin.WriteString(buf, tok.Kind) | 127 _, e := cmpbin.WriteString(buf, tok.Kind) |
| 129 panicIf(e) | 128 panicIf(e) |
| 130 if tok.StringID != "" { | 129 if tok.StringID != "" { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 _, err = cmpbin.WriteFloat64(buf, p.Value().(float64)) | 235 _, err = cmpbin.WriteFloat64(buf, p.Value().(float64)) |
| 237 case ds.PTString: | 236 case ds.PTString: |
| 238 _, err = cmpbin.WriteString(buf, p.Value().(string)) | 237 _, err = cmpbin.WriteString(buf, p.Value().(string)) |
| 239 case ds.PTBytes: | 238 case ds.PTBytes: |
| 240 _, err = cmpbin.WriteBytes(buf, p.Value().([]byte)) | 239 _, err = cmpbin.WriteBytes(buf, p.Value().([]byte)) |
| 241 case ds.PTTime: | 240 case ds.PTTime: |
| 242 err = WriteTime(buf, p.Value().(time.Time)) | 241 err = WriteTime(buf, p.Value().(time.Time)) |
| 243 case ds.PTGeoPoint: | 242 case ds.PTGeoPoint: |
| 244 err = WriteGeoPoint(buf, p.Value().(ds.GeoPoint)) | 243 err = WriteGeoPoint(buf, p.Value().(ds.GeoPoint)) |
| 245 case ds.PTKey: | 244 case ds.PTKey: |
| 246 » » err = WriteKey(buf, context, p.Value().(ds.Key)) | 245 » » err = WriteKey(buf, context, p.Value().(*ds.Key)) |
| 247 case ds.PTBlobKey: | 246 case ds.PTBlobKey: |
| 248 _, err = cmpbin.WriteString(buf, string(p.Value().(blobstore.Key
))) | 247 _, err = cmpbin.WriteString(buf, string(p.Value().(blobstore.Key
))) |
| 249 } | 248 } |
| 250 return | 249 return |
| 251 } | 250 } |
| 252 | 251 |
| 253 // ReadProperty reads a Property from the buffer. `context`, `appid`, and | 252 // ReadProperty reads a Property from the buffer. `context`, `appid`, and |
| 254 // `namespace` behave the same way they do for ReadKey, but only have an | 253 // `namespace` behave the same way they do for ReadKey, but only have an |
| 255 // effect if the decoded property has a Key value. | 254 // effect if the decoded property has a Key value. |
| 256 func ReadProperty(buf Buffer, context KeyContext, appid, namespace string) (p ds
.Property, err error) { | 255 func ReadProperty(buf Buffer, context KeyContext, appid, namespace string) (p ds
.Property, err error) { |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 368 } | 367 } |
| 369 pm[name] = props | 368 pm[name] = props |
| 370 } | 369 } |
| 371 return | 370 return |
| 372 } | 371 } |
| 373 | 372 |
| 374 // WriteIndexColumn writes an IndexColumn to the buffer. | 373 // WriteIndexColumn writes an IndexColumn to the buffer. |
| 375 func WriteIndexColumn(buf Buffer, c ds.IndexColumn) (err error) { | 374 func WriteIndexColumn(buf Buffer, c ds.IndexColumn) (err error) { |
| 376 defer recoverTo(&err) | 375 defer recoverTo(&err) |
| 377 | 376 |
| 378 » if c.Direction == ds.ASCENDING { | 377 » if !c.Descending { |
| 379 panicIf(buf.WriteByte(0)) | 378 panicIf(buf.WriteByte(0)) |
| 380 } else { | 379 } else { |
| 381 panicIf(buf.WriteByte(1)) | 380 panicIf(buf.WriteByte(1)) |
| 382 } | 381 } |
| 383 _, err = cmpbin.WriteString(buf, c.Property) | 382 _, err = cmpbin.WriteString(buf, c.Property) |
| 384 return | 383 return |
| 385 } | 384 } |
| 386 | 385 |
| 387 // ReadIndexColumn reads an IndexColumn from the buffer. | 386 // ReadIndexColumn reads an IndexColumn from the buffer. |
| 388 func ReadIndexColumn(buf Buffer) (c ds.IndexColumn, err error) { | 387 func ReadIndexColumn(buf Buffer) (c ds.IndexColumn, err error) { |
| 389 defer recoverTo(&err) | 388 defer recoverTo(&err) |
| 390 | 389 |
| 391 dir, err := buf.ReadByte() | 390 dir, err := buf.ReadByte() |
| 392 panicIf(err) | 391 panicIf(err) |
| 393 | 392 |
| 394 » switch dir { | 393 » c.Descending = dir != 0 |
| 395 » case 0: | |
| 396 » » c.Direction = ds.ASCENDING | |
| 397 » default: | |
| 398 » » c.Direction = ds.DESCENDING | |
| 399 » } | |
| 400 c.Property, _, err = cmpbin.ReadString(buf) | 394 c.Property, _, err = cmpbin.ReadString(buf) |
| 401 return | 395 return |
| 402 } | 396 } |
| 403 | 397 |
| 404 // WriteIndexDefinition writes an IndexDefinition to the buffer | 398 // WriteIndexDefinition writes an IndexDefinition to the buffer |
| 405 func WriteIndexDefinition(buf Buffer, i ds.IndexDefinition) (err error) { | 399 func WriteIndexDefinition(buf Buffer, i ds.IndexDefinition) (err error) { |
| 406 defer recoverTo(&err) | 400 defer recoverTo(&err) |
| 407 | 401 |
| 408 _, err = cmpbin.WriteString(buf, i.Kind) | 402 _, err = cmpbin.WriteString(buf, i.Kind) |
| 409 panicIf(err) | 403 panicIf(err) |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 457 switch x := i.(type) { | 451 switch x := i.(type) { |
| 458 case ds.GeoPoint: | 452 case ds.GeoPoint: |
| 459 err = WriteGeoPoint(buf, x) | 453 err = WriteGeoPoint(buf, x) |
| 460 | 454 |
| 461 case ds.IndexColumn: | 455 case ds.IndexColumn: |
| 462 err = WriteIndexColumn(buf, x) | 456 err = WriteIndexColumn(buf, x) |
| 463 | 457 |
| 464 case ds.IndexDefinition: | 458 case ds.IndexDefinition: |
| 465 err = WriteIndexDefinition(buf, x) | 459 err = WriteIndexDefinition(buf, x) |
| 466 | 460 |
| 467 » case ds.Key: | 461 » case *ds.Key: |
| 468 err = WriteKey(buf, ctx, x) | 462 err = WriteKey(buf, ctx, x) |
| 469 | 463 |
| 470 case ds.KeyTok: | 464 case ds.KeyTok: |
| 471 err = WriteKeyTok(buf, x) | 465 err = WriteKeyTok(buf, x) |
| 472 | 466 |
| 473 case ds.Property: | 467 case ds.Property: |
| 474 err = WriteProperty(buf, ctx, x) | 468 err = WriteProperty(buf, ctx, x) |
| 475 | 469 |
| 476 case ds.PropertyMap: | 470 case ds.PropertyMap: |
| 477 err = WritePropertyMap(buf, ctx, x) | 471 err = WritePropertyMap(buf, ctx, x) |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 542 } | 536 } |
| 543 } | 537 } |
| 544 | 538 |
| 545 func recoverTo(err *error) { | 539 func recoverTo(err *error) { |
| 546 if r := recover(); r != nil { | 540 if r := recover(); r != nil { |
| 547 if rerr := r.(parseError); rerr != nil { | 541 if rerr := r.(parseError); rerr != nil { |
| 548 *err = error(rerr) | 542 *err = error(rerr) |
| 549 } | 543 } |
| 550 } | 544 } |
| 551 } | 545 } |
| OLD | NEW |