├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ └── golangci-lint.yml ├── .gitignore ├── LICENSE ├── README.md ├── bq ├── provider.go └── provider_test.go ├── cel2sql.go ├── cel2sql_test.go ├── go.mod ├── go.sum ├── sqltypes └── types.go └── test └── testdata.go /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gomod" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Set up Go 17 | uses: actions/setup-go@v2 18 | with: 19 | go-version: 1.16 20 | 21 | - name: Build 22 | run: go build -v ./... 23 | 24 | - name: Test 25 | run: go test -v ./... 26 | -------------------------------------------------------------------------------- /.github/workflows/golangci-lint.yml: -------------------------------------------------------------------------------- 1 | name: golangci-lint 2 | on: 3 | push: 4 | tags: 5 | - v* 6 | branches: 7 | - main 8 | pull_request: 9 | jobs: 10 | golangci: 11 | name: lint 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: golangci-lint 16 | uses: golangci/golangci-lint-action@v2 17 | with: 18 | version: latest 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cel2sql 2 | 3 | cel2sql converts [CEL (Common Expression Language)](https://opensource.google/projects/cel) to SQL condition. 4 | It is specifically targeting BigQuery standard SQL. 5 | 6 | ## Usage 7 | 8 | ```go 9 | import ( 10 | "context" 11 | "fmt" 12 | 13 | "cloud.google.com/go/bigquery" 14 | "github.com/cockscomb/cel2sql" 15 | "github.com/cockscomb/cel2sql/bq" 16 | "github.com/cockscomb/cel2sql/sqltypes" 17 | "github.com/google/cel-go/cel" 18 | "github.com/google/cel-go/checker/decls" 19 | ) 20 | 21 | // BigQuery table metadata 22 | var client *bigquery.Client = ... 23 | tableMetadata, _ := client.Dataset("your_dataset").Table("employees").Metadata(context.TODO()) 24 | 25 | // Prepare CEL environment 26 | env, _ := cel.NewEnv( 27 | cel.CustomTypeProvider(bq.NewTypeProvider(map[string]bigquery.Schema{ 28 | "Employee": tableMetadata.Schema, 29 | })), 30 | sqltypes.SQLTypeDeclarations, 31 | cel.Declarations( 32 | decls.NewVar("employee", decls.NewObjectType("Employee")), 33 | ), 34 | ) 35 | 36 | // Convert CEL to SQL 37 | ast, _ := env.Compile(`employee.name == "John Doe" && employee.hired_at >= current_timestamp() - duration("24h")`) 38 | sqlCondition, _ := cel2sql.Convert(ast) 39 | 40 | fmt.Println(sqlCondition) // `employee`.`name` = "John Doe" AND `employee`.`hired_at` >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 DAY) 41 | ``` 42 | 43 | ## Type Conversion 44 | 45 | CEL Type | BigQuery Standard SQL Data Type 46 | ----------- | ---------------------------------- 47 | `int` | `INT64` 48 | `uint` | Unsupported but treated as `INT64` 49 | `double` | `FLOAT64` 50 | `bool` | `BOOL` 51 | `string` | `STRING` 52 | `bytes` | `BYTES` 53 | `list` | `ARRAY` 54 | `map` | `STRUCT` 55 | `null_type` | `NULL` 56 | `timestamp` | `TIMESTAMP` 57 | `duration` | `INTERVAL` 58 | 59 | ## Supported CEL Operators/Functions 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 74 | 77 | 80 | 81 | 82 | 85 | 88 | 91 | 92 | 93 | 96 | 99 | 100 | 101 | 104 | 107 | 110 | 111 | 112 | 115 | 118 | 119 | 120 | 123 | 126 | 127 | 128 | 131 | 134 | 137 | 138 | 139 | 142 | 145 | 148 | 149 | 150 | 153 | 156 | 159 | 160 | 161 | 164 | 167 | 168 | 169 | 172 | 175 | 178 | 179 | 180 | 183 | 186 | 187 | 188 | 191 | 194 | 195 | 196 | 199 | 202 | 203 | 204 | 207 | 210 | 211 | 212 | 215 | 218 | 219 | 220 | 223 | 226 | 227 | 228 | 231 | 234 | 237 | 238 | 239 | 242 | 245 | 246 | 247 | 250 | 253 | 254 | 255 | 258 | 261 | 264 | 265 | 266 | 269 | 272 | 273 | 274 | 277 | 280 | 283 | 284 | 285 | 288 | 291 | 292 | 293 | 296 | 299 | 300 | 301 | 304 | 307 | 308 | 309 | 312 | 315 | 316 | 317 | 320 | 323 | 324 | 325 | 328 | 331 | 334 | 335 | 336 | 339 | 342 | 343 | 344 | 347 | 350 | 351 | 352 | 355 | 358 | 359 | 360 | 363 | 366 | 367 | 368 | 371 | 374 | 375 | 376 | 379 | 382 | 385 | 386 | 387 | 390 | 393 | 394 | 395 | 398 | 401 | 402 | 403 | 406 | 409 | 412 | 413 | 414 | 417 | 420 | 421 | 422 | 425 | 428 | 429 | 430 | 433 | 436 | 437 | 438 | 441 | 444 | 445 | 446 | 449 | 452 | 453 | 454 | 457 | 460 | 463 | 464 | 465 | 468 | 471 | 472 | 473 | 476 | 479 | 480 | 481 | 484 | 487 | 488 | 489 | 492 | 495 | 496 | 497 | 500 | 503 | 504 | 505 | 508 | 511 | 514 | 515 | 516 | 519 | 522 | 525 | 526 | 527 | 530 | 533 | 534 | 535 | 538 | 541 | 544 | 545 | 546 | 549 | 552 | 555 | 556 | 557 | 560 | 563 | 566 | 567 | 568 | 571 | 574 | 575 | 576 | 579 | 582 | 585 | 586 | 587 | 590 | 593 | 596 | 597 | 598 | 601 | 604 | 607 | 608 | 609 | 612 | 615 | 616 | 617 | 620 | 623 | 626 | 627 | 628 | 631 | 634 | 637 | 638 | 639 | 642 | 645 | 648 | 649 | 650 | 653 | 656 | 657 | 658 | 661 | 664 | 667 | 668 | 669 | 672 | 675 | 676 | 677 | 680 | 683 | 686 | 687 | 688 | 691 | 694 | 695 | 696 | 699 | 702 | 705 | 706 | 707 | 710 | 713 | 714 | 715 | 718 | 721 | 724 | 725 | 726 | 729 | 732 | 733 | 734 | 737 | 740 | 743 | 744 | 745 | 748 | 751 | 752 | 753 | 756 | 759 | 762 | 763 | 764 | 767 | 770 | 771 | 772 | 775 | 778 | 781 | 782 | 783 | 786 | 789 | 790 | 791 | 794 | 797 | 800 | 801 | 802 | 805 | 808 | 809 | 810 | 813 | 816 | 819 | 820 | 821 | 824 | 827 | 828 | 829 | 832 | 835 | 838 | 839 | 840 | 843 | 846 | 847 | 848 | 851 | 854 | 855 | 856 | 859 | 862 | 863 | 864 | 867 | 870 | 873 | 874 | 875 | 878 | 881 | 884 | 885 | 886 | 889 | 892 | 893 | 894 | 897 | 900 | 901 | 902 | 905 | 908 | 911 | 912 | 913 | 916 | 919 | 922 | 923 | 924 | 927 | 930 | 931 | 932 | 935 | 938 | 939 | 940 | 943 | 946 | 947 | 948 | 951 | 954 | 955 | 956 | 959 | 962 | 965 | 966 |
SymbolTypeSQL
72 | !_ 73 | 75 | (bool) -> bool 76 | 78 | NOT bool 79 |
83 | -_ 84 | 86 | (int) -> int 87 | 89 | -int 90 |
94 | (double) -> double 95 | 97 | -double 98 |
102 | _!=_ 103 | 105 | (A, A) -> bool 106 | 108 | A != A 109 |
113 | (bool, bool) -> bool 114 | 116 | bool IS NOT bool 117 |
121 | (A, null) -> bool 122 | 124 | A IS NOT NULL 125 |
129 | _%_ 130 | 132 | (int, int) -> int 133 | 135 | MOD(int, int) 136 |
140 | _&&_ 141 | 143 | (bool, bool) -> bool 144 | 146 | bool AND bool 147 |
151 | _*_ 152 | 154 | (int, int) -> int 155 | 157 | int * int 158 |
162 | (double, double) -> double 163 | 165 | double * double 166 |
170 | _+_ 171 | 173 | (int, int) -> int 174 | 176 | int + int 177 |
181 | (double, double) -> double 182 | 184 | double + double 185 |
189 | (string, string) -> string 190 | 192 | string || string 193 |
197 | (bytes, bytes) -> bytes 198 | 200 | bytes || bytes 201 |
205 | (list(A), list(A)) -> list(A) 206 | 208 | list(A) || list(A) 209 |
213 | (google.protobuf.Timestamp, google.protobuf.Duration) -> google.protobuf.Timestamp 214 | 216 | TIMESTAMP_ADD(timestamp, INTERVAL duration date_part) 217 |
221 | (google.protobuf.Duration, google.protobuf.Timestamp) -> google.protobuf.Timestamp 222 | 224 | TIMESTAMP_ADD(timestamp, INTERVAL duration date_part) 225 |
229 | _-_ 230 | 232 | (int, int) -> int 233 | 235 | int - int 236 |
240 | (double, double) -> double 241 | 243 | double - double 244 |
248 | (google.protobuf.Timestamp, google.protobuf.Duration) -> google.protobuf.Timestamp 249 | 251 | TIMESTAMP_SUB(timestamp, INTERVAL duration date_part) 252 |
256 | _/_ 257 | 259 | (int, int) -> int 260 | 262 | int / int 263 |
267 | (double, double) -> double 268 | 270 | double / double 271 |
275 | _<=_ 276 | 278 | (bool, bool) -> bool 279 | 281 | bool <= bool 282 |
286 | (int, int) -> bool 287 | 289 | int <= int 290 |
294 | (double, double) -> bool 295 | 297 | double <= double 298 |
302 | (string, string) -> bool 303 | 305 | string <= string 306 |
310 | (bytes, bytes) -> bool 311 | 313 | bytes <= bytes 314 |
318 | (google.protobuf.Timestamp, google.protobuf.Timestamp) -> bool 319 | 321 | timestamp <= timestamp 322 |
326 | _<_ 327 | 329 | (bool, bool) -> bool 330 | 332 | bool < bool 333 |
337 | (int, int) -> bool 338 | 340 | int < int 341 |
345 | (double, double) -> bool 346 | 348 | double < double 349 |
353 | (string, string) -> bool 354 | 356 | string < string 357 |
361 | (bytes, bytes) -> bool 362 | 364 | bytes < bytes 365 |
369 | (google.protobuf.Timestamp, google.protobuf.Timestamp) -> bool 370 | 372 | timestamp < timestamp 373 |
377 | _==_ 378 | 380 | (A, A) -> bool 381 | 383 | A = A 384 |
388 | (bool, bool) -> bool 389 | 391 | A IS A 392 |
396 | (A, null) -> bool 397 | 399 | A IS NULL 400 |
404 | _>=_ 405 | 407 | (bool, bool) -> bool 408 | 410 | bool >= bool 411 |
415 | (int, int) -> bool 416 | 418 | int >= int 419 |
423 | (double, double) -> bool 424 | 426 | double >= double 427 |
431 | (string, string) -> bool 432 | 434 | string >= string 435 |
439 | (bytes, bytes) -> bool 440 | 442 | bytes >= bytes 443 |
447 | (google.protobuf.Timestamp, google.protobuf.Timestamp) -> bool 448 | 450 | timestamp >= timestamp 451 |
455 | _>_ 456 | 458 | (bool, bool) -> bool 459 | 461 | bool > bool 462 |
466 | (int, int) -> bool 467 | 469 | int > int 470 |
474 | (double, double) -> bool 475 | 477 | double > double 478 |
482 | (string, string) -> bool 483 | 485 | string > string 486 |
490 | (bytes, bytes) -> bool 491 | 493 | bytes > bytes 494 |
498 | (google.protobuf.Timestamp, google.protobuf.Timestamp) -> bool 499 | 501 | timestamp > timestamp 502 |
506 | _?_:_ 507 | 509 | (bool, A, A) -> A 510 | 512 | IF(bool, A, A) 513 |
517 | _[_] 518 | 520 | (list(A), int) -> A 521 | 523 | list[OFFSET(int)] 524 |
528 | (map(A, B), A) -> B 529 | 531 | map.`A` 532 |
536 | in 537 | 539 | (A, list(A)) -> bool 540 | 542 | A IN UNNEST(list) 543 |
547 | _||_ 548 | 550 | (bool, bool) -> bool 551 | 553 | bool OR bool 554 |
558 | bool 559 | 561 | (int) -> bool 562 | 564 | CAST(int AS BOOL) 565 |
569 | (string) -> bool 570 | 572 | CAST(string AS BOOL) 573 |
577 | bytes 578 | 580 | (string) -> bytes 581 | 583 | CAST(stringAS BYTES) 584 |
588 | contains 589 | 591 | string.(string) -> bool 592 | 594 | INSTR(string, string) != 0 595 |
599 | double 600 | 602 | (int) -> double 603 | 605 | CAST(int AS FLOAT64) 606 |
610 | (string) -> double 611 | 613 | CAST(string AS FLOAT64) 614 |
618 | duration 619 | 621 | (string) -> google.protobuf.Duration 622 | 624 | INTERVAL duration date_part 625 |
629 | endsWith 630 | 632 | string.(string) -> bool 633 | 635 | ENDS_WITH(string, string) 636 |
640 | getDate 641 | 643 | google.protobuf.Timestamp.() -> int 644 | 646 | EXTRACT(DAY FROM timestamp) 647 |
651 | google.protobuf.Timestamp.(string) -> int 652 | 654 | EXTRACT(DAY FROM timestamp AT string) 655 |
659 | getDayOfMonth 660 | 662 | google.protobuf.Timestamp.() -> int 663 | 665 | EXTRACT(DAY FROM timestamp) - 1 666 |
670 | google.protobuf.Timestamp.(string) -> int 671 | 673 | EXTRACT(DAY FROM timestamp AT string) - 1 674 |
678 | getDayOfWeek 679 | 681 | google.protobuf.Timestamp.() -> int 682 | 684 | EXTRACT(DAYOFWEEK FROM timestamp) - 1 685 |
689 | google.protobuf.Timestamp.(string) -> int 690 | 692 | EXTRACT(DAYOFWEEK FROM timestamp AT string) - 1 693 |
697 | getDayOfYear 698 | 700 | google.protobuf.Timestamp.() -> int 701 | 703 | EXTRACT(DAYOFYEAR FROM timestamp) - 1 704 |
708 | google.protobuf.Timestamp.(string) -> int 709 | 711 | EXTRACT(DAYOFYEAR FROM timestamp AT string) - 1 712 |
716 | getFullYear 717 | 719 | google.protobuf.Timestamp.() -> int 720 | 722 | EXTRACT(YEAR FROM timestamp) 723 |
727 | google.protobuf.Timestamp.(string) -> int 728 | 730 | EXTRACT(YEAR FROM timestamp AT string) 731 |
735 | getHours 736 | 738 | google.protobuf.Timestamp.() -> int 739 | 741 | EXTRACT(HOUR FROM timestamp) 742 |
746 | google.protobuf.Timestamp.(string) -> int 747 | 749 | EXTRACT(HOUR FROM timestamp AT string) 750 |
754 | getMilliseconds 755 | 757 | google.protobuf.Timestamp.() -> int 758 | 760 | EXTRACT(MILLISECOND FROM timestamp) 761 |
765 | google.protobuf.Timestamp.(string) -> int 766 | 768 | EXTRACT(MILLISECOND FROM timestamp AT string) 769 |
773 | getMinutes 774 | 776 | google.protobuf.Timestamp.() -> int 777 | 779 | EXTRACT(MINUTE FROM timestamp) 780 |
784 | google.protobuf.Timestamp.(string) -> int 785 | 787 | EXTRACT(MINUTE FROM timestamp AT string) 788 |
792 | getMonth 793 | 795 | google.protobuf.Timestamp.() -> int 796 | 798 | EXTRACT(MONTH FROM timestamp) - 1 799 |
803 | google.protobuf.Timestamp.(string) -> int 804 | 806 | EXTRACT(MONTH FROM timestamp AT string) - 1 807 |
811 | getSeconds 812 | 814 | google.protobuf.Timestamp.() -> int 815 | 817 | EXTRACT(SECOND FROM timestamp) 818 |
822 | google.protobuf.Timestamp.(string) -> int 823 | 825 | EXTRACT(SECOND FROM timestamp AT string) 826 |
830 | int 831 | 833 | (bool) -> int 834 | 836 | CAST(bool AS INT64) 837 |
841 | (double) -> int 842 | 844 | CAST(double AS INT64) 845 |
849 | (string) -> int 850 | 852 | CAST(string AS INT64) 853 |
857 | (google.protobuf.Timestamp) -> int 858 | 860 | UNIX_SECONDS(timestamp) 861 |
865 | matches 866 | 868 | string.(string) -> bool 869 | 871 | REGEXP_CONTAINS(string, string) 872 |
876 | size 877 | 879 | (string) -> int 880 | 882 | CHAR_LENGTH(string) 883 |
887 | (bytes) -> int 888 | 890 | BYTE_LENGTH(bytes) 891 |
895 | (list(A)) -> int 896 | 898 | ARRAY_LENGTH(list) 899 |
903 | startsWith 904 | 906 | string.(string) -> bool 907 | 909 | STARTS_WITHstring, string) 910 |
914 | string 915 | 917 | (bool) -> string 918 | 920 | CAST(bool AS STRING) 921 |
925 | (int) -> string 926 | 928 | CAST(int AS STRING) 929 |
933 | (double) -> string 934 | 936 | CAST(double AS STRING) 937 |
941 | (bytes) -> string 942 | 944 | CAST(bytes AS STRING) 945 |
949 | (timestamp) -> string 950 | 952 | CAST(timestamp AS STRING) 953 |
957 | timestamp 958 | 960 | (string) -> google.protobuf.Timestamp 961 | 963 | TIMESTAMP(string) 964 |
967 | 968 | ## Standard SQL Types/Functions 969 | 970 | cel2sql supports time related types bellow. 971 | 972 | - `DATE` 973 | - `TIME` 974 | - `DATETIME` 975 | 976 | cel2sql contains time related functions bellow. 977 | 978 | - `current_date()` 979 | - `current_time()` 980 | - `current_datetime()` 981 | - `current_timestamp()` 982 | - `interval(N, date_part)` 983 | -------------------------------------------------------------------------------- /bq/provider.go: -------------------------------------------------------------------------------- 1 | package bq 2 | 3 | import ( 4 | "strings" 5 | 6 | "cloud.google.com/go/bigquery" 7 | "github.com/google/cel-go/checker/decls" 8 | "github.com/google/cel-go/common/types" 9 | "github.com/google/cel-go/common/types/ref" 10 | exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" 11 | 12 | "github.com/cockscomb/cel2sql/sqltypes" 13 | ) 14 | 15 | type typeProvider struct { 16 | schemas map[string]bigquery.Schema 17 | } 18 | 19 | func NewTypeProvider(schemas map[string]bigquery.Schema) *typeProvider { 20 | return &typeProvider{schemas: schemas} 21 | } 22 | 23 | func (p *typeProvider) EnumValue(enumName string) ref.Val { 24 | return types.NewErr("unknown enum name '%s'", enumName) 25 | } 26 | 27 | func (p *typeProvider) FindIdent(identName string) (ref.Val, bool) { 28 | return nil, false 29 | } 30 | 31 | func (p *typeProvider) findSchema(typeName string) (bigquery.Schema, bool) { 32 | typeNames := strings.Split(typeName, ".") 33 | schema, found := p.schemas[typeNames[0]] 34 | if !found { 35 | return nil, false 36 | } 37 | for _, tn := range typeNames[1:] { 38 | var s *bigquery.Schema 39 | for _, fieldSchema := range schema { 40 | if fieldSchema.Name == tn { 41 | s = &fieldSchema.Schema 42 | break 43 | } 44 | } 45 | if s == nil { 46 | return nil, false 47 | } 48 | schema = *s 49 | } 50 | return schema, true 51 | } 52 | 53 | func (p *typeProvider) FindType(typeName string) (*exprpb.Type, bool) { 54 | _, found := p.findSchema(typeName) 55 | if !found { 56 | return nil, false 57 | } 58 | return decls.NewTypeType(decls.NewObjectType(typeName)), true 59 | } 60 | 61 | func (p *typeProvider) FindFieldType(messageType string, fieldName string) (*ref.FieldType, bool) { 62 | schema, found := p.findSchema(messageType) 63 | if !found { 64 | return nil, false 65 | } 66 | var field *bigquery.FieldSchema 67 | for _, fieldSchema := range schema { 68 | if fieldSchema.Name == fieldName { 69 | field = fieldSchema 70 | break 71 | } 72 | } 73 | if field == nil { 74 | return nil, false 75 | } 76 | var typ *exprpb.Type 77 | switch field.Type { 78 | case bigquery.StringFieldType: 79 | typ = decls.String 80 | case bigquery.BytesFieldType: 81 | typ = decls.Bytes 82 | case bigquery.BooleanFieldType: 83 | typ = decls.Bool 84 | case bigquery.IntegerFieldType: 85 | typ = decls.Int 86 | case bigquery.FloatFieldType: 87 | typ = decls.Double 88 | case bigquery.TimestampFieldType: 89 | typ = decls.Timestamp 90 | case bigquery.RecordFieldType: 91 | typ = decls.NewObjectType(strings.Join([]string{messageType, fieldName}, ".")) 92 | case bigquery.DateFieldType: 93 | typ = sqltypes.Date 94 | case bigquery.TimeFieldType: 95 | typ = sqltypes.Time 96 | case bigquery.DateTimeFieldType: 97 | typ = sqltypes.DateTime 98 | } 99 | if field.Repeated { 100 | typ = decls.NewListType(typ) 101 | } 102 | return &ref.FieldType{ 103 | Type: typ, 104 | }, true 105 | } 106 | 107 | func (p *typeProvider) NewValue(typeName string, fields map[string]ref.Val) ref.Val { 108 | return types.NewErr("unknown type '%s'", typeName) 109 | } 110 | 111 | var _ ref.TypeProvider = new(typeProvider) 112 | -------------------------------------------------------------------------------- /bq/provider_test.go: -------------------------------------------------------------------------------- 1 | package bq_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "cloud.google.com/go/bigquery" 7 | "github.com/google/cel-go/checker/decls" 8 | "github.com/google/cel-go/common/types/ref" 9 | "github.com/stretchr/testify/assert" 10 | exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" 11 | 12 | "github.com/cockscomb/cel2sql/bq" 13 | "github.com/cockscomb/cel2sql/test" 14 | ) 15 | 16 | func Test_typeProvider_FindType(t *testing.T) { 17 | typeProvider := bq.NewTypeProvider(map[string]bigquery.Schema{ 18 | "trigrams": test.NewTrigramsTableMetadata().Schema, 19 | "wikipedia": test.NewWikipediaTableMetadata().Schema, 20 | }) 21 | 22 | type args struct { 23 | typeName string 24 | } 25 | tests := []struct { 26 | name string 27 | args args 28 | want *exprpb.Type 29 | wantFound bool 30 | }{ 31 | { 32 | name: "trigrams", 33 | args: args{typeName: "trigrams"}, 34 | want: &exprpb.Type{ 35 | TypeKind: &exprpb.Type_Type{ 36 | Type: &exprpb.Type{ 37 | TypeKind: &exprpb.Type_MessageType{ 38 | MessageType: "trigrams", 39 | }, 40 | }, 41 | }, 42 | }, 43 | wantFound: true, 44 | }, 45 | { 46 | name: "trigrams.cell", 47 | args: args{typeName: "trigrams.cell"}, 48 | want: &exprpb.Type{ 49 | TypeKind: &exprpb.Type_Type{ 50 | Type: &exprpb.Type{ 51 | TypeKind: &exprpb.Type_MessageType{ 52 | MessageType: "trigrams.cell", 53 | }, 54 | }, 55 | }, 56 | }, 57 | wantFound: true, 58 | }, 59 | { 60 | name: "trigrams.cell.value", 61 | args: args{typeName: "trigrams.cell.value"}, 62 | want: &exprpb.Type{ 63 | TypeKind: &exprpb.Type_Type{ 64 | Type: &exprpb.Type{ 65 | TypeKind: &exprpb.Type_MessageType{ 66 | MessageType: "trigrams.cell.value", 67 | }, 68 | }, 69 | }, 70 | }, 71 | wantFound: true, 72 | }, 73 | { 74 | name: "not_exists", 75 | args: args{typeName: "not_exists"}, 76 | want: nil, 77 | wantFound: false, 78 | }, 79 | { 80 | name: "not_exists", 81 | args: args{typeName: "trigrams.cell.not_exists"}, 82 | want: nil, 83 | wantFound: false, 84 | }, 85 | } 86 | for _, tt := range tests { 87 | t.Run(tt.name, func(t *testing.T) { 88 | got, gotFound := typeProvider.FindType(tt.args.typeName) 89 | if assert.Equal(t, tt.wantFound, gotFound) { 90 | assert.Equal(t, tt.want, got) 91 | } 92 | }) 93 | } 94 | } 95 | 96 | func Test_typeProvider_FindFieldType(t *testing.T) { 97 | typeProvider := bq.NewTypeProvider(map[string]bigquery.Schema{ 98 | "trigrams": test.NewTrigramsTableMetadata().Schema, 99 | "wikipedia": test.NewWikipediaTableMetadata().Schema, 100 | }) 101 | 102 | type args struct { 103 | messageType string 104 | fieldName string 105 | } 106 | tests := []struct { 107 | name string 108 | args args 109 | want *ref.FieldType 110 | wantFound bool 111 | }{ 112 | { 113 | name: "wikipedia.title", 114 | args: args{ 115 | messageType: "wikipedia", 116 | fieldName: "title", 117 | }, 118 | want: &ref.FieldType{ 119 | Type: decls.String, 120 | }, 121 | wantFound: true, 122 | }, 123 | { 124 | name: "wikipedia.id", 125 | args: args{ 126 | messageType: "wikipedia", 127 | fieldName: "id", 128 | }, 129 | want: &ref.FieldType{ 130 | Type: decls.Int, 131 | }, 132 | wantFound: true, 133 | }, 134 | { 135 | name: "wikipedia.is_redirect", 136 | args: args{ 137 | messageType: "wikipedia", 138 | fieldName: "is_redirect", 139 | }, 140 | want: &ref.FieldType{ 141 | Type: decls.Bool, 142 | }, 143 | wantFound: true, 144 | }, 145 | { 146 | name: "trigrams.cell", 147 | args: args{ 148 | messageType: "trigrams", 149 | fieldName: "cell", 150 | }, 151 | want: &ref.FieldType{ 152 | Type: decls.NewListType(decls.NewObjectType("trigrams.cell")), 153 | }, 154 | wantFound: true, 155 | }, 156 | { 157 | name: "trigrams.cell", 158 | args: args{ 159 | messageType: "trigrams.cell", 160 | fieldName: "value", 161 | }, 162 | want: &ref.FieldType{ 163 | Type: decls.NewListType(decls.String), 164 | }, 165 | wantFound: true, 166 | }, 167 | { 168 | name: "trigrams.cell.sample", 169 | args: args{ 170 | messageType: "trigrams.cell", 171 | fieldName: "sample", 172 | }, 173 | want: &ref.FieldType{ 174 | Type: decls.NewListType(decls.NewObjectType("trigrams.cell.sample")), 175 | }, 176 | wantFound: true, 177 | }, 178 | { 179 | name: "trigrams.cell.sample.id", 180 | args: args{ 181 | messageType: "trigrams.cell.sample", 182 | fieldName: "id", 183 | }, 184 | want: &ref.FieldType{ 185 | Type: decls.String, 186 | }, 187 | wantFound: true, 188 | }, 189 | { 190 | name: "not_exists_message", 191 | args: args{ 192 | messageType: "not_exists", 193 | fieldName: "", 194 | }, 195 | want: nil, 196 | wantFound: false, 197 | }, 198 | { 199 | name: "not_exists_field", 200 | args: args{ 201 | messageType: "wikipedia", 202 | fieldName: "not_exists", 203 | }, 204 | want: nil, 205 | wantFound: false, 206 | }, 207 | } 208 | for _, tt := range tests { 209 | t.Run(tt.name, func(t *testing.T) { 210 | got, gotFound := typeProvider.FindFieldType(tt.args.messageType, tt.args.fieldName) 211 | if assert.Equal(t, tt.wantFound, gotFound) { 212 | assert.Equal(t, tt.want, got) 213 | } 214 | }) 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /cel2sql.go: -------------------------------------------------------------------------------- 1 | package cel2sql 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | "strconv" 7 | "strings" 8 | "time" 9 | 10 | "github.com/google/cel-go/cel" 11 | "github.com/google/cel-go/common/operators" 12 | "github.com/google/cel-go/common/overloads" 13 | exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" 14 | ) 15 | 16 | // Implementations based on `google/cel-go`'s unparser 17 | // https://github.com/google/cel-go/blob/master/parser/unparser.go 18 | 19 | func Convert(ast *cel.Ast) (string, error) { 20 | checkedExpr, err := cel.AstToCheckedExpr(ast) 21 | if err != nil { 22 | return "", err 23 | } 24 | un := &converter{ 25 | typeMap: checkedExpr.TypeMap, 26 | } 27 | if err := un.visit(checkedExpr.Expr); err != nil { 28 | return "", err 29 | } 30 | return un.str.String(), nil 31 | } 32 | 33 | type converter struct { 34 | str strings.Builder 35 | typeMap map[int64]*exprpb.Type 36 | } 37 | 38 | func (con *converter) visit(expr *exprpb.Expr) error { 39 | switch expr.ExprKind.(type) { 40 | case *exprpb.Expr_CallExpr: 41 | return con.visitCall(expr) 42 | // TODO: Comprehensions are currently not supported. 43 | case *exprpb.Expr_ComprehensionExpr: 44 | return con.visitComprehension(expr) 45 | case *exprpb.Expr_ConstExpr: 46 | return con.visitConst(expr) 47 | case *exprpb.Expr_IdentExpr: 48 | return con.visitIdent(expr) 49 | case *exprpb.Expr_ListExpr: 50 | return con.visitList(expr) 51 | case *exprpb.Expr_SelectExpr: 52 | return con.visitSelect(expr) 53 | case *exprpb.Expr_StructExpr: 54 | return con.visitStruct(expr) 55 | } 56 | return fmt.Errorf("unsupported expr: %v", expr) 57 | } 58 | 59 | func (con *converter) visitCall(expr *exprpb.Expr) error { 60 | c := expr.GetCallExpr() 61 | fun := c.GetFunction() 62 | switch fun { 63 | // ternary operator 64 | case operators.Conditional: 65 | return con.visitCallConditional(expr) 66 | // index operator 67 | case operators.Index: 68 | return con.visitCallIndex(expr) 69 | // unary operators 70 | case operators.LogicalNot, operators.Negate: 71 | return con.visitCallUnary(expr) 72 | // binary operators 73 | case operators.Add, 74 | operators.Divide, 75 | operators.Equals, 76 | operators.Greater, 77 | operators.GreaterEquals, 78 | operators.In, 79 | operators.Less, 80 | operators.LessEquals, 81 | operators.LogicalAnd, 82 | operators.LogicalOr, 83 | operators.Multiply, 84 | operators.NotEquals, 85 | operators.OldIn, 86 | operators.Subtract: 87 | return con.visitCallBinary(expr) 88 | // standard function calls. 89 | default: 90 | return con.visitCallFunc(expr) 91 | } 92 | } 93 | 94 | var standardSQLBinaryOperators = map[string]string{ 95 | operators.LogicalAnd: "AND", 96 | operators.LogicalOr: "OR", 97 | operators.Equals: "=", 98 | operators.In: "IN", 99 | } 100 | 101 | func (con *converter) visitCallBinary(expr *exprpb.Expr) error { 102 | c := expr.GetCallExpr() 103 | fun := c.GetFunction() 104 | args := c.GetArgs() 105 | lhs := args[0] 106 | // add parens if the current operator is lower precedence than the lhs expr operator. 107 | lhsParen := isComplexOperatorWithRespectTo(fun, lhs) 108 | rhs := args[1] 109 | // add parens if the current operator is lower precedence than the rhs expr operator, 110 | // or the same precedence and the operator is left recursive. 111 | rhsParen := isComplexOperatorWithRespectTo(fun, rhs) 112 | lhsType := con.getType(lhs) 113 | rhsType := con.getType(rhs) 114 | if (isTimestampRelatedType(lhsType) && isDurationRelatedType(rhsType)) || 115 | (isTimestampRelatedType(rhsType) && isDurationRelatedType(lhsType)) { 116 | return con.callTimestampOperation(fun, lhs, rhs) 117 | } 118 | if !rhsParen && isLeftRecursive(fun) { 119 | rhsParen = isSamePrecedence(fun, rhs) 120 | } 121 | if err := con.visitMaybeNested(lhs, lhsParen); err != nil { 122 | return err 123 | } 124 | var operator string 125 | if fun == operators.Add && (lhsType.GetPrimitive() == exprpb.Type_STRING && rhsType.GetPrimitive() == exprpb.Type_STRING) { 126 | operator = "||" 127 | } else if fun == operators.Add && (rhsType.GetPrimitive() == exprpb.Type_BYTES && lhsType.GetPrimitive() == exprpb.Type_BYTES) { 128 | operator = "||" 129 | } else if fun == operators.Add && (isListType(lhsType) && isListType(rhsType)) { 130 | operator = "||" 131 | } else if fun == operators.Equals && (isNullLiteral(rhs) || isBoolLiteral(rhs)) { 132 | operator = "IS" 133 | } else if fun == operators.NotEquals && (isNullLiteral(rhs) || isBoolLiteral(rhs)) { 134 | operator = "IS NOT" 135 | } else if op, found := standardSQLBinaryOperators[fun]; found { 136 | operator = op 137 | } else if op, found := operators.FindReverseBinaryOperator(fun); found { 138 | operator = op 139 | } else { 140 | return fmt.Errorf("cannot unmangle operator: %s", fun) 141 | } 142 | con.str.WriteString(" ") 143 | con.str.WriteString(operator) 144 | con.str.WriteString(" ") 145 | if fun == operators.In && isListType(rhsType) { 146 | con.str.WriteString("UNNEST(") 147 | } 148 | if err := con.visitMaybeNested(rhs, rhsParen); err != nil { 149 | return err 150 | } 151 | if fun == operators.In && isListType(rhsType) { 152 | con.str.WriteString(")") 153 | } 154 | return nil 155 | } 156 | 157 | func isTimestampRelatedType(typ *exprpb.Type) bool { 158 | abstractType := typ.GetAbstractType() 159 | if abstractType != nil { 160 | name := abstractType.GetName() 161 | return name == "DATE" || name == "TIME" || name == "DATETIME" 162 | } 163 | return typ.GetWellKnown() == exprpb.Type_TIMESTAMP 164 | } 165 | 166 | func isDateType(typ *exprpb.Type) bool { 167 | return typ.GetAbstractType() != nil && typ.GetAbstractType().GetName() == "DATE" 168 | } 169 | 170 | func isTimeType(typ *exprpb.Type) bool { 171 | return typ.GetAbstractType() != nil && typ.GetAbstractType().GetName() == "TIME" 172 | } 173 | 174 | func isDateTimeType(typ *exprpb.Type) bool { 175 | return typ.GetAbstractType() != nil && typ.GetAbstractType().GetName() == "DATETIME" 176 | } 177 | 178 | func isTimestampType(typ *exprpb.Type) bool { 179 | return typ.GetWellKnown() == exprpb.Type_TIMESTAMP 180 | } 181 | 182 | func isDurationRelatedType(typ *exprpb.Type) bool { 183 | abstractType := typ.GetAbstractType() 184 | if abstractType != nil { 185 | name := abstractType.GetName() 186 | return name == "INTERVAL" 187 | } 188 | return typ.GetWellKnown() == exprpb.Type_DURATION 189 | } 190 | 191 | func (con *converter) callTimestampOperation(fun string, lhs *exprpb.Expr, rhs *exprpb.Expr) error { 192 | lhsParen := isComplexOperatorWithRespectTo(fun, lhs) 193 | rhsParen := isComplexOperatorWithRespectTo(fun, rhs) 194 | lhsType := con.getType(lhs) 195 | rhsType := con.getType(rhs) 196 | 197 | var timestampType *exprpb.Type 198 | var timestamp, duration *exprpb.Expr 199 | var timestampParen, durationParen bool 200 | switch { 201 | case isTimestampRelatedType(lhsType): 202 | timestampType = lhsType 203 | timestamp, duration = lhs, rhs 204 | timestampParen, durationParen = lhsParen, rhsParen 205 | case isTimestampRelatedType(rhsType): 206 | timestampType = rhsType 207 | timestamp, duration = rhs, lhs 208 | timestampParen, durationParen = rhsParen, lhsParen 209 | default: 210 | panic("lhs or rhs must be timestamp related type") 211 | } 212 | 213 | var sqlFun string 214 | switch fun { 215 | case operators.Add: 216 | switch { 217 | case isTimeType(timestampType): 218 | sqlFun = "TIME_ADD" 219 | case isDateType(timestampType): 220 | sqlFun = "DATE_ADD" 221 | case isDateTimeType(timestampType): 222 | sqlFun = "DATETIME_ADD" 223 | default: 224 | sqlFun = "TIMESTAMP_ADD" 225 | } 226 | case operators.Subtract: 227 | switch { 228 | case isTimeType(timestampType): 229 | sqlFun = "TIME_SUB" 230 | case isDateType(timestampType): 231 | sqlFun = "DATE_SUB" 232 | case isDateTimeType(timestampType): 233 | sqlFun = "DATETIME_SUB" 234 | default: 235 | sqlFun = "TIMESTAMP_SUB" 236 | } 237 | default: 238 | return fmt.Errorf("unsupported operation (%s)", fun) 239 | } 240 | con.str.WriteString(sqlFun) 241 | con.str.WriteString("(") 242 | if err := con.visitMaybeNested(timestamp, timestampParen); err != nil { 243 | return err 244 | } 245 | con.str.WriteString(", ") 246 | if err := con.visitMaybeNested(duration, durationParen); err != nil { 247 | return err 248 | } 249 | con.str.WriteString(")") 250 | return nil 251 | } 252 | 253 | func (con *converter) visitCallConditional(expr *exprpb.Expr) error { 254 | c := expr.GetCallExpr() 255 | args := c.GetArgs() 256 | con.str.WriteString("IF(") 257 | if err := con.visit(args[0]); err != nil { 258 | return err 259 | } 260 | con.str.WriteString(", ") 261 | if err := con.visit(args[1]); err != nil { 262 | return err 263 | } 264 | con.str.WriteString(", ") 265 | if err := con.visit(args[2]); err != nil { 266 | return nil 267 | } 268 | con.str.WriteString(")") 269 | return nil 270 | } 271 | 272 | var standardSQLFunctions = map[string]string{ 273 | operators.Modulo: "MOD", 274 | overloads.StartsWith: "STARTS_WITH", 275 | overloads.EndsWith: "ENDS_WITH", 276 | overloads.Matches: "REGEXP_CONTAINS", 277 | } 278 | 279 | func (con *converter) callContains(target *exprpb.Expr, args []*exprpb.Expr) error { 280 | con.str.WriteString("INSTR(") 281 | if target != nil { 282 | nested := isBinaryOrTernaryOperator(target) 283 | err := con.visitMaybeNested(target, nested) 284 | if err != nil { 285 | return err 286 | } 287 | con.str.WriteString(", ") 288 | } 289 | for i, arg := range args { 290 | err := con.visit(arg) 291 | if err != nil { 292 | return err 293 | } 294 | if i < len(args)-1 { 295 | con.str.WriteString(", ") 296 | } 297 | } 298 | con.str.WriteString(") != 0") 299 | return nil 300 | } 301 | 302 | func (con *converter) callDuration(target *exprpb.Expr, args []*exprpb.Expr) error { 303 | if len(args) != 1 { 304 | return fmt.Errorf("arguments must be single") 305 | } 306 | arg := args[0] 307 | var durationString string 308 | switch arg.ExprKind.(type) { 309 | case *exprpb.Expr_ConstExpr: 310 | switch arg.GetConstExpr().ConstantKind.(type) { 311 | case *exprpb.Constant_StringValue: 312 | durationString = arg.GetConstExpr().GetStringValue() 313 | default: 314 | return fmt.Errorf("unsupported constant kind %t", arg.GetConstExpr().ConstantKind) 315 | } 316 | default: 317 | return fmt.Errorf("unsupported kind %t", arg.ExprKind) 318 | } 319 | d, err := time.ParseDuration(durationString) 320 | if err != nil { 321 | return err 322 | } 323 | con.str.WriteString("INTERVAL ") 324 | switch d { 325 | case d.Round(time.Hour): 326 | con.str.WriteString(strconv.FormatFloat(d.Hours(), 'f', 0, 64)) 327 | con.str.WriteString(" HOUR") 328 | case d.Round(time.Minute): 329 | con.str.WriteString(strconv.FormatFloat(d.Minutes(), 'f', 0, 64)) 330 | con.str.WriteString(" MINUTE") 331 | case d.Round(time.Second): 332 | con.str.WriteString(strconv.FormatFloat(d.Seconds(), 'f', 0, 64)) 333 | con.str.WriteString(" SECOND") 334 | case d.Round(time.Millisecond): 335 | con.str.WriteString(strconv.FormatInt(d.Milliseconds(), 10)) 336 | con.str.WriteString(" MILLISECOND") 337 | default: 338 | con.str.WriteString(strconv.FormatInt(d.Truncate(time.Microsecond).Microseconds(), 10)) 339 | con.str.WriteString(" MICROSECOND") 340 | } 341 | return nil 342 | } 343 | 344 | func (con *converter) callInterval(target *exprpb.Expr, args []*exprpb.Expr) error { 345 | con.str.WriteString("INTERVAL ") 346 | if err := con.visit(args[0]); err != nil { 347 | return err 348 | } 349 | con.str.WriteString(" ") 350 | datePart := args[1] 351 | con.str.WriteString(datePart.GetIdentExpr().GetName()) 352 | return nil 353 | } 354 | 355 | func (con *converter) callExtractFromTimestamp(function string, target *exprpb.Expr, args []*exprpb.Expr) error { 356 | con.str.WriteString("EXTRACT(") 357 | switch function { 358 | case overloads.TimeGetFullYear: 359 | con.str.WriteString("YEAR") 360 | case overloads.TimeGetMonth: 361 | con.str.WriteString("MONTH") 362 | case overloads.TimeGetDate: 363 | con.str.WriteString("DAY") 364 | case overloads.TimeGetHours: 365 | con.str.WriteString("HOUR") 366 | case overloads.TimeGetMinutes: 367 | con.str.WriteString("MINUTE") 368 | case overloads.TimeGetSeconds: 369 | con.str.WriteString("SECOND") 370 | case overloads.TimeGetMilliseconds: 371 | con.str.WriteString("MILLISECOND") 372 | case overloads.TimeGetDayOfYear: 373 | con.str.WriteString("DAYOFYEAR") 374 | case overloads.TimeGetDayOfMonth: 375 | con.str.WriteString("DAY") 376 | case overloads.TimeGetDayOfWeek: 377 | con.str.WriteString("DAYOFWEEK") 378 | } 379 | con.str.WriteString(" FROM ") 380 | if err := con.visit(target); err != nil { 381 | return err 382 | } 383 | if isTimestampType(con.getType(target)) && len(args) == 1 { 384 | con.str.WriteString(" AT ") 385 | if err := con.visit(args[0]); err != nil { 386 | return err 387 | } 388 | } 389 | con.str.WriteString(")") 390 | if function == overloads.TimeGetMonth || function == overloads.TimeGetDayOfYear || function == overloads.TimeGetDayOfMonth || function == overloads.TimeGetDayOfWeek { 391 | con.str.WriteString(" - 1") 392 | } 393 | return nil 394 | } 395 | 396 | func (con *converter) callCasting(function string, target *exprpb.Expr, args []*exprpb.Expr) error { 397 | arg := args[0] 398 | if function == overloads.TypeConvertInt && isTimestampType(con.getType(arg)) { 399 | con.str.WriteString("UNIX_SECONDS(") 400 | if err := con.visit(arg); err != nil { 401 | return err 402 | } 403 | con.str.WriteString(")") 404 | return nil 405 | } 406 | con.str.WriteString("CAST(") 407 | if err := con.visit(arg); err != nil { 408 | return err 409 | } 410 | con.str.WriteString(" AS ") 411 | switch function { 412 | case overloads.TypeConvertBool: 413 | con.str.WriteString("BOOL") 414 | case overloads.TypeConvertBytes: 415 | con.str.WriteString("BYTES") 416 | case overloads.TypeConvertDouble: 417 | con.str.WriteString("FLOAT64") 418 | case overloads.TypeConvertInt: 419 | con.str.WriteString("INT64") 420 | case overloads.TypeConvertString: 421 | con.str.WriteString("STRING") 422 | case overloads.TypeConvertUint: 423 | con.str.WriteString("INT64") 424 | } 425 | con.str.WriteString(")") 426 | return nil 427 | } 428 | 429 | func (con *converter) visitCallFunc(expr *exprpb.Expr) error { 430 | c := expr.GetCallExpr() 431 | fun := c.GetFunction() 432 | target := c.GetTarget() 433 | args := c.GetArgs() 434 | switch fun { 435 | case overloads.Contains: 436 | return con.callContains(target, args) 437 | case overloads.TypeConvertDuration: 438 | return con.callDuration(target, args) 439 | case "interval": 440 | return con.callInterval(target, args) 441 | case overloads.TimeGetFullYear, 442 | overloads.TimeGetMonth, 443 | overloads.TimeGetDate, 444 | overloads.TimeGetHours, 445 | overloads.TimeGetMinutes, 446 | overloads.TimeGetSeconds, 447 | overloads.TimeGetMilliseconds, 448 | overloads.TimeGetDayOfYear, 449 | overloads.TimeGetDayOfMonth, 450 | overloads.TimeGetDayOfWeek: 451 | return con.callExtractFromTimestamp(fun, target, args) 452 | case overloads.TypeConvertBool, 453 | overloads.TypeConvertBytes, 454 | overloads.TypeConvertDouble, 455 | overloads.TypeConvertInt, 456 | overloads.TypeConvertString, 457 | overloads.TypeConvertUint: 458 | return con.callCasting(fun, target, args) 459 | } 460 | sqlFun, ok := standardSQLFunctions[fun] 461 | if !ok { 462 | if fun == overloads.Size { 463 | argType := con.getType(args[0]) 464 | switch { 465 | case argType.GetPrimitive() == exprpb.Type_STRING: 466 | sqlFun = "LENGTH" 467 | case argType.GetPrimitive() == exprpb.Type_BYTES: 468 | sqlFun = "LENGTH" 469 | case isListType(argType): 470 | sqlFun = "ARRAY_LENGTH" 471 | default: 472 | return fmt.Errorf("unsupported type: %v", argType) 473 | } 474 | } else { 475 | sqlFun = strings.ToUpper(fun) 476 | } 477 | } 478 | con.str.WriteString(sqlFun) 479 | con.str.WriteString("(") 480 | if target != nil { 481 | nested := isBinaryOrTernaryOperator(target) 482 | err := con.visitMaybeNested(target, nested) 483 | if err != nil { 484 | return err 485 | } 486 | con.str.WriteString(", ") 487 | } 488 | for i, arg := range args { 489 | err := con.visit(arg) 490 | if err != nil { 491 | return err 492 | } 493 | if i < len(args)-1 { 494 | con.str.WriteString(", ") 495 | } 496 | } 497 | con.str.WriteString(")") 498 | return nil 499 | } 500 | 501 | func (con *converter) visitCallIndex(expr *exprpb.Expr) error { 502 | if isMapType(con.getType(expr.GetCallExpr().GetArgs()[0])) { 503 | return con.visitCallMapIndex(expr) 504 | } 505 | return con.visitCallListIndex(expr) 506 | } 507 | 508 | func (con *converter) visitCallMapIndex(expr *exprpb.Expr) error { 509 | c := expr.GetCallExpr() 510 | args := c.GetArgs() 511 | m := args[0] 512 | nested := isBinaryOrTernaryOperator(m) 513 | if err := con.visitMaybeNested(m, nested); err != nil { 514 | return err 515 | } 516 | fieldName, err := extractFieldName(args[1]) 517 | if err != nil { 518 | return err 519 | } 520 | con.str.WriteString(".`") 521 | con.str.WriteString(fieldName) 522 | con.str.WriteString("`") 523 | return nil 524 | } 525 | 526 | func (con *converter) visitCallListIndex(expr *exprpb.Expr) error { 527 | c := expr.GetCallExpr() 528 | args := c.GetArgs() 529 | l := args[0] 530 | nested := isBinaryOrTernaryOperator(l) 531 | if err := con.visitMaybeNested(l, nested); err != nil { 532 | return err 533 | } 534 | con.str.WriteString("[OFFSET(") 535 | index := args[1] 536 | if err := con.visit(index); err != nil { 537 | return err 538 | } 539 | con.str.WriteString(")]") 540 | return nil 541 | } 542 | 543 | var standardSQLUnaryOperators = map[string]string{ 544 | operators.LogicalNot: "NOT ", 545 | } 546 | 547 | func (con *converter) visitCallUnary(expr *exprpb.Expr) error { 548 | c := expr.GetCallExpr() 549 | fun := c.GetFunction() 550 | args := c.GetArgs() 551 | var operator string 552 | if op, found := standardSQLUnaryOperators[fun]; found { 553 | operator = op 554 | } else if op, found := operators.FindReverse(fun); found { 555 | operator = op 556 | } else { 557 | return fmt.Errorf("cannot unmangle operator: %s", fun) 558 | } 559 | con.str.WriteString(operator) 560 | nested := isComplexOperator(args[0]) 561 | return con.visitMaybeNested(args[0], nested) 562 | } 563 | 564 | func (con *converter) visitComprehension(expr *exprpb.Expr) error { 565 | // TODO: introduce a macro expansion map between the top-level comprehension id and the 566 | // function call that the macro replaces. 567 | return fmt.Errorf("unimplemented : %v", expr) 568 | } 569 | 570 | func (con *converter) visitConst(expr *exprpb.Expr) error { 571 | c := expr.GetConstExpr() 572 | switch c.ConstantKind.(type) { 573 | case *exprpb.Constant_BoolValue: 574 | if c.GetBoolValue() { 575 | con.str.WriteString("TRUE") 576 | } else { 577 | con.str.WriteString("FALSE") 578 | } 579 | case *exprpb.Constant_BytesValue: 580 | b := c.GetBytesValue() 581 | con.str.WriteString(`b"`) 582 | con.str.WriteString(bytesToOctets(b)) 583 | con.str.WriteString(`"`) 584 | case *exprpb.Constant_DoubleValue: 585 | d := strconv.FormatFloat(c.GetDoubleValue(), 'g', -1, 64) 586 | con.str.WriteString(d) 587 | case *exprpb.Constant_Int64Value: 588 | i := strconv.FormatInt(c.GetInt64Value(), 10) 589 | con.str.WriteString(i) 590 | case *exprpb.Constant_NullValue: 591 | con.str.WriteString("NULL") 592 | case *exprpb.Constant_StringValue: 593 | con.str.WriteString(strconv.Quote(c.GetStringValue())) 594 | case *exprpb.Constant_Uint64Value: 595 | ui := strconv.FormatUint(c.GetUint64Value(), 10) 596 | con.str.WriteString(ui) 597 | default: 598 | return fmt.Errorf("unimplemented : %v", expr) 599 | } 600 | return nil 601 | } 602 | 603 | func (con *converter) visitIdent(expr *exprpb.Expr) error { 604 | con.str.WriteString("`") 605 | con.str.WriteString(expr.GetIdentExpr().GetName()) 606 | con.str.WriteString("`") 607 | return nil 608 | } 609 | 610 | func (con *converter) visitList(expr *exprpb.Expr) error { 611 | l := expr.GetListExpr() 612 | elems := l.GetElements() 613 | con.str.WriteString("[") 614 | for i, elem := range elems { 615 | err := con.visit(elem) 616 | if err != nil { 617 | return err 618 | } 619 | if i < len(elems)-1 { 620 | con.str.WriteString(", ") 621 | } 622 | } 623 | con.str.WriteString("]") 624 | return nil 625 | } 626 | 627 | func (con *converter) visitSelect(expr *exprpb.Expr) error { 628 | sel := expr.GetSelectExpr() 629 | // handle the case when the select expression was generated by the has() macro. 630 | if sel.GetTestOnly() { 631 | con.str.WriteString("has(") 632 | } 633 | nested := !sel.GetTestOnly() && isBinaryOrTernaryOperator(sel.GetOperand()) 634 | err := con.visitMaybeNested(sel.GetOperand(), nested) 635 | if err != nil { 636 | return err 637 | } 638 | con.str.WriteString(".`") 639 | con.str.WriteString(sel.GetField()) 640 | con.str.WriteString("`") 641 | if sel.GetTestOnly() { 642 | con.str.WriteString(")") 643 | } 644 | return nil 645 | } 646 | 647 | func (con *converter) visitStruct(expr *exprpb.Expr) error { 648 | s := expr.GetStructExpr() 649 | // If the message name is non-empty, then this should be treated as message construction. 650 | if s.GetMessageName() != "" { 651 | return con.visitStructMsg(expr) 652 | } 653 | // Otherwise, build a map. 654 | return con.visitStructMap(expr) 655 | } 656 | 657 | func (con *converter) visitStructMsg(expr *exprpb.Expr) error { 658 | m := expr.GetStructExpr() 659 | entries := m.GetEntries() 660 | con.str.WriteString(m.GetMessageName()) 661 | con.str.WriteString("{") 662 | for i, entry := range entries { 663 | f := entry.GetFieldKey() 664 | con.str.WriteString(f) 665 | con.str.WriteString(": ") 666 | v := entry.GetValue() 667 | err := con.visit(v) 668 | if err != nil { 669 | return err 670 | } 671 | if i < len(entries)-1 { 672 | con.str.WriteString(", ") 673 | } 674 | } 675 | con.str.WriteString("}") 676 | return nil 677 | } 678 | 679 | func (con *converter) visitStructMap(expr *exprpb.Expr) error { 680 | m := expr.GetStructExpr() 681 | entries := m.GetEntries() 682 | con.str.WriteString("STRUCT(") 683 | for i, entry := range entries { 684 | v := entry.GetValue() 685 | if err := con.visit(v); err != nil { 686 | return err 687 | } 688 | con.str.WriteString(" AS ") 689 | fieldName, err := extractFieldName(entry.GetMapKey()) 690 | if err != nil { 691 | return err 692 | } 693 | con.str.WriteString(fieldName) 694 | if i < len(entries)-1 { 695 | con.str.WriteString(", ") 696 | } 697 | } 698 | con.str.WriteString(")") 699 | return nil 700 | } 701 | 702 | func (con *converter) visitMaybeNested(expr *exprpb.Expr, nested bool) error { 703 | if nested { 704 | con.str.WriteString("(") 705 | } 706 | err := con.visit(expr) 707 | if err != nil { 708 | return err 709 | } 710 | if nested { 711 | con.str.WriteString(")") 712 | } 713 | return nil 714 | } 715 | 716 | func (con *converter) getType(node *exprpb.Expr) *exprpb.Type { 717 | return con.typeMap[node.GetId()] 718 | } 719 | 720 | func isMapType(typ *exprpb.Type) bool { 721 | _, ok := typ.TypeKind.(*exprpb.Type_MapType_) 722 | return ok 723 | } 724 | 725 | func isListType(typ *exprpb.Type) bool { 726 | _, ok := typ.TypeKind.(*exprpb.Type_ListType_) 727 | return ok 728 | } 729 | 730 | // isLeftRecursive indicates whether the parser resolves the call in a left-recursive manner as 731 | // this can have an effect of how parentheses affect the order of operations in the AST. 732 | func isLeftRecursive(op string) bool { 733 | return op != operators.LogicalAnd && op != operators.LogicalOr 734 | } 735 | 736 | // isSamePrecedence indicates whether the precedence of the input operator is the same as the 737 | // precedence of the (possible) operation represented in the input Expr. 738 | // 739 | // If the expr is not a Call, the result is false. 740 | func isSamePrecedence(op string, expr *exprpb.Expr) bool { 741 | if expr.GetCallExpr() == nil { 742 | return false 743 | } 744 | c := expr.GetCallExpr() 745 | other := c.GetFunction() 746 | return operators.Precedence(op) == operators.Precedence(other) 747 | } 748 | 749 | // isLowerPrecedence indicates whether the precedence of the input operator is lower precedence 750 | // than the (possible) operation represented in the input Expr. 751 | // 752 | // If the expr is not a Call, the result is false. 753 | func isLowerPrecedence(op string, expr *exprpb.Expr) bool { 754 | if expr.GetCallExpr() == nil { 755 | return false 756 | } 757 | c := expr.GetCallExpr() 758 | other := c.GetFunction() 759 | return operators.Precedence(op) < operators.Precedence(other) 760 | } 761 | 762 | // Indicates whether the expr is a complex operator, i.e., a call expression 763 | // with 2 or more arguments. 764 | func isComplexOperator(expr *exprpb.Expr) bool { 765 | if expr.GetCallExpr() != nil && len(expr.GetCallExpr().GetArgs()) >= 2 { 766 | return true 767 | } 768 | return false 769 | } 770 | 771 | // Indicates whether it is a complex operation compared to another. 772 | // expr is *not* considered complex if it is not a call expression or has 773 | // less than two arguments, or if it has a higher precedence than op. 774 | func isComplexOperatorWithRespectTo(op string, expr *exprpb.Expr) bool { 775 | if expr.GetCallExpr() == nil || len(expr.GetCallExpr().GetArgs()) < 2 { 776 | return false 777 | } 778 | return isLowerPrecedence(op, expr) 779 | } 780 | 781 | // Indicate whether this is a binary or ternary operator. 782 | func isBinaryOrTernaryOperator(expr *exprpb.Expr) bool { 783 | if expr.GetCallExpr() == nil || len(expr.GetCallExpr().GetArgs()) < 2 { 784 | return false 785 | } 786 | _, isBinaryOp := operators.FindReverseBinaryOperator(expr.GetCallExpr().GetFunction()) 787 | return isBinaryOp || isSamePrecedence(operators.Conditional, expr) 788 | } 789 | 790 | func isNullLiteral(node *exprpb.Expr) bool { 791 | _, isConst := node.ExprKind.(*exprpb.Expr_ConstExpr) 792 | if !isConst { 793 | return false 794 | } 795 | _, isNull := node.GetConstExpr().ConstantKind.(*exprpb.Constant_NullValue) 796 | return isNull 797 | } 798 | 799 | func isBoolLiteral(node *exprpb.Expr) bool { 800 | _, isConst := node.ExprKind.(*exprpb.Expr_ConstExpr) 801 | if !isConst { 802 | return false 803 | } 804 | _, isBool := node.GetConstExpr().ConstantKind.(*exprpb.Constant_BoolValue) 805 | return isBool 806 | } 807 | 808 | func isStringLiteral(node *exprpb.Expr) bool { 809 | _, isConst := node.ExprKind.(*exprpb.Expr_ConstExpr) 810 | if !isConst { 811 | return false 812 | } 813 | _, isString := node.GetConstExpr().ConstantKind.(*exprpb.Constant_StringValue) 814 | return isString 815 | } 816 | 817 | // bytesToOctets converts byte sequences to a string using a three digit octal encoded value 818 | // per byte. 819 | func bytesToOctets(byteVal []byte) string { 820 | var b strings.Builder 821 | for _, c := range byteVal { 822 | _, _ = fmt.Fprintf(&b, "\\%03o", c) 823 | } 824 | return b.String() 825 | } 826 | 827 | var fieldNameRegexp = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]{0,127}$`) 828 | 829 | func validateFieldName(name string) error { 830 | if !fieldNameRegexp.MatchString(name) { 831 | return fmt.Errorf("invalid field name \"%s\"", name) 832 | } 833 | return nil 834 | } 835 | 836 | func extractFieldName(node *exprpb.Expr) (string, error) { 837 | if !isStringLiteral(node) { 838 | return "", fmt.Errorf("unsupported type: %v", node) 839 | } 840 | fieldName := node.GetConstExpr().GetStringValue() 841 | if err := validateFieldName(fieldName); err != nil { 842 | return "", err 843 | } 844 | return fieldName, nil 845 | } 846 | -------------------------------------------------------------------------------- /cel2sql_test.go: -------------------------------------------------------------------------------- 1 | package cel2sql_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "cloud.google.com/go/bigquery" 7 | "github.com/google/cel-go/cel" 8 | "github.com/google/cel-go/checker/decls" 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | 12 | "github.com/cockscomb/cel2sql" 13 | "github.com/cockscomb/cel2sql/bq" 14 | "github.com/cockscomb/cel2sql/sqltypes" 15 | "github.com/cockscomb/cel2sql/test" 16 | ) 17 | 18 | func TestConvert(t *testing.T) { 19 | env, err := cel.NewEnv( 20 | cel.CustomTypeProvider(bq.NewTypeProvider(map[string]bigquery.Schema{ 21 | "trigrams": test.NewTrigramsTableMetadata().Schema, 22 | "wikipedia": test.NewWikipediaTableMetadata().Schema, 23 | })), 24 | sqltypes.SQLTypeDeclarations, 25 | cel.Declarations( 26 | decls.NewVar("name", decls.String), 27 | decls.NewVar("age", decls.Int), 28 | decls.NewVar("adult", decls.Bool), 29 | decls.NewVar("height", decls.Double), 30 | decls.NewVar("string_list", decls.NewListType(decls.String)), 31 | decls.NewVar("string_int_map", decls.NewMapType(decls.String, decls.Int)), 32 | decls.NewVar("null_var", decls.Null), 33 | decls.NewVar("birthday", sqltypes.Date), 34 | decls.NewVar("fixed_time", sqltypes.Time), 35 | decls.NewVar("scheduled_at", sqltypes.DateTime), 36 | decls.NewVar("created_at", decls.Timestamp), 37 | decls.NewVar("trigram", decls.NewObjectType("trigrams")), 38 | decls.NewVar("page", decls.NewObjectType("wikipedia")), 39 | ), 40 | ) 41 | require.NoError(t, err) 42 | type args struct { 43 | source string 44 | } 45 | tests := []struct { 46 | name string 47 | args args 48 | want string 49 | wantErr bool 50 | }{ 51 | { 52 | name: "startsWith", 53 | args: args{source: `name.startsWith("a")`}, 54 | want: "STARTS_WITH(`name`, \"a\")", 55 | wantErr: false, 56 | }, 57 | { 58 | name: "endsWith", 59 | args: args{source: `name.endsWith("z")`}, 60 | want: "ENDS_WITH(`name`, \"z\")", 61 | wantErr: false, 62 | }, 63 | { 64 | name: "matches", 65 | args: args{source: `name.matches("a+")`}, 66 | want: "REGEXP_CONTAINS(`name`, \"a+\")", 67 | wantErr: false, 68 | }, 69 | { 70 | name: "contains", 71 | args: args{source: `name.contains("abc")`}, 72 | want: "INSTR(`name`, \"abc\") != 0", 73 | wantErr: false, 74 | }, 75 | { 76 | name: "&&", 77 | args: args{source: `name.startsWith("a") && name.endsWith("z")`}, 78 | want: "STARTS_WITH(`name`, \"a\") AND ENDS_WITH(`name`, \"z\")", 79 | wantErr: false, 80 | }, 81 | { 82 | name: "||", 83 | args: args{source: `name.startsWith("a") || name.endsWith("z")`}, 84 | want: "STARTS_WITH(`name`, \"a\") OR ENDS_WITH(`name`, \"z\")", 85 | wantErr: false, 86 | }, 87 | { 88 | name: "()", 89 | args: args{source: `age >= 10 && (name.startsWith("a") || name.endsWith("z"))`}, 90 | want: "`age` >= 10 AND (STARTS_WITH(`name`, \"a\") OR ENDS_WITH(`name`, \"z\"))", 91 | wantErr: false, 92 | }, 93 | { 94 | name: "IF", 95 | args: args{source: `name == "a" ? "a" : "b"`}, 96 | want: "IF(`name` = \"a\", \"a\", \"b\")", 97 | wantErr: false, 98 | }, 99 | { 100 | name: "==", 101 | args: args{source: `name == "a"`}, 102 | want: "`name` = \"a\"", 103 | wantErr: false, 104 | }, 105 | { 106 | name: "!=", 107 | args: args{source: `age != 20`}, 108 | want: "`age` != 20", 109 | wantErr: false, 110 | }, 111 | { 112 | name: "IS NULL", 113 | args: args{source: `null_var == null`}, 114 | want: "`null_var` IS NULL", 115 | wantErr: false, 116 | }, 117 | { 118 | name: "IS NOT TRUE", 119 | args: args{source: `adult != true`}, 120 | want: "`adult` IS NOT TRUE", 121 | wantErr: false, 122 | }, 123 | { 124 | name: "<", 125 | args: args{source: `age < 20`}, 126 | want: "`age` < 20", 127 | wantErr: false, 128 | }, 129 | { 130 | name: ">=", 131 | args: args{source: `height >= 1.6180339887`}, 132 | want: "`height` >= 1.6180339887", 133 | wantErr: false, 134 | }, 135 | { 136 | name: "NOT", 137 | args: args{source: `!adult`}, 138 | want: "NOT `adult`", 139 | wantErr: false, 140 | }, 141 | { 142 | name: "-", 143 | args: args{source: `-1`}, 144 | want: "-1", 145 | wantErr: false, 146 | }, 147 | { 148 | name: "list", 149 | args: args{source: `[1, 2, 3][0] == 1`}, 150 | want: "[1, 2, 3][OFFSET(0)] = 1", 151 | wantErr: false, 152 | }, 153 | { 154 | name: "list_var", 155 | args: args{source: `string_list[0] == "a"`}, 156 | want: "`string_list`[OFFSET(0)] = \"a\"", 157 | wantErr: false, 158 | }, 159 | { 160 | name: "map", 161 | args: args{source: `{"one": 1, "two": 2, "three": 3}["one"] == 1`}, 162 | want: "STRUCT(1 AS one, 2 AS two, 3 AS three).`one` = 1", 163 | wantErr: false, 164 | }, 165 | { 166 | name: "map_var", 167 | args: args{source: `string_int_map["one"] == 1`}, 168 | want: "`string_int_map`.`one` = 1", 169 | wantErr: false, 170 | }, 171 | { 172 | name: "invalidFieldType", 173 | args: args{source: `{1: 1}[1]`}, 174 | want: "", 175 | wantErr: true, 176 | }, 177 | { 178 | name: "invalidFieldName", 179 | args: args{source: `{"on e": 1}["on e"]`}, 180 | want: "", 181 | wantErr: true, 182 | }, 183 | { 184 | name: "add", 185 | args: args{source: `1 + 2 == 3`}, 186 | want: "1 + 2 = 3", 187 | wantErr: false, 188 | }, 189 | { 190 | name: "concatString", 191 | args: args{source: `"a" + "b" == "ab"`}, 192 | want: "\"a\" || \"b\" = \"ab\"", 193 | wantErr: false, 194 | }, 195 | { 196 | name: "concatList", 197 | args: args{source: `1 in [1] + [2, 3]`}, 198 | want: "1 IN UNNEST([1] || [2, 3])", 199 | wantErr: false, 200 | }, 201 | { 202 | name: "modulo", 203 | args: args{source: `5 % 3 == 2`}, 204 | want: "MOD(5, 3) = 2", 205 | wantErr: false, 206 | }, 207 | { 208 | name: "date", 209 | args: args{source: `birthday > date(2000, 1, 1) + 1`}, 210 | want: "`birthday` > DATE(2000, 1, 1) + 1", 211 | wantErr: false, 212 | }, 213 | { 214 | name: "time", 215 | args: args{source: `fixed_time == time("18:00:00")`}, 216 | want: "`fixed_time` = TIME(\"18:00:00\")", 217 | wantErr: false, 218 | }, 219 | { 220 | name: "datetime", 221 | args: args{source: `scheduled_at != datetime(date("2021-09-01"), fixed_time)`}, 222 | want: "`scheduled_at` != DATETIME(DATE(\"2021-09-01\"), `fixed_time`)", 223 | wantErr: false, 224 | }, 225 | { 226 | name: "timestamp", 227 | args: args{source: `created_at - duration("60m") <= timestamp(datetime("2021-09-01 18:00:00"), "Asia/Tokyo")`}, 228 | want: "TIMESTAMP_SUB(`created_at`, INTERVAL 1 HOUR) <= TIMESTAMP(DATETIME(\"2021-09-01 18:00:00\"), \"Asia/Tokyo\")", 229 | wantErr: false, 230 | }, 231 | { 232 | name: "duration_second", 233 | args: args{source: `duration("10s")`}, 234 | want: "INTERVAL 10 SECOND", 235 | wantErr: false, 236 | }, 237 | { 238 | name: "duration_minute", 239 | args: args{source: `duration("1h1m")`}, 240 | want: "INTERVAL 61 MINUTE", 241 | wantErr: false, 242 | }, 243 | { 244 | name: "duration_hour", 245 | args: args{source: `duration("60m")`}, 246 | want: "INTERVAL 1 HOUR", 247 | wantErr: false, 248 | }, 249 | { 250 | name: "interval", 251 | args: args{source: `interval(1, MONTH)`}, 252 | want: "INTERVAL 1 MONTH", 253 | wantErr: false, 254 | }, 255 | { 256 | name: "date_add", 257 | args: args{source: `date("2021-09-01") + interval(1, DAY)`}, 258 | want: "DATE_ADD(DATE(\"2021-09-01\"), INTERVAL 1 DAY)", 259 | wantErr: false, 260 | }, 261 | { 262 | name: "date_sub", 263 | args: args{source: `current_date() - interval(1, DAY)`}, 264 | want: "DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)", 265 | wantErr: false, 266 | }, 267 | { 268 | name: "time_add", 269 | args: args{source: `time("09:00:00") + interval(1, MINUTE)`}, 270 | want: "TIME_ADD(TIME(\"09:00:00\"), INTERVAL 1 MINUTE)", 271 | wantErr: false, 272 | }, 273 | { 274 | name: "time_sub", 275 | args: args{source: `time("09:00:00") - interval(1, MINUTE)`}, 276 | want: "TIME_SUB(TIME(\"09:00:00\"), INTERVAL 1 MINUTE)", 277 | wantErr: false, 278 | }, 279 | { 280 | name: "datetime_add", 281 | args: args{source: `datetime("2021-09-01 18:00:00") + interval(1, MINUTE)`}, 282 | want: "DATETIME_ADD(DATETIME(\"2021-09-01 18:00:00\"), INTERVAL 1 MINUTE)", 283 | wantErr: false, 284 | }, 285 | { 286 | name: "datetime_sub", 287 | args: args{source: `current_datetime("Asia/Tokyo") - interval(1, MINUTE)`}, 288 | want: "DATETIME_SUB(CURRENT_DATETIME(\"Asia/Tokyo\"), INTERVAL 1 MINUTE)", 289 | wantErr: false, 290 | }, 291 | { 292 | name: "timestamp_add", 293 | args: args{source: `duration("1h") + timestamp("2021-09-01T18:00:00Z")`}, 294 | want: "TIMESTAMP_ADD(TIMESTAMP(\"2021-09-01T18:00:00Z\"), INTERVAL 1 HOUR)", 295 | wantErr: false, 296 | }, 297 | { 298 | name: "timestamp_sub", 299 | args: args{source: `created_at - interval(1, HOUR)`}, 300 | want: "TIMESTAMP_SUB(`created_at`, INTERVAL 1 HOUR)", 301 | wantErr: false, 302 | }, 303 | { 304 | name: "timestamp_getSeconds", 305 | args: args{source: `created_at.getSeconds()`}, 306 | want: "EXTRACT(SECOND FROM `created_at`)", 307 | wantErr: false, 308 | }, 309 | { 310 | name: "\"timestamp_getHours_withTimezone", 311 | args: args{source: `created_at.getHours("Asia/Tokyo")`}, 312 | want: "EXTRACT(HOUR FROM `created_at` AT \"Asia/Tokyo\")", 313 | wantErr: false, 314 | }, 315 | { 316 | name: "date_getFullYear", 317 | args: args{source: `birthday.getFullYear()`}, 318 | want: "EXTRACT(YEAR FROM `birthday`)", 319 | wantErr: false, 320 | }, 321 | { 322 | name: "datetime_getMonth", 323 | args: args{source: `scheduled_at.getMonth()`}, 324 | want: "EXTRACT(MONTH FROM `scheduled_at`) - 1", 325 | wantErr: false, 326 | }, 327 | { 328 | name: "datetime_getDayOfMonth", 329 | args: args{source: `scheduled_at.getDayOfMonth()`}, 330 | want: "EXTRACT(DAY FROM `scheduled_at`) - 1", 331 | wantErr: false, 332 | }, 333 | { 334 | name: "time_getMinutes", 335 | args: args{source: `fixed_time.getMinutes()`}, 336 | want: "EXTRACT(MINUTE FROM `fixed_time`)", 337 | wantErr: false, 338 | }, 339 | { 340 | name: "fieldSelect", 341 | args: args{source: `page.title == "test"`}, 342 | want: "`page`.`title` = \"test\"", 343 | wantErr: false, 344 | }, 345 | { 346 | name: "fieldSelect_startsWith", 347 | args: args{source: `page.title.startsWith("test")`}, 348 | want: "STARTS_WITH(`page`.`title`, \"test\")", 349 | wantErr: false, 350 | }, 351 | { 352 | name: "fieldSelect_add", 353 | args: args{source: `trigram.cell[0].page_count + 1`}, 354 | want: "`trigram`.`cell`[OFFSET(0)].`page_count` + 1", 355 | wantErr: false, 356 | }, 357 | { 358 | name: "fieldSelect_concatString", 359 | args: args{source: `trigram.cell[0].sample[0].title + "test"`}, 360 | want: "`trigram`.`cell`[OFFSET(0)].`sample`[OFFSET(0)].`title` || \"test\"", 361 | wantErr: false, 362 | }, 363 | { 364 | name: "fieldSelect_in", 365 | args: args{source: `"test" in trigram.cell[0].value`}, 366 | want: "\"test\" IN UNNEST(`trigram`.`cell`[OFFSET(0)].`value`)", 367 | wantErr: false, 368 | }, 369 | { 370 | name: "cast_bool", 371 | args: args{source: `bool(0) == false`}, 372 | want: "CAST(0 AS BOOL) IS FALSE", 373 | wantErr: false, 374 | }, 375 | { 376 | name: "cast_bytes", 377 | args: args{source: `bytes("test")`}, 378 | want: "CAST(\"test\" AS BYTES)", 379 | wantErr: false, 380 | }, 381 | { 382 | name: "cast_int", 383 | args: args{source: `int(true) == 1`}, 384 | want: "CAST(TRUE AS INT64) = 1", 385 | wantErr: false, 386 | }, 387 | { 388 | name: "cast_string", 389 | args: args{source: `string(true) == "true"`}, 390 | want: "CAST(TRUE AS STRING) = \"true\"", 391 | wantErr: false, 392 | }, 393 | { 394 | name: "cast_string_from_timestamp", 395 | args: args{source: `string(created_at)`}, 396 | want: "CAST(`created_at` AS STRING)", 397 | wantErr: false, 398 | }, 399 | { 400 | name: "cast_int_epoch", 401 | args: args{source: `int(created_at)`}, 402 | want: "UNIX_SECONDS(`created_at`)", 403 | wantErr: false, 404 | }, 405 | { 406 | name: "size_string", 407 | args: args{source: `size("test")`}, 408 | want: "LENGTH(\"test\")", 409 | wantErr: false, 410 | }, 411 | { 412 | name: "size_bytes", 413 | args: args{source: `size(bytes("test"))`}, 414 | want: "LENGTH(CAST(\"test\" AS BYTES))", 415 | wantErr: false, 416 | }, 417 | { 418 | name: "size_list", 419 | args: args{source: `size(string_list)`}, 420 | want: "ARRAY_LENGTH(`string_list`)", 421 | wantErr: false, 422 | }, 423 | } 424 | for _, tt := range tests { 425 | t.Run(tt.name, func(t *testing.T) { 426 | ast, issues := env.Compile(tt.args.source) 427 | require.Empty(t, issues) 428 | 429 | got, err := cel2sql.Convert(ast) 430 | if !tt.wantErr && assert.NoError(t, err) { 431 | assert.Equal(t, tt.want, got) 432 | } else { 433 | assert.Error(t, err) 434 | } 435 | }) 436 | } 437 | } 438 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/cockscomb/cel2sql 2 | 3 | go 1.16 4 | 5 | require ( 6 | cloud.google.com/go/bigquery v1.25.0 7 | github.com/google/cel-go v0.7.3 8 | github.com/stretchr/testify v1.7.0 9 | google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 10 | ) 11 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 8 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 9 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 10 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 11 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 12 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 13 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 14 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 15 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 16 | cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= 17 | cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= 18 | cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= 19 | cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= 20 | cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= 21 | cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= 22 | cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= 23 | cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= 24 | cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= 25 | cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= 26 | cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= 27 | cloud.google.com/go v0.97.0 h1:3DXvAyifywvq64LfkKaMOmkWPS1CikIQdMe2lY9vxU8= 28 | cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= 29 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 30 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 31 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 32 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 33 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 34 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 35 | cloud.google.com/go/bigquery v1.25.0 h1:8MQohtqep0hpDh5PGy3juVaawv9l5335EX27SeeE1qo= 36 | cloud.google.com/go/bigquery v1.25.0/go.mod h1:4WtqW7wUNz7dklHMg62ST1k97dQrsnZN5iCeZYrIsC8= 37 | cloud.google.com/go/datacatalog v1.0.0 h1:KHjIs525XbESSGHxwEKHTzkwfvj7xxYrCy4gcvvlHBY= 38 | cloud.google.com/go/datacatalog v1.0.0/go.mod h1:cz8rXsZV278v0nXPhnp5eXRnZtqx2Mtv96W8r7a7Oxs= 39 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 40 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 41 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 42 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 43 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 44 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 45 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 46 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 47 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 48 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 49 | cloud.google.com/go/storage v1.10.0 h1:STgFzyU5/8miMl0//zKh2aQeTyeaUH3WN9bSUiJ09bA= 50 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 51 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 52 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 53 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 54 | github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= 55 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 56 | github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= 57 | github.com/antlr/antlr4 v0.0.0-20200503195918-621b933c7a7f h1:0cEys61Sr2hUBEXfNV8eyQP01oZuBgoMeHunebPirK8= 58 | github.com/antlr/antlr4 v0.0.0-20200503195918-621b933c7a7f/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y= 59 | github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= 60 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 61 | github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= 62 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 63 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 64 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 65 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 66 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 67 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 68 | github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 69 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 h1:cqQfy1jclcSy/FwLjemeg3SR1yaINm74aQyupQ0Bl8M= 70 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 71 | github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed h1:OZmjad4L3H8ncOIR8rnb5MREYqG8ixi5+WbeUsquF0c= 72 | github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 73 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 74 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 75 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 76 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 77 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 78 | github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= 79 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 80 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 81 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0 h1:dulLQAYQFYtG5MTplgNGHWuV2D+OBD+Z8lmDBmbLg+s= 82 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= 83 | github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= 84 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 85 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 86 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 87 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 88 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 89 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 90 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 91 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 92 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= 93 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 94 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 95 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 96 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 97 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 98 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 99 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 100 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 101 | github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= 102 | github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 103 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 104 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 105 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 106 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 107 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 108 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 109 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 110 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 111 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 112 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 113 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 114 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 115 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 116 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 117 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 118 | github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= 119 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 120 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 121 | github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 122 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 123 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 124 | github.com/google/cel-go v0.7.3 h1:8v9BSN0avuGwrHFKNCjfiQ/CE6+D6sW+BDyOVoEeP6o= 125 | github.com/google/cel-go v0.7.3/go.mod h1:4EtyFAHT5xNr0Msu0MJjyGxPUgdr9DlcaPyzLt/kkt8= 126 | github.com/google/cel-spec v0.5.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= 127 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 128 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 129 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 130 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 131 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 132 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 133 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 134 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 135 | github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 136 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 137 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 138 | github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= 139 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 140 | github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= 141 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 142 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 143 | github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 144 | github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ= 145 | github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= 146 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 147 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 148 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 149 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 150 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 151 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 152 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 153 | github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 154 | github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 155 | github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 156 | github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 157 | github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 158 | github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 159 | github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 160 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 161 | github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= 162 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 163 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 164 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 165 | github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= 166 | github.com/googleapis/gax-go/v2 v2.1.1 h1:dp3bWCh+PPO1zjRRiCSczJav13sBvG4UhNyVTa1KqdU= 167 | github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= 168 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= 169 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 170 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 171 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 172 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 173 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 174 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 175 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 176 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 177 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 178 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 179 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 180 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 181 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 182 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 183 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 184 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 185 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 186 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= 187 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 188 | github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= 189 | github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= 190 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 191 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 192 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 193 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 194 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 195 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 196 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 197 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 198 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 199 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 200 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 201 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 202 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 203 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 204 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 205 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 206 | go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= 207 | go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= 208 | go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= 209 | go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= 210 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 211 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 212 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 213 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 214 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 215 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 216 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 217 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 218 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 219 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 220 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 221 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 222 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 223 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 224 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 225 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 226 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 227 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 228 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 229 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 230 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 231 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 232 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 233 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 234 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 235 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 236 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 237 | golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 238 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 239 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 240 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 241 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 242 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 243 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 244 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 245 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 246 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 247 | golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 248 | golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 249 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 250 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 251 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 252 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 253 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 254 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 255 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 256 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 257 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 258 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 259 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 260 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 261 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 262 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 263 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 264 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 265 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 266 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 267 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 268 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 269 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 270 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 271 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 272 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 273 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 274 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 275 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 276 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 277 | golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 278 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 279 | golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 280 | golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 281 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 282 | golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= 283 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 284 | golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420 h1:a8jGStKg0XqKDlKqjLrXn0ioF5MH36pT7Z0BRTqLhbk= 285 | golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 286 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 287 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 288 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 289 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 290 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 291 | golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 292 | golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 293 | golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 294 | golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 295 | golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 296 | golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 297 | golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 298 | golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 299 | golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 300 | golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 301 | golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1 h1:B333XXssMuKQeBwiNODx4TupZy7bf4sxFZnN2ZOcvUE= 302 | golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 303 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 304 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 305 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 306 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 307 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 308 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 309 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 310 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 311 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 312 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 313 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 314 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 315 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 316 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 317 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 318 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 319 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 320 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 321 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 322 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 323 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 324 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 325 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 326 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 327 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 328 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 329 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 330 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 331 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 332 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 333 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 334 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 335 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 336 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 337 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 338 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 339 | golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 340 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 341 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 342 | golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 343 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 344 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 345 | golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 346 | golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 347 | golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 348 | golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 349 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 350 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 351 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 352 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 353 | golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 354 | golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 355 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 356 | golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 357 | golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 358 | golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 359 | golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik= 360 | golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 361 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 362 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 363 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 364 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 365 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 366 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 367 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 368 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 369 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= 370 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 371 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 372 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 373 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 374 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 375 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 376 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 377 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 378 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 379 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 380 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 381 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 382 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 383 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 384 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 385 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 386 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 387 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 388 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 389 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 390 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 391 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 392 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 393 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 394 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 395 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 396 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 397 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 398 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 399 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 400 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 401 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 402 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 403 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 404 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 405 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 406 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 407 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 408 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 409 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 410 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 411 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 412 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 413 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 414 | golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= 415 | golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 416 | golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 417 | golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 418 | golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 419 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 420 | golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 421 | golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 422 | golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 423 | golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 424 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 425 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 426 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 427 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 428 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 429 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 430 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 431 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 432 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 433 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 434 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 435 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 436 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 437 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 438 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 439 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 440 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 441 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 442 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 443 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 444 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 445 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 446 | google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= 447 | google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= 448 | google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= 449 | google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= 450 | google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= 451 | google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= 452 | google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= 453 | google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= 454 | google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= 455 | google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= 456 | google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= 457 | google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= 458 | google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= 459 | google.golang.org/api v0.60.0 h1:eq/zs5WPH4J9undYM9IP1O7dSr7Yh8Y0GtSCpzGzIUk= 460 | google.golang.org/api v0.60.0/go.mod h1:d7rl65NZAkEQ90JFzqBjcRq1TVeG5ZoGV3sSpEnnVb4= 461 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 462 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 463 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 464 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 465 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 466 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 467 | google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= 468 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 469 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 470 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 471 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 472 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 473 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 474 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 475 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 476 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 477 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 478 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 479 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 480 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 481 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 482 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 483 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 484 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 485 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 486 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 487 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 488 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 489 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 490 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 491 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 492 | google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 493 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 494 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 495 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 496 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 497 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 498 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 499 | google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 500 | google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 501 | google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 502 | google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 503 | google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 504 | google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 505 | google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 506 | google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 507 | google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 508 | google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 509 | google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= 510 | google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= 511 | google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= 512 | google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= 513 | google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= 514 | google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= 515 | google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= 516 | google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= 517 | google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= 518 | google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= 519 | google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= 520 | google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 521 | google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 522 | google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 523 | google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 524 | google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= 525 | google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 526 | google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 527 | google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 528 | google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 h1:b9mVrqYfq3P4bCdaLg1qtBnPzUYgglsIdjZkL/fQVOE= 529 | google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 530 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 531 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 532 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 533 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 534 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 535 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 536 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 537 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 538 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 539 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 540 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 541 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 542 | google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 543 | google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= 544 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 545 | google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= 546 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 547 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 548 | google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 549 | google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 550 | google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 551 | google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 552 | google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= 553 | google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= 554 | google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= 555 | google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= 556 | google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 557 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 558 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 559 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 560 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 561 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 562 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 563 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 564 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 565 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 566 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 567 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 568 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 569 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= 570 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 571 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 572 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 573 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 574 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 575 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 576 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 577 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 578 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 579 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 580 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 581 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 582 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 583 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 584 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 585 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 586 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 587 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 588 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 589 | -------------------------------------------------------------------------------- /sqltypes/types.go: -------------------------------------------------------------------------------- 1 | package sqltypes 2 | 3 | import ( 4 | "github.com/google/cel-go/cel" 5 | "github.com/google/cel-go/checker/decls" 6 | "github.com/google/cel-go/common/operators" 7 | "github.com/google/cel-go/common/overloads" 8 | expr "google.golang.org/genproto/googleapis/api/expr/v1alpha1" 9 | ) 10 | 11 | var ( 12 | Date = decls.NewAbstractType("DATE") 13 | Time = decls.NewAbstractType("TIME") 14 | DateTime = decls.NewAbstractType("DATETIME") 15 | Interval = decls.NewAbstractType("INTERVAL") 16 | DatePart = decls.NewAbstractType("date_part") 17 | ) 18 | 19 | func newConstantString(str string) *expr.Constant { 20 | return &expr.Constant{ConstantKind: &expr.Constant_StringValue{StringValue: str}} 21 | } 22 | 23 | var SQLTypeDeclarations = cel.Declarations( 24 | // constants 25 | decls.NewConst("MICROSECOND", DatePart, newConstantString("MICROSECOND")), 26 | decls.NewConst("MILLISECOND", DatePart, newConstantString("MILLISECOND")), 27 | decls.NewConst("SECOND", DatePart, newConstantString("SECOND")), 28 | decls.NewConst("MINUTE", DatePart, newConstantString("MINUTE")), 29 | decls.NewConst("HOUR", DatePart, newConstantString("HOUR")), 30 | decls.NewConst("DAY", DatePart, newConstantString("DAY")), 31 | decls.NewConst("DAYOFWEEK", DatePart, newConstantString("DAYOFWEEK")), 32 | decls.NewConst("WEEK", DatePart, newConstantString("WEEK")), 33 | decls.NewConst("ISOWEEK", DatePart, newConstantString("ISOWEEK")), 34 | decls.NewConst("MONTH", DatePart, newConstantString("MONTH")), 35 | decls.NewConst("QUARTER", DatePart, newConstantString("QUARTER")), 36 | decls.NewConst("YEAR", DatePart, newConstantString("YEAR")), 37 | decls.NewConst("ISOYEAR", DatePart, newConstantString("ISOYEAR")), 38 | 39 | // functions 40 | decls.NewFunction(overloads.TimeGetFullYear, 41 | decls.NewInstanceOverload("date_to_year", []*expr.Type{Date}, decls.Int), 42 | decls.NewInstanceOverload("datetime_to_year", []*expr.Type{DateTime}, decls.Int), 43 | ), 44 | decls.NewFunction(overloads.TimeGetMonth, 45 | decls.NewInstanceOverload("date_to_month", []*expr.Type{Date}, decls.Int), 46 | decls.NewInstanceOverload("datetime_to_month", []*expr.Type{DateTime}, decls.Int), 47 | ), 48 | decls.NewFunction(overloads.TimeGetDate, 49 | decls.NewInstanceOverload("date_to_date", []*expr.Type{Date}, decls.Int), 50 | decls.NewInstanceOverload("datetime_to_date", []*expr.Type{DateTime}, decls.Int), 51 | ), 52 | decls.NewFunction(overloads.TimeGetHours, 53 | decls.NewInstanceOverload("time_to_hours", []*expr.Type{Time}, decls.Int), 54 | decls.NewInstanceOverload("datetime_to_hours", []*expr.Type{DateTime}, decls.Int), 55 | ), 56 | decls.NewFunction(overloads.TimeGetMinutes, 57 | decls.NewInstanceOverload("time_to_minutes", []*expr.Type{Time}, decls.Int), 58 | decls.NewInstanceOverload("datetime_to_minutes", []*expr.Type{DateTime}, decls.Int), 59 | ), 60 | decls.NewFunction(overloads.TimeGetSeconds, 61 | decls.NewInstanceOverload("time_to_seconds", []*expr.Type{Time}, decls.Int), 62 | decls.NewInstanceOverload("datetime_to_seconds", []*expr.Type{DateTime}, decls.Int), 63 | ), 64 | decls.NewFunction(overloads.TimeGetMilliseconds, 65 | decls.NewInstanceOverload("time_to_milliseconds", []*expr.Type{Time}, decls.Int), 66 | decls.NewInstanceOverload("datetime_to_milliseconds", []*expr.Type{DateTime}, decls.Int), 67 | ), 68 | decls.NewFunction(overloads.TimeGetDayOfYear, 69 | decls.NewInstanceOverload("date_to_day_of_year", []*expr.Type{Date}, decls.Int), 70 | decls.NewInstanceOverload("datetime_to_day_of_year", []*expr.Type{DateTime}, decls.Int), 71 | ), 72 | decls.NewFunction(overloads.TimeGetDayOfMonth, 73 | decls.NewInstanceOverload("date_to_day_of_month", []*expr.Type{Date}, decls.Int), 74 | decls.NewInstanceOverload("datetime_to_day_of_month", []*expr.Type{DateTime}, decls.Int), 75 | ), 76 | decls.NewFunction(overloads.TimeGetDayOfWeek, 77 | decls.NewInstanceOverload("date_to_day_of_week", []*expr.Type{Date}, decls.Int), 78 | decls.NewInstanceOverload("datetime_to_day_of_week", []*expr.Type{DateTime}, decls.Int), 79 | ), 80 | decls.NewFunction(overloads.TypeConvertBool, 81 | decls.NewOverload("int_to_bool", []*expr.Type{decls.Int}, decls.Bool), 82 | decls.NewOverload("uint_to_bool", []*expr.Type{decls.Uint}, decls.Bool), 83 | ), 84 | decls.NewFunction(overloads.TypeConvertInt, 85 | decls.NewOverload("bool_to_int", []*expr.Type{decls.Bool}, decls.Int), 86 | ), 87 | 88 | // operators 89 | decls.NewFunction(operators.Less, 90 | decls.NewOverload("less_date", []*expr.Type{Date, Date}, decls.Bool), 91 | decls.NewOverload("less_time", []*expr.Type{Time, Time}, decls.Bool), 92 | decls.NewOverload("less_datetime", []*expr.Type{DateTime, DateTime}, decls.Bool), 93 | ), 94 | decls.NewFunction(operators.LessEquals, 95 | decls.NewOverload("less_equals_date", []*expr.Type{Date, Date}, decls.Bool), 96 | decls.NewOverload("less_equals_time", []*expr.Type{Time, Time}, decls.Bool), 97 | decls.NewOverload("less_equals_datetime", []*expr.Type{DateTime, DateTime}, decls.Bool), 98 | ), 99 | decls.NewFunction(operators.Greater, 100 | decls.NewOverload("greater_date", []*expr.Type{Date, Date}, decls.Bool), 101 | decls.NewOverload("greater_time", []*expr.Type{Time, Time}, decls.Bool), 102 | decls.NewOverload("greater_datetime", []*expr.Type{DateTime, DateTime}, decls.Bool), 103 | ), 104 | decls.NewFunction(operators.GreaterEquals, 105 | decls.NewOverload("greater_equals_date", []*expr.Type{Date, Date}, decls.Bool), 106 | decls.NewOverload("greater_equals_time", []*expr.Type{Time, Time}, decls.Bool), 107 | decls.NewOverload("greater_equals_datetime", []*expr.Type{DateTime, DateTime}, decls.Bool), 108 | ), 109 | decls.NewFunction(operators.Add, 110 | decls.NewOverload("add_date_int", []*expr.Type{Date, decls.Int}, Date), 111 | decls.NewOverload("add_int_date", []*expr.Type{decls.Int, Date}, Date), 112 | ), 113 | decls.NewFunction(operators.Subtract, 114 | decls.NewOverload("subtract_date_int", []*expr.Type{Date, decls.Int}, Date), 115 | ), 116 | decls.NewFunction(operators.Add, 117 | decls.NewOverload("add_date_interval", []*expr.Type{Date, Interval}, Date), 118 | decls.NewOverload("add_date_duration", []*expr.Type{Date, decls.Duration}, Date), 119 | decls.NewOverload("add_interval_date", []*expr.Type{Interval, Date}, Date), 120 | decls.NewOverload("add_duration_date", []*expr.Type{decls.Duration, Date}, Date), 121 | decls.NewOverload("add_time_interval", []*expr.Type{Time, Interval}, Time), 122 | decls.NewOverload("add_time_duration", []*expr.Type{Time, decls.Duration}, Time), 123 | decls.NewOverload("add_interval_time", []*expr.Type{Interval, Time}, Time), 124 | decls.NewOverload("add_duration_time", []*expr.Type{decls.Duration, Time}, Time), 125 | decls.NewOverload("add_datetime_interval", []*expr.Type{DateTime, Interval}, DateTime), 126 | decls.NewOverload("add_datetime_duration", []*expr.Type{DateTime, decls.Duration}, DateTime), 127 | decls.NewOverload("add_interval_datetime", []*expr.Type{Interval, DateTime}, DateTime), 128 | decls.NewOverload("add_duration_datetime", []*expr.Type{decls.Duration, DateTime}, DateTime), 129 | decls.NewOverload("add_timestamp_interval", []*expr.Type{decls.Timestamp, Interval}, decls.Timestamp), 130 | decls.NewOverload("add_interval_timestamp", []*expr.Type{Interval, decls.Timestamp}, decls.Timestamp), 131 | ), 132 | decls.NewFunction(operators.Subtract, 133 | decls.NewOverload("subtract_date_interval", []*expr.Type{Date, Interval}, Date), 134 | decls.NewOverload("subtract_date_duration", []*expr.Type{Date, decls.Duration}, Date), 135 | decls.NewOverload("subtract_time_interval", []*expr.Type{Time, Interval}, Time), 136 | decls.NewOverload("subtract_time_duration", []*expr.Type{Time, decls.Duration}, Time), 137 | decls.NewOverload("subtract_datetime_interval", []*expr.Type{DateTime, Interval}, DateTime), 138 | decls.NewOverload("subtract_datetime_duration", []*expr.Type{DateTime, decls.Duration}, DateTime), 139 | decls.NewOverload("subtract_timestamp_interval", []*expr.Type{decls.Timestamp, Interval}, decls.Timestamp), 140 | ), 141 | 142 | decls.NewFunction("interval", 143 | decls.NewOverload("interval_construct", []*expr.Type{decls.Int, DatePart}, Interval), 144 | ), 145 | 146 | // https://cloud.google.com/bigquery/docs/reference/standard-sql/date_functions 147 | decls.NewFunction("date", 148 | decls.NewOverload("date_construct_year_month_day", []*expr.Type{decls.Int, decls.Int, decls.Int}, Date), 149 | decls.NewOverload("date_construct_string", []*expr.Type{decls.String}, Date), 150 | ), 151 | decls.NewFunction("current_date", 152 | decls.NewOverload("current_date", []*expr.Type{}, Date), 153 | decls.NewOverload("current_date_timezone", []*expr.Type{decls.String}, Date), 154 | ), 155 | // https://cloud.google.com/bigquery/docs/reference/standard-sql/time_functions 156 | decls.NewFunction("time", 157 | decls.NewOverload("time_construct_hour_minute_second", []*expr.Type{decls.Int, decls.Int, decls.Int}, Time), 158 | decls.NewOverload("time_construct_string", []*expr.Type{decls.String}, Time), 159 | decls.NewOverload("time_construct_datetime", []*expr.Type{DateTime}, Time), 160 | decls.NewOverload("time_construct_timestamp", []*expr.Type{decls.Timestamp}, Time), 161 | decls.NewOverload("time_construct_timestamp_timezone", []*expr.Type{decls.Timestamp, decls.String}, Time), 162 | ), 163 | decls.NewFunction("current_time", 164 | decls.NewOverload("current_time", []*expr.Type{}, Time), 165 | decls.NewOverload("current_time_timezone", []*expr.Type{decls.String}, Time), 166 | ), 167 | // https://cloud.google.com/bigquery/docs/reference/standard-sql/datetime_functions 168 | decls.NewFunction("datetime", 169 | decls.NewOverload("datetime_construct_year_month_day_hour_minute_second", []*expr.Type{decls.Int, decls.Int, decls.Int, decls.Int, decls.Int, decls.Int}, DateTime), 170 | decls.NewOverload("datetime_construct_string", []*expr.Type{decls.String}, DateTime), 171 | decls.NewOverload("datetime_construct_date", []*expr.Type{Date}, DateTime), 172 | decls.NewOverload("datetime_construct_date_time", []*expr.Type{Date, Time}, DateTime), 173 | decls.NewOverload("datetime_construct_timestamp", []*expr.Type{decls.Timestamp}, DateTime), 174 | decls.NewOverload("datetime_construct_timestamp_timezone", []*expr.Type{decls.Timestamp, decls.String}, DateTime), 175 | ), 176 | decls.NewFunction("current_datetime", 177 | decls.NewOverload("current_datetime", []*expr.Type{}, DateTime), 178 | decls.NewOverload("current_datetime_timezone", []*expr.Type{decls.String}, DateTime), 179 | ), 180 | // https://cloud.google.com/bigquery/docs/reference/standard-sql/timestamp_functions 181 | decls.NewFunction("timestamp", 182 | decls.NewOverload("timestamp_construct_string_timezone", []*expr.Type{decls.String, decls.String}, decls.Timestamp), 183 | decls.NewOverload("timestamp_construct_date", []*expr.Type{Date}, decls.Timestamp), 184 | decls.NewOverload("timestamp_construct_date_timezone", []*expr.Type{Date, decls.String}, decls.Timestamp), 185 | decls.NewOverload("timestamp_construct_datetime", []*expr.Type{DateTime}, decls.Timestamp), 186 | decls.NewOverload("timestamp_construct_datetime_timezone", []*expr.Type{DateTime, decls.String}, decls.Timestamp), 187 | ), 188 | decls.NewFunction("current_timestamp", 189 | decls.NewOverload("current_timestamp", []*expr.Type{}, decls.Timestamp), 190 | ), 191 | // https://cloud.google.com/bigquery/docs/reference/standard-sql/string_functions 192 | decls.NewFunction("ascii", 193 | decls.NewOverload("string_ascii", []*expr.Type{decls.String}, decls.Int), 194 | ), 195 | decls.NewFunction("unicode", 196 | decls.NewOverload("string_unicode", []*expr.Type{decls.String}, decls.Int), 197 | ), 198 | decls.NewFunction("chr", 199 | decls.NewOverload("int_chr", []*expr.Type{decls.Int}, decls.String), 200 | ), 201 | decls.NewFunction("code_points_to_bytes", 202 | decls.NewOverload("int_code_points_to_bytes", []*expr.Type{decls.NewListType(decls.Int)}, decls.Bytes), 203 | ), 204 | decls.NewFunction("code_points_to_string", 205 | decls.NewOverload("int_code_points_to_string", []*expr.Type{decls.NewListType(decls.Int)}, decls.String), 206 | ), 207 | decls.NewFunction("to_code_points", 208 | decls.NewOverload("string_to_code_points", []*expr.Type{decls.String}, decls.NewListType(decls.Int)), 209 | decls.NewOverload("bytes_to_code_points", []*expr.Type{decls.Bytes}, decls.NewListType(decls.Int)), 210 | ), 211 | decls.NewFunction("from_base32", 212 | decls.NewOverload("string_from_base32", []*expr.Type{decls.String}, decls.Bytes), 213 | ), 214 | decls.NewFunction("to_base32", 215 | decls.NewOverload("bytes_to_base32", []*expr.Type{decls.Bytes}, decls.String), 216 | ), 217 | decls.NewFunction("from_base64", 218 | decls.NewOverload("string_from_base64", []*expr.Type{decls.String}, decls.Bytes), 219 | ), 220 | decls.NewFunction("to_base64", 221 | decls.NewOverload("bytes_to_base64", []*expr.Type{decls.Bytes}, decls.String), 222 | ), 223 | decls.NewFunction("from_hex", 224 | decls.NewOverload("string_from_hex", []*expr.Type{decls.String}, decls.Bytes), 225 | ), 226 | decls.NewFunction("to_hex", 227 | decls.NewOverload("bytes_to_hex", []*expr.Type{decls.Bytes}, decls.String), 228 | ), 229 | decls.NewFunction("split", 230 | decls.NewOverload("string_split", []*expr.Type{decls.String}, decls.NewListType(decls.String)), 231 | decls.NewOverload("string_split_delimiters", []*expr.Type{decls.String, decls.String}, decls.NewListType(decls.String)), 232 | decls.NewOverload("bytes_split_delimiters", []*expr.Type{decls.Bytes, decls.Bytes}, decls.NewListType(decls.Bytes)), 233 | ), 234 | decls.NewFunction("lower", 235 | decls.NewOverload("string_lower", []*expr.Type{decls.String}, decls.String), 236 | decls.NewOverload("bytes_lower", []*expr.Type{decls.Bytes}, decls.Bytes), 237 | ), 238 | decls.NewFunction("upper", 239 | decls.NewOverload("string_upper", []*expr.Type{decls.String}, decls.String), 240 | decls.NewOverload("bytes_upper", []*expr.Type{decls.Bytes}, decls.Bytes), 241 | ), 242 | decls.NewFunction("initcap", 243 | decls.NewOverload("string_initcap", []*expr.Type{decls.String}, decls.String), 244 | decls.NewOverload("string_initcap_delimiters", []*expr.Type{decls.String, decls.String}, decls.String), 245 | ), 246 | decls.NewFunction("instr", 247 | decls.NewOverload("string_instr", []*expr.Type{decls.String, decls.String}, decls.Int), 248 | decls.NewOverload("string_instr_position", []*expr.Type{decls.String, decls.String, decls.Int}, decls.Int), 249 | decls.NewOverload("string_instr_position_occurrence", []*expr.Type{decls.String, decls.String, decls.Int, decls.Int}, decls.Int), 250 | decls.NewOverload("bytes_instr", []*expr.Type{decls.Bytes, decls.Bytes}, decls.Int), 251 | decls.NewOverload("bytes_instr_position", []*expr.Type{decls.Bytes, decls.Bytes, decls.Int}, decls.Int), 252 | decls.NewOverload("bytes_instr_position_occurrence", []*expr.Type{decls.Bytes, decls.Bytes, decls.Int, decls.Int}, decls.Int), 253 | ), 254 | decls.NewFunction("strpos", 255 | decls.NewOverload("string_strpos", []*expr.Type{decls.String, decls.String}, decls.Int), 256 | decls.NewOverload("bytes_strpos", []*expr.Type{decls.Bytes, decls.Bytes}, decls.Int), 257 | ), 258 | decls.NewFunction("left", 259 | decls.NewOverload("string_left", []*expr.Type{decls.String, decls.Int}, decls.String), 260 | decls.NewOverload("bytes_left", []*expr.Type{decls.Bytes, decls.Int}, decls.Bytes), 261 | ), 262 | decls.NewFunction("right", 263 | decls.NewOverload("string_right", []*expr.Type{decls.String, decls.Int}, decls.String), 264 | decls.NewOverload("bytes_right", []*expr.Type{decls.Bytes, decls.Int}, decls.Bytes), 265 | ), 266 | decls.NewFunction("substr", 267 | decls.NewOverload("string_substr", []*expr.Type{decls.String, decls.Int}, decls.String), 268 | decls.NewOverload("string_substr_length", []*expr.Type{decls.String, decls.Int, decls.Int}, decls.String), 269 | decls.NewOverload("bytes_substr", []*expr.Type{decls.Bytes, decls.Int}, decls.Bytes), 270 | decls.NewOverload("bytes_substr_length", []*expr.Type{decls.Bytes, decls.Int, decls.Int}, decls.Bytes), 271 | ), 272 | decls.NewFunction("lpad", 273 | decls.NewOverload("string_lpad", []*expr.Type{decls.String, decls.Int}, decls.String), 274 | decls.NewOverload("string_lpad_pattern", []*expr.Type{decls.String, decls.Int, decls.String}, decls.String), 275 | decls.NewOverload("bytes_lpad", []*expr.Type{decls.Bytes, decls.Int}, decls.Bytes), 276 | decls.NewOverload("bytes_lpad_pattern", []*expr.Type{decls.Bytes, decls.Int, decls.Bytes}, decls.Bytes), 277 | ), 278 | decls.NewFunction("rpad", 279 | decls.NewOverload("string_rpad", []*expr.Type{decls.String, decls.Int}, decls.String), 280 | decls.NewOverload("string_rpad_pattern", []*expr.Type{decls.String, decls.Int, decls.String}, decls.String), 281 | decls.NewOverload("bytes_rpad", []*expr.Type{decls.Bytes, decls.Int}, decls.Bytes), 282 | decls.NewOverload("bytes_rpad_pattern", []*expr.Type{decls.Bytes, decls.Int, decls.Bytes}, decls.Bytes), 283 | ), 284 | decls.NewFunction("ltrim", 285 | decls.NewOverload("string_ltrim", []*expr.Type{decls.String}, decls.String), 286 | decls.NewOverload("string_ltrim_pattern", []*expr.Type{decls.String, decls.String}, decls.String), 287 | decls.NewOverload("bytes_ltrim_pattern", []*expr.Type{decls.Bytes, decls.Bytes}, decls.Bytes), 288 | ), 289 | decls.NewFunction("rtrim", 290 | decls.NewOverload("string_rtrim", []*expr.Type{decls.String}, decls.String), 291 | decls.NewOverload("string_rtrim_pattern", []*expr.Type{decls.String, decls.String}, decls.String), 292 | decls.NewOverload("bytes_rtrim_pattern", []*expr.Type{decls.Bytes, decls.Bytes}, decls.Bytes), 293 | ), 294 | decls.NewFunction("trim", 295 | decls.NewOverload("string_trim", []*expr.Type{decls.String}, decls.String), 296 | decls.NewOverload("string_trim_pattern", []*expr.Type{decls.String, decls.String}, decls.String), 297 | decls.NewOverload("bytes_trim_pattern", []*expr.Type{decls.Bytes, decls.Bytes}, decls.Bytes), 298 | ), 299 | decls.NewFunction("regexp_extract", 300 | decls.NewOverload("string_regexp_extract", []*expr.Type{decls.String, decls.String}, decls.String), 301 | decls.NewOverload("string_regexp_extract_position", []*expr.Type{decls.String, decls.String, decls.Int}, decls.String), 302 | decls.NewOverload("string_regexp_extract_position_occurrence", []*expr.Type{decls.String, decls.String, decls.Int, decls.Int}, decls.String), 303 | ), 304 | decls.NewFunction("regexp_extract_all", 305 | decls.NewOverload("string_regexp_extract_all", []*expr.Type{decls.String, decls.String}, decls.NewListType(decls.String)), 306 | ), 307 | decls.NewFunction("regexp_instr", 308 | decls.NewOverload("string_regexp_instr", []*expr.Type{decls.String, decls.String}, decls.Int), 309 | decls.NewOverload("string_regexp_instr_position", []*expr.Type{decls.String, decls.String, decls.Int}, decls.Int), 310 | decls.NewOverload("string_regexp_instr_position_occurrence", []*expr.Type{decls.String, decls.String, decls.Int, decls.Int}, decls.Int), 311 | decls.NewOverload("string_regexp_instr_position_occurrence_occurrence_position", []*expr.Type{decls.String, decls.String, decls.Int, decls.Int, decls.Int}, decls.Int), 312 | ), 313 | decls.NewFunction("regexp_replace", 314 | decls.NewOverload("string_regexp_replace", []*expr.Type{decls.String, decls.String, decls.String}, decls.String), 315 | ), 316 | decls.NewFunction("replace", 317 | decls.NewOverload("string_replace", []*expr.Type{decls.String, decls.String, decls.String}, decls.String), 318 | decls.NewOverload("bytes_replace", []*expr.Type{decls.Bytes, decls.Bytes, decls.Bytes}, decls.Bytes), 319 | ), 320 | decls.NewFunction("translate", 321 | decls.NewOverload("string_translate", []*expr.Type{decls.String, decls.String, decls.String}, decls.String), 322 | decls.NewOverload("bytes_translate", []*expr.Type{decls.Bytes, decls.Bytes, decls.Bytes}, decls.Bytes), 323 | ), 324 | decls.NewFunction("repeat", 325 | decls.NewOverload("string_repeat", []*expr.Type{decls.String, decls.Int}, decls.String), 326 | decls.NewOverload("bytes_repeat", []*expr.Type{decls.Bytes, decls.Int}, decls.Bytes), 327 | ), 328 | decls.NewFunction("reverse", 329 | decls.NewOverload("string_reverse", []*expr.Type{decls.String}, decls.String), 330 | decls.NewOverload("bytes_reverse", []*expr.Type{decls.Bytes}, decls.Bytes), 331 | ), 332 | decls.NewFunction("safe_convert_bytes_to_string", 333 | decls.NewOverload("bytes_safe_convert_bytes_to_string", []*expr.Type{decls.Bytes}, decls.String), 334 | ), 335 | decls.NewFunction("soundex", 336 | decls.NewOverload("bytes_soundex", []*expr.Type{decls.String}, decls.String), 337 | ), 338 | ) 339 | -------------------------------------------------------------------------------- /test/testdata.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "time" 5 | 6 | "cloud.google.com/go/bigquery" 7 | ) 8 | 9 | func NewTrigramsTableMetadata() *bigquery.TableMetadata { 10 | return &bigquery.TableMetadata{ 11 | Name: "", 12 | Location: "US", 13 | Description: "", 14 | Schema: bigquery.Schema{ 15 | &bigquery.FieldSchema{ 16 | Name: "ngram", 17 | Description: "", 18 | Repeated: false, 19 | Required: false, 20 | Type: "STRING", 21 | PolicyTags: nil, 22 | Schema: nil, 23 | }, 24 | &bigquery.FieldSchema{ 25 | Name: "first", 26 | Description: "", 27 | Repeated: false, 28 | Required: false, 29 | Type: "STRING", 30 | PolicyTags: nil, 31 | Schema: nil, 32 | }, 33 | &bigquery.FieldSchema{ 34 | Name: "second", 35 | Description: "", 36 | Repeated: false, 37 | Required: false, 38 | Type: "STRING", 39 | PolicyTags: nil, 40 | Schema: nil, 41 | }, 42 | &bigquery.FieldSchema{ 43 | Name: "third", 44 | Description: "", 45 | Repeated: false, 46 | Required: false, 47 | Type: "STRING", 48 | PolicyTags: nil, 49 | Schema: nil, 50 | }, 51 | &bigquery.FieldSchema{ 52 | Name: "fourth", 53 | Description: "", 54 | Repeated: false, 55 | Required: false, 56 | Type: "STRING", 57 | PolicyTags: nil, 58 | Schema: nil, 59 | }, 60 | &bigquery.FieldSchema{ 61 | Name: "fifth", 62 | Description: "", 63 | Repeated: false, 64 | Required: false, 65 | Type: "STRING", 66 | PolicyTags: nil, 67 | Schema: nil, 68 | }, 69 | &bigquery.FieldSchema{ 70 | Name: "cell", 71 | Description: "", 72 | Repeated: true, 73 | Required: false, 74 | Type: "RECORD", 75 | PolicyTags: nil, 76 | Schema: bigquery.Schema{ 77 | &bigquery.FieldSchema{ 78 | Name: "value", 79 | Description: "", 80 | Repeated: true, 81 | Required: false, 82 | Type: "STRING", 83 | PolicyTags: nil, 84 | Schema: nil, 85 | }, 86 | &bigquery.FieldSchema{ 87 | Name: "volume_count", 88 | Description: "", 89 | Repeated: false, 90 | Required: false, 91 | Type: "INTEGER", 92 | PolicyTags: nil, 93 | Schema: nil, 94 | }, 95 | &bigquery.FieldSchema{ 96 | Name: "volume_fraction", 97 | Description: "", 98 | Repeated: false, 99 | Required: false, 100 | Type: "FLOAT", 101 | PolicyTags: nil, 102 | Schema: nil, 103 | }, 104 | &bigquery.FieldSchema{ 105 | Name: "page_count", 106 | Description: "", 107 | Repeated: false, 108 | Required: false, 109 | Type: "INTEGER", 110 | PolicyTags: nil, 111 | Schema: nil, 112 | }, 113 | &bigquery.FieldSchema{ 114 | Name: "match_count", 115 | Description: "", 116 | Repeated: false, 117 | Required: false, 118 | Type: "INTEGER", 119 | PolicyTags: nil, 120 | Schema: nil, 121 | }, 122 | &bigquery.FieldSchema{ 123 | Name: "sample", 124 | Description: "", 125 | Repeated: true, 126 | Required: false, 127 | Type: "RECORD", 128 | PolicyTags: nil, 129 | Schema: bigquery.Schema{ 130 | &bigquery.FieldSchema{ 131 | Name: "id", 132 | Description: "", 133 | Repeated: false, 134 | Required: false, 135 | Type: "STRING", 136 | PolicyTags: nil, 137 | Schema: nil, 138 | }, 139 | &bigquery.FieldSchema{ 140 | Name: "text", 141 | Description: "", 142 | Repeated: false, 143 | Required: false, 144 | Type: "STRING", 145 | PolicyTags: nil, 146 | Schema: nil, 147 | }, 148 | &bigquery.FieldSchema{ 149 | Name: "title", 150 | Description: "", 151 | Repeated: false, 152 | Required: false, 153 | Type: "STRING", 154 | PolicyTags: nil, 155 | Schema: nil, 156 | }, 157 | &bigquery.FieldSchema{ 158 | Name: "subtitle", 159 | Description: "", 160 | Repeated: false, 161 | Required: false, 162 | Type: "STRING", 163 | PolicyTags: nil, 164 | Schema: nil, 165 | }, 166 | &bigquery.FieldSchema{ 167 | Name: "authors", 168 | Description: "", 169 | Repeated: false, 170 | Required: false, 171 | Type: "STRING", 172 | PolicyTags: nil, 173 | Schema: nil, 174 | }, 175 | &bigquery.FieldSchema{ 176 | Name: "url", 177 | Description: "", 178 | Repeated: false, 179 | Required: false, 180 | Type: "STRING", 181 | PolicyTags: nil, 182 | Schema: nil, 183 | }, 184 | }, 185 | }, 186 | }, 187 | }, 188 | }, 189 | MaterializedView: nil, 190 | ViewQuery: "", 191 | UseLegacySQL: false, 192 | UseStandardSQL: false, 193 | TimePartitioning: nil, 194 | RangePartitioning: nil, 195 | RequirePartitionFilter: false, 196 | Clustering: nil, 197 | ExpirationTime: time.Now(), 198 | Labels: nil, 199 | ExternalDataConfig: nil, 200 | EncryptionConfig: nil, 201 | FullID: "bigquery-public-data:samples.trigrams", 202 | Type: "TABLE", 203 | CreationTime: time.Now(), 204 | LastModifiedTime: time.Now(), 205 | NumBytes: 277168458677, 206 | NumLongTermBytes: 277168458677, 207 | NumRows: 0x40e6235, 208 | StreamingBuffer: nil, 209 | ETag: "coBH0z/sk1ardM9lC1MCMw==", 210 | } 211 | } 212 | 213 | func NewWikipediaTableMetadata() *bigquery.TableMetadata { 214 | return &bigquery.TableMetadata{ 215 | Name: "", 216 | Location: "US", 217 | Description: "", 218 | Schema: bigquery.Schema{ 219 | &bigquery.FieldSchema{ 220 | Name: "title", 221 | Description: "The title of the page, as displayed on the page (not in the URL). Always starts with a capital letter and may begin with a namespace (e.g. \"Talk:\", \"User:\", \"User Talk:\", ... )", 222 | Repeated: false, 223 | Required: true, 224 | Type: "STRING", 225 | PolicyTags: nil, 226 | Schema: nil, 227 | }, 228 | &bigquery.FieldSchema{ 229 | Name: "id", 230 | Description: "A unique ID for the article that was revised. These correspond to the order in which articles were created, except for the first several thousand IDs, which are issued in alphabetical order.", 231 | Repeated: false, 232 | Required: false, 233 | Type: "INTEGER", 234 | PolicyTags: nil, 235 | Schema: nil, 236 | }, 237 | &bigquery.FieldSchema{ 238 | Name: "language", 239 | Description: "Empty in the current dataset.", 240 | Repeated: false, 241 | Required: true, 242 | Type: "STRING", 243 | PolicyTags: nil, 244 | Schema: nil, 245 | }, 246 | &bigquery.FieldSchema{ 247 | Name: "wp_namespace", 248 | Description: "Wikipedia segments its pages into namespaces (e.g. \"Talk\", \"User\", etc.)\n\nMEDIA = 202; // =-2 in WP XML, but these values must be >0\nSPECIAL = 201; // =-1 in WP XML, but these values must be >0\nMAIN = 0;\nTALK = 1;\nUSER = 2;\nUSER_TALK = 3;\nWIKIPEDIA = 4;\nWIKIPEDIA_TALK = 5;\nIMAGE = 6; // Has since been renamed to \"File\" in WP XML.\nIMAGE_TALK = 7; // Equivalent to \"File talk\".\nMEDIAWIKI = 8;\nMEDIAWIKI_TALK = 9;\nTEMPLATE = 10;\nTEMPLATE_TALK = 11;\nHELP = 12;\nHELP_TALK = 13;\nCATEGORY = 14;\nCATEGORY_TALK = 15;\nPORTAL = 100;\nPORTAL_TALK = 101;\nWIKIPROJECT = 102;\nWIKIPROJECT_TALK = 103;\nREFERENCE = 104;\nREFERENCE_TALK = 105;\nBOOK = 108;\nBOOK_TALK = 109;", 249 | Repeated: false, 250 | Required: true, 251 | Type: "INTEGER", 252 | PolicyTags: nil, 253 | Schema: nil, 254 | }, 255 | &bigquery.FieldSchema{ 256 | Name: "is_redirect", 257 | Description: "Versions later than ca. 200908 may have a redirection marker in the XML.", 258 | Repeated: false, 259 | Required: false, 260 | Type: "BOOLEAN", 261 | PolicyTags: nil, 262 | Schema: nil, 263 | }, 264 | &bigquery.FieldSchema{ 265 | Name: "revision_id", 266 | Description: "These are unique across all revisions to all pages in a particular language and increase with time. Sorting the revisions to a page by revision_id will yield them in chronological order.", 267 | Repeated: false, 268 | Required: false, 269 | Type: "INTEGER", 270 | PolicyTags: nil, 271 | Schema: nil, 272 | }, 273 | &bigquery.FieldSchema{ 274 | Name: "contributor_ip", 275 | Description: "Typically, either _ip or (_id and _username) will be set. IP information is unavailable for edits from registered accounts. A (very) small fraction of edits have neither _ip or (_id and _username). They show up on Wikipedia as \"(Username or IP removed)\".", 276 | Repeated: false, 277 | Required: false, 278 | Type: "STRING", 279 | PolicyTags: nil, 280 | Schema: nil, 281 | }, 282 | &bigquery.FieldSchema{ 283 | Name: "contributor_id", 284 | Description: "Typically, either (_id and _username) or _ip will be set. A (very) small fraction of edits have neither _ip or (_id and _username). They show up on Wikipedia as \"(Username or IP removed)\".", 285 | Repeated: false, 286 | Required: false, 287 | Type: "INTEGER", 288 | PolicyTags: nil, 289 | Schema: nil, 290 | }, 291 | &bigquery.FieldSchema{ 292 | Name: "contributor_username", 293 | Description: "Typically, either (_id and _username) or _ip will be set. A (very) small fraction of edits have neither _ip or (_id and _username). They show up on Wikipedia as \"(Username or IP removed)\".", 294 | Repeated: false, 295 | Required: false, 296 | Type: "STRING", 297 | PolicyTags: nil, 298 | Schema: nil, 299 | }, 300 | &bigquery.FieldSchema{ 301 | Name: "timestamp", 302 | Description: "In Unix time, seconds since epoch.", 303 | Repeated: false, 304 | Required: true, 305 | Type: "INTEGER", 306 | PolicyTags: nil, 307 | Schema: nil, 308 | }, 309 | &bigquery.FieldSchema{ 310 | Name: "is_minor", 311 | Description: "Corresponds to the \"Minor Edit\" checkbox on Wikipedia's edit page.", 312 | Repeated: false, 313 | Required: false, 314 | Type: "BOOLEAN", 315 | PolicyTags: nil, 316 | Schema: nil, 317 | }, 318 | &bigquery.FieldSchema{ 319 | Name: "is_bot", 320 | Description: "A special flag that some of Wikipedia's more active bots voluntarily set.", 321 | Repeated: false, 322 | Required: false, 323 | Type: "BOOLEAN", 324 | PolicyTags: nil, 325 | Schema: nil, 326 | }, 327 | &bigquery.FieldSchema{ 328 | Name: "reversion_id", 329 | Description: "If this edit is a reversion to a previous edit, this field records the revision_id that was reverted to. If the same article text occurred multiple times, then this will point to the earliest revision. Only revisions with greater than fifty characters are considered for this field. This is to avoid labeling multiple blankings as reversions.", 330 | Repeated: false, 331 | Required: false, 332 | Type: "INTEGER", 333 | PolicyTags: nil, 334 | Schema: nil, 335 | }, 336 | &bigquery.FieldSchema{ 337 | Name: "comment", 338 | Description: "Optional user-supplied description of the edit. Section edits are, by default, prefixed with \"/* Section Name */ \".", 339 | Repeated: false, 340 | Required: false, 341 | Type: "STRING", 342 | PolicyTags: nil, 343 | Schema: nil, 344 | }, 345 | &bigquery.FieldSchema{ 346 | Name: "num_characters", 347 | Description: "The length of the article after the revision was applied.", 348 | Repeated: false, 349 | Required: true, 350 | Type: "INTEGER", 351 | PolicyTags: nil, 352 | Schema: nil, 353 | }, 354 | }, 355 | MaterializedView: nil, 356 | ViewQuery: "", 357 | UseLegacySQL: false, 358 | UseStandardSQL: false, 359 | TimePartitioning: nil, 360 | RangePartitioning: nil, 361 | RequirePartitionFilter: false, 362 | Clustering: nil, 363 | ExpirationTime: time.Time{}, 364 | Labels: nil, 365 | ExternalDataConfig: nil, 366 | EncryptionConfig: nil, 367 | FullID: "bigquery-public-data:samples.wikipedia", 368 | Type: "TABLE", 369 | CreationTime: time.Now(), 370 | LastModifiedTime: time.Now(), 371 | NumBytes: 38324173849, 372 | NumLongTermBytes: 38324173849, 373 | NumRows: 0x12b429ab, 374 | StreamingBuffer: nil, 375 | ETag: "banEhEDm4Cu2wGJcfhspUg==", 376 | } 377 | } 378 | --------------------------------------------------------------------------------