├── .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 | Symbol |
67 | Type |
68 | SQL |
69 |
70 |
71 |
72 | !_
73 | |
74 |
75 | (bool) -> bool
76 | |
77 |
78 | NOT bool
79 | |
80 |
81 |
82 |
83 | -_
84 | |
85 |
86 | (int) -> int
87 | |
88 |
89 | - int
90 | |
91 |
92 |
93 |
94 | (double) -> double
95 | |
96 |
97 | - double
98 | |
99 |
100 |
101 |
102 | _!=_
103 | |
104 |
105 | (A, A) -> bool
106 | |
107 |
108 | A != A
109 | |
110 |
111 |
112 |
113 | (bool, bool) -> bool
114 | |
115 |
116 | bool IS NOT bool
117 | |
118 |
119 |
120 |
121 | (A, null) -> bool
122 | |
123 |
124 | A IS NOT NULL
125 | |
126 |
127 |
128 |
129 | _%_
130 | |
131 |
132 | (int, int) -> int
133 | |
134 |
135 | MOD( int, int)
136 | |
137 |
138 |
139 |
140 | _&&_
141 | |
142 |
143 | (bool, bool) -> bool
144 | |
145 |
146 | bool AND bool
147 | |
148 |
149 |
150 |
151 | _*_
152 | |
153 |
154 | (int, int) -> int
155 | |
156 |
157 | int * int
158 | |
159 |
160 |
161 |
162 | (double, double) -> double
163 | |
164 |
165 | double * double
166 | |
167 |
168 |
169 |
170 | _+_
171 | |
172 |
173 | (int, int) -> int
174 | |
175 |
176 | int + int
177 | |
178 |
179 |
180 |
181 | (double, double) -> double
182 | |
183 |
184 | double + double
185 | |
186 |
187 |
188 |
189 | (string, string) -> string
190 | |
191 |
192 | string || string
193 | |
194 |
195 |
196 |
197 | (bytes, bytes) -> bytes
198 | |
199 |
200 | bytes || bytes
201 | |
202 |
203 |
204 |
205 | (list(A), list(A)) -> list(A)
206 | |
207 |
208 | list(A) || list(A)
209 | |
210 |
211 |
212 |
213 | (google.protobuf.Timestamp, google.protobuf.Duration) -> google.protobuf.Timestamp
214 | |
215 |
216 | TIMESTAMP_ADD( timestamp, INTERVAL duration date_part)
217 | |
218 |
219 |
220 |
221 | (google.protobuf.Duration, google.protobuf.Timestamp) -> google.protobuf.Timestamp
222 | |
223 |
224 | TIMESTAMP_ADD( timestamp, INTERVAL duration date_part)
225 | |
226 |
227 |
228 |
229 | _-_
230 | |
231 |
232 | (int, int) -> int
233 | |
234 |
235 | int - int
236 | |
237 |
238 |
239 |
240 | (double, double) -> double
241 | |
242 |
243 | double - double
244 | |
245 |
246 |
247 |
248 | (google.protobuf.Timestamp, google.protobuf.Duration) -> google.protobuf.Timestamp
249 | |
250 |
251 | TIMESTAMP_SUB( timestamp, INTERVAL duration date_part)
252 | |
253 |
254 |
255 |
256 | _/_
257 | |
258 |
259 | (int, int) -> int
260 | |
261 |
262 | int / int
263 | |
264 |
265 |
266 |
267 | (double, double) -> double
268 | |
269 |
270 | double / double
271 | |
272 |
273 |
274 |
275 | _<=_
276 | |
277 |
278 | (bool, bool) -> bool
279 | |
280 |
281 | bool <= bool
282 | |
283 |
284 |
285 |
286 | (int, int) -> bool
287 | |
288 |
289 | int <= int
290 | |
291 |
292 |
293 |
294 | (double, double) -> bool
295 | |
296 |
297 | double <= double
298 | |
299 |
300 |
301 |
302 | (string, string) -> bool
303 | |
304 |
305 | string <= string
306 | |
307 |
308 |
309 |
310 | (bytes, bytes) -> bool
311 | |
312 |
313 | bytes <= bytes
314 | |
315 |
316 |
317 |
318 | (google.protobuf.Timestamp, google.protobuf.Timestamp) -> bool
319 | |
320 |
321 | timestamp <= timestamp
322 | |
323 |
324 |
325 |
326 | _<_
327 | |
328 |
329 | (bool, bool) -> bool
330 | |
331 |
332 | bool < bool
333 | |
334 |
335 |
336 |
337 | (int, int) -> bool
338 | |
339 |
340 | int < int
341 | |
342 |
343 |
344 |
345 | (double, double) -> bool
346 | |
347 |
348 | double < double
349 | |
350 |
351 |
352 |
353 | (string, string) -> bool
354 | |
355 |
356 | string < string
357 | |
358 |
359 |
360 |
361 | (bytes, bytes) -> bool
362 | |
363 |
364 | bytes < bytes
365 | |
366 |
367 |
368 |
369 | (google.protobuf.Timestamp, google.protobuf.Timestamp) -> bool
370 | |
371 |
372 | timestamp < timestamp
373 | |
374 |
375 |
376 |
377 | _==_
378 | |
379 |
380 | (A, A) -> bool
381 | |
382 |
383 | A = A
384 | |
385 |
386 |
387 |
388 | (bool, bool) -> bool
389 | |
390 |
391 | A IS A
392 | |
393 |
394 |
395 |
396 | (A, null) -> bool
397 | |
398 |
399 | A IS NULL
400 | |
401 |
402 |
403 |
404 | _>=_
405 | |
406 |
407 | (bool, bool) -> bool
408 | |
409 |
410 | bool >= bool
411 | |
412 |
413 |
414 |
415 | (int, int) -> bool
416 | |
417 |
418 | int >= int
419 | |
420 |
421 |
422 |
423 | (double, double) -> bool
424 | |
425 |
426 | double >= double
427 | |
428 |
429 |
430 |
431 | (string, string) -> bool
432 | |
433 |
434 | string >= string
435 | |
436 |
437 |
438 |
439 | (bytes, bytes) -> bool
440 | |
441 |
442 | bytes >= bytes
443 | |
444 |
445 |
446 |
447 | (google.protobuf.Timestamp, google.protobuf.Timestamp) -> bool
448 | |
449 |
450 | timestamp >= timestamp
451 | |
452 |
453 |
454 |
455 | _>_
456 | |
457 |
458 | (bool, bool) -> bool
459 | |
460 |
461 | bool > bool
462 | |
463 |
464 |
465 |
466 | (int, int) -> bool
467 | |
468 |
469 | int > int
470 | |
471 |
472 |
473 |
474 | (double, double) -> bool
475 | |
476 |
477 | double > double
478 | |
479 |
480 |
481 |
482 | (string, string) -> bool
483 | |
484 |
485 | string > string
486 | |
487 |
488 |
489 |
490 | (bytes, bytes) -> bool
491 | |
492 |
493 | bytes > bytes
494 | |
495 |
496 |
497 |
498 | (google.protobuf.Timestamp, google.protobuf.Timestamp) -> bool
499 | |
500 |
501 | timestamp > timestamp
502 | |
503 |
504 |
505 |
506 | _?_:_
507 | |
508 |
509 | (bool, A, A) -> A
510 | |
511 |
512 | IF( bool, A, A)
513 | |
514 |
515 |
516 |
517 | _[_]
518 | |
519 |
520 | (list(A), int) -> A
521 | |
522 |
523 | list[OFFSET( int)]
524 | |
525 |
526 |
527 |
528 | (map(A, B), A) -> B
529 | |
530 |
531 | map.` A`
532 | |
533 |
534 |
535 |
536 | in
537 | |
538 |
539 | (A, list(A)) -> bool
540 | |
541 |
542 | A IN UNNEST( list)
543 | |
544 |
545 |
546 |
547 | _||_
548 | |
549 |
550 | (bool, bool) -> bool
551 | |
552 |
553 | bool OR bool
554 | |
555 |
556 |
557 |
558 | bool
559 | |
560 |
561 | (int) -> bool
562 | |
563 |
564 | CAST( int AS BOOL)
565 | |
566 |
567 |
568 |
569 | (string) -> bool
570 | |
571 |
572 | CAST( string AS BOOL)
573 | |
574 |
575 |
576 |
577 | bytes
578 | |
579 |
580 | (string) -> bytes
581 | |
582 |
583 | CAST( stringAS BYTES)
584 | |
585 |
586 |
587 |
588 | contains
589 | |
590 |
591 | string.(string) -> bool
592 | |
593 |
594 | INSTR( string, string) != 0
595 | |
596 |
597 |
598 |
599 | double
600 | |
601 |
602 | (int) -> double
603 | |
604 |
605 | CAST( int AS FLOAT64)
606 | |
607 |
608 |
609 |
610 | (string) -> double
611 | |
612 |
613 | CAST( string AS FLOAT64)
614 | |
615 |
616 |
617 |
618 | duration
619 | |
620 |
621 | (string) -> google.protobuf.Duration
622 | |
623 |
624 | INTERVAL duration date_part
625 | |
626 |
627 |
628 |
629 | endsWith
630 | |
631 |
632 | string.(string) -> bool
633 | |
634 |
635 | ENDS_WITH( string, string)
636 | |
637 |
638 |
639 |
640 | getDate
641 | |
642 |
643 | google.protobuf.Timestamp.() -> int
644 | |
645 |
646 | EXTRACT(DAY FROM timestamp)
647 | |
648 |
649 |
650 |
651 | google.protobuf.Timestamp.(string) -> int
652 | |
653 |
654 | EXTRACT(DAY FROM timestamp AT string)
655 | |
656 |
657 |
658 |
659 | getDayOfMonth
660 | |
661 |
662 | google.protobuf.Timestamp.() -> int
663 | |
664 |
665 | EXTRACT(DAY FROM timestamp) - 1
666 | |
667 |
668 |
669 |
670 | google.protobuf.Timestamp.(string) -> int
671 | |
672 |
673 | EXTRACT(DAY FROM timestamp AT string) - 1
674 | |
675 |
676 |
677 |
678 | getDayOfWeek
679 | |
680 |
681 | google.protobuf.Timestamp.() -> int
682 | |
683 |
684 | EXTRACT(DAYOFWEEK FROM timestamp) - 1
685 | |
686 |
687 |
688 |
689 | google.protobuf.Timestamp.(string) -> int
690 | |
691 |
692 | EXTRACT(DAYOFWEEK FROM timestamp AT string) - 1
693 | |
694 |
695 |
696 |
697 | getDayOfYear
698 | |
699 |
700 | google.protobuf.Timestamp.() -> int
701 | |
702 |
703 | EXTRACT(DAYOFYEAR FROM timestamp) - 1
704 | |
705 |
706 |
707 |
708 | google.protobuf.Timestamp.(string) -> int
709 | |
710 |
711 | EXTRACT(DAYOFYEAR FROM timestamp AT string) - 1
712 | |
713 |
714 |
715 |
716 | getFullYear
717 | |
718 |
719 | google.protobuf.Timestamp.() -> int
720 | |
721 |
722 | EXTRACT(YEAR FROM timestamp)
723 | |
724 |
725 |
726 |
727 | google.protobuf.Timestamp.(string) -> int
728 | |
729 |
730 | EXTRACT(YEAR FROM timestamp AT string)
731 | |
732 |
733 |
734 |
735 | getHours
736 | |
737 |
738 | google.protobuf.Timestamp.() -> int
739 | |
740 |
741 | EXTRACT(HOUR FROM timestamp)
742 | |
743 |
744 |
745 |
746 | google.protobuf.Timestamp.(string) -> int
747 | |
748 |
749 | EXTRACT(HOUR FROM timestamp AT string)
750 | |
751 |
752 |
753 |
754 | getMilliseconds
755 | |
756 |
757 | google.protobuf.Timestamp.() -> int
758 | |
759 |
760 | EXTRACT(MILLISECOND FROM timestamp)
761 | |
762 |
763 |
764 |
765 | google.protobuf.Timestamp.(string) -> int
766 | |
767 |
768 | EXTRACT(MILLISECOND FROM timestamp AT string)
769 | |
770 |
771 |
772 |
773 | getMinutes
774 | |
775 |
776 | google.protobuf.Timestamp.() -> int
777 | |
778 |
779 | EXTRACT(MINUTE FROM timestamp)
780 | |
781 |
782 |
783 |
784 | google.protobuf.Timestamp.(string) -> int
785 | |
786 |
787 | EXTRACT(MINUTE FROM timestamp AT string)
788 | |
789 |
790 |
791 |
792 | getMonth
793 | |
794 |
795 | google.protobuf.Timestamp.() -> int
796 | |
797 |
798 | EXTRACT(MONTH FROM timestamp) - 1
799 | |
800 |
801 |
802 |
803 | google.protobuf.Timestamp.(string) -> int
804 | |
805 |
806 | EXTRACT(MONTH FROM timestamp AT string) - 1
807 | |
808 |
809 |
810 |
811 | getSeconds
812 | |
813 |
814 | google.protobuf.Timestamp.() -> int
815 | |
816 |
817 | EXTRACT(SECOND FROM timestamp)
818 | |
819 |
820 |
821 |
822 | google.protobuf.Timestamp.(string) -> int
823 | |
824 |
825 | EXTRACT(SECOND FROM timestamp AT string)
826 | |
827 |
828 |
829 |
830 | int
831 | |
832 |
833 | (bool) -> int
834 | |
835 |
836 | CAST( bool AS INT64)
837 | |
838 |
839 |
840 |
841 | (double) -> int
842 | |
843 |
844 | CAST( double AS INT64)
845 | |
846 |
847 |
848 |
849 | (string) -> int
850 | |
851 |
852 | CAST( string AS INT64)
853 | |
854 |
855 |
856 |
857 | (google.protobuf.Timestamp) -> int
858 | |
859 |
860 | UNIX_SECONDS( timestamp)
861 | |
862 |
863 |
864 |
865 | matches
866 | |
867 |
868 | string.(string) -> bool
869 | |
870 |
871 | REGEXP_CONTAINS( string, string)
872 | |
873 |
874 |
875 |
876 | size
877 | |
878 |
879 | (string) -> int
880 | |
881 |
882 | CHAR_LENGTH( string)
883 | |
884 |
885 |
886 |
887 | (bytes) -> int
888 | |
889 |
890 | BYTE_LENGTH( bytes)
891 | |
892 |
893 |
894 |
895 | (list(A)) -> int
896 | |
897 |
898 | ARRAY_LENGTH( list)
899 | |
900 |
901 |
902 |
903 | startsWith
904 | |
905 |
906 | string.(string) -> bool
907 | |
908 |
909 | STARTS_WITH string, string)
910 | |
911 |
912 |
913 |
914 | string
915 | |
916 |
917 | (bool) -> string
918 | |
919 |
920 | CAST( bool AS STRING)
921 | |
922 |
923 |
924 |
925 | (int) -> string
926 | |
927 |
928 | CAST( int AS STRING)
929 | |
930 |
931 |
932 |
933 | (double) -> string
934 | |
935 |
936 | CAST( double AS STRING)
937 | |
938 |
939 |
940 |
941 | (bytes) -> string
942 | |
943 |
944 | CAST( bytes AS STRING)
945 | |
946 |
947 |
948 |
949 | (timestamp) -> string
950 | |
951 |
952 | CAST( timestamp AS STRING)
953 | |
954 |
955 |
956 |
957 | timestamp
958 | |
959 |
960 | (string) -> google.protobuf.Timestamp
961 | |
962 |
963 | TIMESTAMP( string)
964 | |
965 |
966 |
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 |
--------------------------------------------------------------------------------