code.vegaprotocol.io/vega@v0.79.0/core/integration/steps/table_wrapper.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package steps 17 18 import ( 19 "errors" 20 "fmt" 21 "strconv" 22 "strings" 23 "time" 24 25 "code.vegaprotocol.io/vega/core/events" 26 "code.vegaprotocol.io/vega/core/types" 27 "code.vegaprotocol.io/vega/libs/num" 28 "code.vegaprotocol.io/vega/libs/ptr" 29 proto "code.vegaprotocol.io/vega/protos/vega" 30 commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1" 31 datav1 "code.vegaprotocol.io/vega/protos/vega/data/v1" 32 eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1" 33 34 "github.com/cucumber/godog" 35 "github.com/cucumber/messages-go/v16" 36 ) 37 38 // StrictParseFirstRow parses and verifies, table integrity and returns only the 39 // first row. This is suitable of table that act more as object than actual 40 // table. 41 func StrictParseFirstRow(table *godog.Table, required, optional []string) RowWrapper { 42 rows := StrictParseTable(table, required, optional) 43 44 if len(rows) > 1 { 45 panic("this table supports only one row") 46 } 47 48 return rows[0] 49 } 50 51 // StrictParseTable parses and verifies the table integrity. 52 func StrictParseTable(dt *godog.Table, required, optional []string) []RowWrapper { 53 tableLen := len(dt.Rows) 54 if tableLen < 1 { 55 panic("A table is required.") 56 } 57 58 if len(required)+len(optional) != 0 { 59 err := verifyTableIntegrity(required, optional, dt.Rows[0]) 60 if err != nil { 61 panic(err) 62 } 63 } 64 65 tableWithoutHeaderLen := tableLen - 1 66 if tableWithoutHeaderLen == 0 { 67 panic("Did you forget the table header?") 68 } 69 70 out := make([]RowWrapper, 0, tableWithoutHeaderLen) 71 for _, row := range dt.Rows[1:] { 72 wrapper := RowWrapper{values: map[string]string{}} 73 for i := range row.Cells { 74 wrapper.values[dt.Rows[0].Cells[i].Value] = row.Cells[i].Value 75 } 76 out = append(out, wrapper) 77 } 78 79 return out 80 } 81 82 // ParseTable parses the table without verifying its integrity. 83 // Prefer the use of StrictParseTable(). 84 func ParseTable(dt *godog.Table) []RowWrapper { 85 return StrictParseTable(dt, []string{}, []string{}) 86 } 87 88 func verifyTableIntegrity(required, optional []string, header *messages.PickleTableRow) error { 89 cols, err := newColumns(required, optional) 90 if err != nil { 91 return err 92 } 93 94 headerNames := make([]string, 0, len(header.Cells)) 95 for _, cell := range header.Cells { 96 headerNames = append(headerNames, cell.Value) 97 } 98 99 return cols.Verify(headerNames) 100 } 101 102 type columns struct { 103 // config maps a column name to it required state. 104 // true == required 105 // false == optional 106 config map[string]bool 107 } 108 109 func newColumns(required []string, optional []string) (*columns, error) { 110 config := map[string]bool{} 111 112 for _, column := range required { 113 config[column] = true 114 } 115 116 for _, optColumn := range optional { 117 _, ok := config[optColumn] 118 if ok { 119 return nil, fmt.Errorf("column \"%s\" can't be required and optional at the same time", optColumn) 120 } 121 config[optColumn] = false 122 } 123 124 return &columns{ 125 config: config, 126 }, nil 127 } 128 129 // Verify ensures the table declares the expected columns and does 130 // not declared any unexpected columns. 131 func (c *columns) Verify(header []string) error { 132 declaredColumnsSet := map[string]interface{}{} 133 134 for _, column := range header { 135 _, ok := c.config[column] 136 if !ok { 137 return fmt.Errorf("the column \"%s\" is not expected by this table", column) 138 } 139 declaredColumnsSet[column] = nil 140 } 141 142 for column, isRequired := range c.config { 143 _, ok := declaredColumnsSet[column] 144 if !ok && isRequired { 145 return fmt.Errorf("the column \"%s\" is required by this table", column) 146 } 147 } 148 149 return nil 150 } 151 152 type RowWrapper struct { 153 values map[string]string 154 } 155 156 func (r RowWrapper) mustColumn(name string) string { 157 s, ok := r.values[name] 158 if !ok { 159 panic(fmt.Errorf("column \"%s\" not found", name)) 160 } 161 return s 162 } 163 164 func (r RowWrapper) HasColumn(name string) bool { 165 if v, ok := r.values[name]; !ok || v == "" { 166 return false 167 } 168 return true 169 } 170 171 func (r RowWrapper) MustStr(name string) string { 172 return r.mustColumn(name) 173 } 174 175 // StrB does the same as Str, but returns a bool indicating whether or not the 176 // column was set. 177 func (r RowWrapper) StrB(name string) (string, bool) { 178 return r.Str(name), r.HasColumn(name) 179 } 180 181 func (r RowWrapper) Str(name string) string { 182 return r.values[name] 183 } 184 185 func (r RowWrapper) MustStrSlice(name, sep string) []string { 186 return StrSlice(r.mustColumn(name), sep) 187 } 188 189 func (r RowWrapper) StrSlice(name, sep string) []string { 190 return StrSlice(r.values[name], sep) 191 } 192 193 func StrSlice(value string, sep string) []string { 194 if len(value) == 0 { 195 return nil 196 } 197 return strings.Split(value, sep) 198 } 199 200 func (r RowWrapper) MustDecimal(name string) num.Decimal { 201 value, err := Decimal(r.mustColumn(name)) 202 panicW(name, err) 203 return value 204 } 205 206 func (r RowWrapper) Decimal(name string) num.Decimal { 207 value, err := Decimal(r.values[name]) 208 panicW(name, err) 209 return value 210 } 211 212 func (r RowWrapper) DecimalB(name string) (num.Decimal, bool) { 213 if !r.HasColumn(name) { 214 return num.DecimalZero(), false 215 } 216 return r.Decimal(name), true 217 } 218 219 func Decimal(rawValue string) (num.Decimal, error) { 220 return num.DecimalFromString(rawValue) 221 } 222 223 func (r RowWrapper) MustU64(name string) uint64 { 224 value, err := U64(r.mustColumn(name)) 225 panicW(name, err) 226 return value 227 } 228 229 func (r RowWrapper) MustInt(name string) *num.Int { 230 val, ok := num.IntFromString(r.MustStr(name), 10) 231 if ok { 232 panicW(name, fmt.Errorf("failed to parse int")) 233 } 234 return val 235 } 236 237 func (r RowWrapper) MustUint(name string) *num.Uint { 238 value, err := Uint(r.mustColumn(name)) 239 panicW(name, err) 240 return value 241 } 242 243 func (r RowWrapper) MaybeUint(name string) *num.Uint { 244 if !r.HasColumn(name) { 245 return nil 246 } 247 u := r.MustUint(name) 248 if u.IsZero() { 249 return nil 250 } 251 return u 252 } 253 254 func (r RowWrapper) MaybeU64(name string) *uint64 { 255 if !r.HasColumn(name) { 256 return nil 257 } 258 return ptr.From(r.MustU64(name)) 259 } 260 261 func (r RowWrapper) Uint(name string) *num.Uint { 262 value, err := Uint(r.values[name]) 263 panicW(name, err) 264 return value 265 } 266 267 func Uint(value string) (*num.Uint, error) { 268 retVal, overflow := num.UintFromString(value, 10) 269 if overflow { 270 return nil, fmt.Errorf("invalid uint value: %v", value) 271 } 272 return retVal, nil 273 } 274 275 // U64B does the same as U64, but returns a bool indicating whether or not the 276 // column was set. 277 func (r RowWrapper) U64B(name string) (uint64, bool) { 278 if !r.HasColumn(name) { 279 return 0, false 280 } 281 return r.U64(name), true 282 } 283 284 func (r RowWrapper) U64(name string) uint64 { 285 value, err := U64(r.values[name]) 286 panicW(name, err) 287 return value 288 } 289 290 func U64(value string) (uint64, error) { 291 return strconv.ParseUint(value, 10, 64) 292 } 293 294 func (r RowWrapper) MustU32(name string) uint32 { 295 return r.U32(name) 296 } 297 298 func (r RowWrapper) U32(name string) uint32 { 299 value, err := strconv.ParseUint(r.values[name], 10, 32) 300 panicW(name, err) 301 return uint32(value) 302 } 303 304 func (r RowWrapper) I32(name string) int32 { 305 value, err := strconv.ParseInt(r.values[name], 10, 32) 306 panicW(name, err) 307 return int32(value) 308 } 309 310 func (r RowWrapper) MustU64Slice(name, sep string) []uint64 { 311 value, err := U64Slice(r.mustColumn(name), sep) 312 panicW(name, err) 313 return value 314 } 315 316 func (r RowWrapper) U64Slice(name, sep string) []uint64 { 317 value, err := U64Slice(r.values[name], sep) 318 panicW(name, err) 319 return value 320 } 321 322 func U64Slice(rawValue, sep string) ([]uint64, error) { 323 if len(rawValue) == 0 { 324 return []uint64{}, nil 325 } 326 rawValues := strings.Split(rawValue, sep) 327 valuesCount := len(rawValues) 328 array := make([]uint64, 0, valuesCount) 329 for i := 0; i < valuesCount; i++ { 330 item, err := strconv.ParseUint(rawValues[i], 10, 0) 331 if err != nil { 332 return nil, err 333 } 334 array = append(array, item) 335 } 336 return array, nil 337 } 338 339 func (r RowWrapper) MustI64(name string) int64 { 340 value, err := I64(r.mustColumn(name)) 341 panicW(name, err) 342 return value 343 } 344 345 // I64B does the same as U64B, but returns a bool indicating whether or not the 346 // column was set. 347 func (r RowWrapper) I64B(name string) (int64, bool) { 348 if !r.HasColumn(name) { 349 return 0, false 350 } 351 return r.I64(name), true 352 } 353 354 func (r RowWrapper) I64(name string) int64 { 355 value, err := I64(r.values[name]) 356 panicW(name, err) 357 return value 358 } 359 360 func I64(rawValue string) (int64, error) { 361 return strconv.ParseInt(rawValue, 10, 0) 362 } 363 364 func (r RowWrapper) MustI64Slice(name, sep string) []int64 { 365 value, err := I64Slice(r.mustColumn(name), sep) 366 panicW(name, err) 367 return value 368 } 369 370 func (r RowWrapper) I64Slice(name, sep string) []int64 { 371 value, err := I64Slice(r.values[name], sep) 372 panicW(name, err) 373 return value 374 } 375 376 func I64Slice(rawValue string, sep string) ([]int64, error) { 377 if len(rawValue) == 0 { 378 return []int64{}, nil 379 } 380 rawValues := strings.Split(rawValue, sep) 381 valuesCount := len(rawValues) 382 array := make([]int64, 0, valuesCount) 383 for i := 0; i < valuesCount; i++ { 384 item, err := strconv.ParseInt(rawValues[i], 10, 0) 385 if err != nil { 386 return nil, err 387 } 388 array = append(array, item) 389 } 390 return array, nil 391 } 392 393 func (r RowWrapper) MustF64(name string) float64 { 394 value, err := F64(r.mustColumn(name)) 395 panicW(name, err) 396 return value 397 } 398 399 func (r RowWrapper) F64(name string) float64 { 400 value, err := F64(r.values[name]) 401 panicW(name, err) 402 return value 403 } 404 405 func F64(rawValue string) (float64, error) { 406 return strconv.ParseFloat(rawValue, 64) 407 } 408 409 func (r RowWrapper) MustF64Slice(name, sep string) []float64 { 410 value, err := F64Slice(r.mustColumn(name), sep) 411 panicW(name, err) 412 return value 413 } 414 415 func (r RowWrapper) F64Slice(name, sep string) []float64 { 416 value, err := F64Slice(r.values[name], sep) 417 panicW(name, err) 418 return value 419 } 420 421 func F64Slice(rawValue string, sep string) ([]float64, error) { 422 if len(rawValue) == 0 { 423 return nil, nil 424 } 425 rawValues := strings.Split(rawValue, sep) 426 valuesCount := len(rawValues) 427 array := make([]float64, 0, valuesCount) 428 for i := 0; i < valuesCount; i++ { 429 item, err := strconv.ParseFloat(rawValues[i], 64) 430 if err != nil { 431 return nil, err 432 } 433 array = append(array, item) 434 } 435 return array, nil 436 } 437 438 func (r RowWrapper) MustBool(name string) bool { 439 b, err := Bool(r.mustColumn(name)) 440 panicW(name, err) 441 return b 442 } 443 444 func (r RowWrapper) Bool(name string) bool { 445 v, ok := r.values[name] 446 if !ok { 447 return false 448 } 449 b, err := Bool(v) 450 panicW(name, err) 451 return b 452 } 453 454 func Bool(rawValue string) (bool, error) { 455 if rawValue == "true" { 456 return true, nil 457 } else if rawValue == "false" { 458 return false, nil 459 } 460 return false, fmt.Errorf("invalid bool value: %v", rawValue) 461 } 462 463 func (r RowWrapper) MustTime(name string) time.Time { 464 t, err := Time(r.mustColumn(name)) 465 panicW(name, err) 466 return t 467 } 468 469 func (r RowWrapper) Time(name string) time.Time { 470 t, err := Time(r.values[name]) 471 panicW(name, err) 472 return t 473 } 474 475 func Time(rawTime string) (time.Time, error) { 476 parsedTime, err := time.Parse("2006-01-02T15:04:05Z", rawTime) 477 if err != nil { 478 return parsedTime, fmt.Errorf("invalid date value: %v", err) 479 } 480 return parsedTime, nil 481 } 482 483 func (r RowWrapper) MustEventType(name string) events.Type { 484 eventType, err := EventType(r.MustStr(name)) 485 panicW(name, err) 486 return eventType 487 } 488 489 func EventType(rawValue string) (events.Type, error) { 490 ty, ok := events.TryFromString(rawValue) 491 if !ok { 492 return 0, fmt.Errorf("invalid event type: %v", rawValue) 493 } 494 return *ty, nil 495 } 496 497 func (r RowWrapper) LossType(name string) types.LossType { 498 lt, err := LossType(r.Str(name)) 499 if err != nil { 500 return types.LossTypeUnspecified 501 } 502 return lt 503 } 504 505 func (r RowWrapper) MustLossType(name string) types.LossType { 506 lt, err := LossType(r.MustStr(name)) 507 panicW(name, err) 508 return lt 509 } 510 511 func (r RowWrapper) MustOrderType(name string) types.OrderType { 512 orderType, err := OrderType(r.MustStr(name)) 513 panicW(name, err) 514 return orderType 515 } 516 517 func LossType(rawValue string) (types.LossType, error) { 518 lt, ok := eventspb.LossSocialization_Type_value[rawValue] 519 if !ok { 520 return types.LossType(lt), fmt.Errorf("invalid loss socialisation type: %v", rawValue) 521 } 522 return types.LossType(lt), nil 523 } 524 525 func OrderType(rawValue string) (types.OrderType, error) { 526 ty, ok := proto.Order_Type_value[rawValue] 527 if !ok { 528 return types.OrderType(ty), fmt.Errorf("invalid order type: %v", rawValue) 529 } 530 return types.OrderType(ty), nil 531 } 532 533 func (r RowWrapper) MustOrderStatus(name string) types.OrderStatus { 534 s, err := OrderStatus(r.MustStr(name)) 535 panicW(name, err) 536 return s 537 } 538 539 func (r RowWrapper) MustStopOrderStatus(name string) types.StopOrderStatus { 540 s, err := StopOrderStatus(r.MustStr(name)) 541 panicW(name, err) 542 return s 543 } 544 545 func OrderStatus(rawValue string) (types.OrderStatus, error) { 546 ty, ok := proto.Order_Status_value[rawValue] 547 if !ok { 548 return types.OrderStatus(ty), fmt.Errorf("invalid order status: %v", rawValue) 549 } 550 return types.OrderStatus(ty), nil 551 } 552 553 func StopOrderStatus(rawValue string) (types.StopOrderStatus, error) { 554 ty, ok := proto.StopOrder_Status_value[rawValue] 555 if !ok { 556 return types.StopOrderStatus(ty), fmt.Errorf("invalid stop order status: %v", rawValue) 557 } 558 return types.StopOrderStatus(ty), nil 559 } 560 561 func (r RowWrapper) MustPositionStatus(name string) proto.PositionStatus { 562 // account for empty values 563 if v := r.Str(name); len(v) == 0 { 564 return proto.PositionStatus_POSITION_STATUS_UNSPECIFIED 565 } 566 p, err := PositionStatus(r.MustStr(name)) 567 panicW(name, err) 568 return p 569 } 570 571 func PositionStatus(rawValue string) (proto.PositionStatus, error) { 572 ty, ok := proto.PositionStatus_value[rawValue] 573 if !ok { 574 return proto.PositionStatus(ty), fmt.Errorf("invalid position status: %v", rawValue) 575 } 576 return proto.PositionStatus(ty), nil 577 } 578 579 func (r RowWrapper) MustLiquidityStatus(name string) types.LiquidityProvisionStatus { 580 s, err := LiquidityStatus(r.MustStr(name)) 581 panicW(name, err) 582 return s 583 } 584 585 func LiquidityStatus(rawValue string) (types.LiquidityProvisionStatus, error) { 586 ty, ok := proto.LiquidityProvision_Status_value[rawValue] 587 if !ok { 588 return types.LiquidityProvisionStatus(ty), fmt.Errorf("invalid liquidity provision status: %v", rawValue) 589 } 590 return types.LiquidityProvisionStatus(ty), nil 591 } 592 593 func (r RowWrapper) MustTIF(name string) types.OrderTimeInForce { 594 tif, err := TIF(r.MustStr(name)) 595 panicW(name, err) 596 return tif 597 } 598 599 func (r RowWrapper) MustExpiryStrategy(name string) types.StopOrderExpiryStrategy { 600 expiryS, err := ExpiryStrategy(r.MustStr(name)) 601 panicW(name, err) 602 return expiryS 603 } 604 605 func TIF(rawValue string) (types.OrderTimeInForce, error) { 606 tif, ok := proto.Order_TimeInForce_value[strings.ReplaceAll(rawValue, "TIF_", "TIME_IN_FORCE_")] 607 if !ok { 608 return types.OrderTimeInForce(tif), fmt.Errorf("invalid time in force: %v", rawValue) 609 } 610 return types.OrderTimeInForce(tif), nil 611 } 612 613 func ExpiryStrategy(rawValue string) (types.StopOrderExpiryStrategy, error) { 614 es, ok := proto.StopOrder_ExpiryStrategy_value[rawValue] 615 if !ok { 616 return types.StopOrderExpiryStrategy(es), fmt.Errorf("invalid expiry strategy: %v", rawValue) 617 } 618 return types.StopOrderExpiryStrategy(es), nil 619 } 620 621 func (r RowWrapper) MustSide(name string) types.Side { 622 side, err := Side(r.MustStr(name)) 623 panicW(name, err) 624 return side 625 } 626 627 func Side(rawValue string) (types.Side, error) { 628 switch rawValue { 629 case "sell": 630 return types.SideSell, nil 631 case "buy": 632 return types.SideBuy, nil 633 default: 634 return types.SideUnspecified, errors.New("invalid side") 635 } 636 } 637 638 func (r RowWrapper) MustPeggedReference(name string) types.PeggedReference { 639 return peggedReference(r.MustStr(name)) 640 } 641 642 func peggedReference(rawValue string) types.PeggedReference { 643 switch rawValue { 644 case "MID": 645 return types.PeggedReferenceMid 646 case "ASK": 647 return types.PeggedReferenceBestAsk 648 case "BID": 649 return types.PeggedReferenceBestBid 650 } 651 return types.PeggedReferenceUnspecified 652 } 653 654 func (r RowWrapper) MustSizeOverrideSetting(name string) types.StopOrderSizeOverrideSetting { 655 return sizeOverrideSetting(r.MustStr(name)) 656 } 657 658 func sizeOverrideSetting(rawValue string) types.StopOrderSizeOverrideSetting { 659 switch rawValue { 660 case "NONE": 661 return types.StopOrderSizeOverrideSettingNone 662 case "POSITION": 663 return types.StopOrderSizeOverrideSettingPosition 664 } 665 return types.StopOrderSizeOverrideSettingUnspecified 666 } 667 668 func (r RowWrapper) MustOracleSpecPropertyType(name string) datav1.PropertyKey_Type { 669 ty, err := OracleSpecPropertyType(r.MustStr(name)) 670 panicW(name, err) 671 return ty 672 } 673 674 func OracleSpecPropertyType(name string) (datav1.PropertyKey_Type, error) { 675 ty, ok := datav1.PropertyKey_Type_value[name] 676 677 if !ok { 678 return datav1.PropertyKey_TYPE_UNSPECIFIED, fmt.Errorf("couldn't find %s as property type", name) 679 } 680 return datav1.PropertyKey_Type(ty), nil 681 } 682 683 func (r RowWrapper) MustOracleSpecConditionOperator(name string) datav1.Condition_Operator { 684 ty, err := OracleSpecConditionOperator(r.MustStr(name)) 685 panicW(name, err) 686 return ty 687 } 688 689 func OracleSpecConditionOperator(name string) (datav1.Condition_Operator, error) { 690 ty, ok := datav1.Condition_Operator_value[name] 691 692 if !ok { 693 return datav1.Condition_OPERATOR_UNSPECIFIED, fmt.Errorf("couldn't find %s as operator condition", name) 694 } 695 return datav1.Condition_Operator(ty), nil 696 } 697 698 func (r RowWrapper) MustAuctionTrigger(name string) types.AuctionTrigger { 699 at, err := AuctionTrigger(r.MustStr(name)) 700 panicW(name, err) 701 return at 702 } 703 704 func AuctionTrigger(name string) (types.AuctionTrigger, error) { 705 at, ok := proto.AuctionTrigger_value[name] 706 if !ok { 707 return types.AuctionTriggerUnspecified, fmt.Errorf("couldn't find %s as auction trigger", name) 708 } 709 return types.AuctionTrigger(at), nil 710 } 711 712 func (r RowWrapper) MustMarketUpdateState(name string) types.MarketStateUpdateType { 713 msu, err := MarketStateUpdate(r.MustStr(name)) 714 panicW(name, err) 715 return msu 716 } 717 718 func MarketStateUpdate(name string) (types.MarketStateUpdateType, error) { 719 msu, ok := proto.MarketStateUpdateType_value[name] 720 if !ok { 721 return types.MarketStateUpdateTypeUnspecified, fmt.Errorf("couldn't find %s as market state update type", name) 722 } 723 return types.MarketStateUpdateType(msu), nil 724 } 725 726 func (r RowWrapper) MustTradingMode(name string) types.MarketTradingMode { 727 ty, err := TradingMode(r.MustStr(name)) 728 panicW(name, err) 729 return ty 730 } 731 732 func (r RowWrapper) MarkPriceType() types.CompositePriceType { 733 if !r.HasColumn("price type") { 734 return types.CompositePriceTypeByLastTrade 735 } 736 if r.mustColumn("price type") == "last trade" { 737 return types.CompositePriceTypeByLastTrade 738 } else if r.mustColumn("price type") == "median" { 739 return types.CompositePriceTypeByMedian 740 } else if r.mustColumn("price type") == "weight" { 741 return types.CompositePriceTypeByWeight 742 } else { 743 panic("invalid price type") 744 } 745 } 746 747 func TradingMode(name string) (types.MarketTradingMode, error) { 748 ty, ok := proto.Market_TradingMode_value[name] 749 750 if !ok { 751 return types.MarketTradingModeUnspecified, fmt.Errorf("couldn't find %s as trading_mode", name) 752 } 753 return types.MarketTradingMode(ty), nil 754 } 755 756 func MarketState(name string) (types.MarketState, error) { 757 ty, ok := proto.Market_State_value[name] 758 759 if !ok { 760 return types.MarketStateUnspecified, fmt.Errorf("couldn't find %s as market state", name) 761 } 762 return types.MarketState(ty), nil 763 } 764 765 func (r RowWrapper) MustAccount(name string) types.AccountType { 766 acc, err := Account(r.MustStr(name)) 767 panicW(name, err) 768 return acc 769 } 770 771 func Account(name string) (types.AccountType, error) { 772 value := types.AccountType(proto.AccountType_value[name]) 773 774 if value == types.AccountTypeUnspecified { 775 return types.AccountTypeUnspecified, fmt.Errorf("invalid account type %s", name) 776 } 777 return value, nil 778 } 779 780 func AccountID(marketID, partyID, asset string, ty types.AccountType) string { 781 idBuf := make([]byte, 256) 782 783 if ty == types.AccountTypeGeneral || ty == types.AccountTypeFeesInfrastructure { 784 marketID = "" 785 } 786 787 if partyID == "market" { 788 partyID = "" 789 } 790 791 if len(marketID) == 0 { 792 marketID = "!" 793 } 794 795 if len(partyID) == 0 { 796 partyID = "*" 797 } 798 799 copy(idBuf, marketID) 800 ln := len(marketID) 801 copy(idBuf[ln:], partyID) 802 ln += len(partyID) 803 copy(idBuf[ln:], asset) 804 ln += len(asset) 805 idBuf[ln] = byte(ty + 48) 806 return string(idBuf[:ln+1]) 807 } 808 809 func (r RowWrapper) MustDuration(name string) time.Duration { 810 return time.Duration(r.MustI64(name)) 811 } 812 813 func (r RowWrapper) Duration(name string) time.Duration { 814 return time.Duration(r.I64(name)) 815 } 816 817 func (r RowWrapper) MustDurationStr(name string) time.Duration { 818 s := r.MustStr(name) 819 d, err := time.ParseDuration(s) 820 panicW(name, err) 821 return d 822 } 823 824 func (r RowWrapper) MustDurationSec(name string) time.Duration { 825 n := r.MustI64(name) 826 if n == 0 { 827 return 0 828 } 829 return time.Duration(n) * time.Second 830 } 831 832 func (r RowWrapper) MustDurationSec2(name string) time.Duration { 833 n := r.MustI64(name) 834 if n == 0 { 835 return 0 836 } 837 return time.Duration(n) * time.Second 838 } 839 840 func (r RowWrapper) DurationSec(name string) time.Duration { 841 n := r.I64(name) 842 if n == 0 { 843 return 0 844 } 845 return time.Duration(n) * time.Second 846 } 847 848 func (r RowWrapper) MustAMMCancelationMethod(name string) types.AMMCancellationMethod { 849 cancelMethod, err := AMMCancelMethod(r.MustStr(name)) 850 panicW(name, err) 851 return cancelMethod 852 } 853 854 func (r RowWrapper) MustAMMPoolStatus(name string) types.AMMPoolStatus { 855 ps, err := AMMPoolStatus(r.MustStr(name)) 856 panicW(name, err) 857 return ps 858 } 859 860 func (r RowWrapper) MustPoolStatusReason(name string) types.AMMStatusReason { 861 pr, err := AMMPoolStatusReason(r.MustStr(name)) 862 panicW(name, err) 863 return pr 864 } 865 866 func AMMCancelMethod(rawValue string) (types.AMMCancellationMethod, error) { 867 ty, ok := commandspb.CancelAMM_Method_value[rawValue] 868 if !ok { 869 return types.AMMCancellationMethod(ty), fmt.Errorf("invalid cancelation method: %v", rawValue) 870 } 871 return types.AMMCancellationMethod(ty), nil 872 } 873 874 func AMMPoolStatus(rawValue string) (types.AMMPoolStatus, error) { 875 ps, ok := eventspb.AMM_Status_value[rawValue] 876 if !ok { 877 return types.AMMPoolStatusUnspecified, fmt.Errorf("invalid AMM pool status: %s", rawValue) 878 } 879 return types.AMMPoolStatus(ps), nil 880 } 881 882 func AMMPoolStatusReason(rawValue string) (types.AMMStatusReason, error) { 883 pr, ok := eventspb.AMM_StatusReason_value[rawValue] 884 if !ok { 885 return types.AMMStatusReasonUnspecified, fmt.Errorf("invalid AMM pool status reason: %s", rawValue) 886 } 887 return types.AMMStatusReason(pr), nil 888 } 889 890 func panicW(field string, err error) { 891 if err != nil { 892 panic(fmt.Sprintf("couldn't parse %s: %v", field, err)) 893 } 894 } 895 896 func stringToU64(s string) uint64 { 897 i, _ := strconv.ParseUint(s, 10, 64) 898 return i 899 }