fork of https://github.com/sourcegraph/zoekt
1package query
2
3import (
4 "fmt"
5 "regexp/syntax"
6
7 "github.com/RoaringBitmap/roaring"
8 "github.com/grafana/regexp"
9 webserverv1 "github.com/sourcegraph/zoekt/grpc/protos/zoekt/webserver/v1"
10)
11
12func QToProto(q Q) *webserverv1.Q {
13 switch v := q.(type) {
14 case RawConfig:
15 return &webserverv1.Q{Query: &webserverv1.Q_RawConfig{RawConfig: v.ToProto()}}
16 case *Regexp:
17 return &webserverv1.Q{Query: &webserverv1.Q_Regexp{Regexp: v.ToProto()}}
18 case *Symbol:
19 return &webserverv1.Q{Query: &webserverv1.Q_Symbol{Symbol: v.ToProto()}}
20 case *Language:
21 return &webserverv1.Q{Query: &webserverv1.Q_Language{Language: v.ToProto()}}
22 case *Const:
23 return &webserverv1.Q{Query: &webserverv1.Q_Const{Const: v.Value}}
24 case *Repo:
25 return &webserverv1.Q{Query: &webserverv1.Q_Repo{Repo: v.ToProto()}}
26 case *RepoRegexp:
27 return &webserverv1.Q{Query: &webserverv1.Q_RepoRegexp{RepoRegexp: v.ToProto()}}
28 case *BranchesRepos:
29 return &webserverv1.Q{Query: &webserverv1.Q_BranchesRepos{BranchesRepos: v.ToProto()}}
30 case *RepoIDs:
31 return &webserverv1.Q{Query: &webserverv1.Q_RepoIds{RepoIds: v.ToProto()}}
32 case *RepoSet:
33 return &webserverv1.Q{Query: &webserverv1.Q_RepoSet{RepoSet: v.ToProto()}}
34 case *FileNameSet:
35 return &webserverv1.Q{Query: &webserverv1.Q_FileNameSet{FileNameSet: v.ToProto()}}
36 case *Type:
37 return &webserverv1.Q{Query: &webserverv1.Q_Type{Type: v.ToProto()}}
38 case *Substring:
39 return &webserverv1.Q{Query: &webserverv1.Q_Substring{Substring: v.ToProto()}}
40 case *And:
41 return &webserverv1.Q{Query: &webserverv1.Q_And{And: v.ToProto()}}
42 case *Or:
43 return &webserverv1.Q{Query: &webserverv1.Q_Or{Or: v.ToProto()}}
44 case *Not:
45 return &webserverv1.Q{Query: &webserverv1.Q_Not{Not: v.ToProto()}}
46 case *Branch:
47 return &webserverv1.Q{Query: &webserverv1.Q_Branch{Branch: v.ToProto()}}
48 case *Boost:
49 return &webserverv1.Q{Query: &webserverv1.Q_Boost{Boost: v.ToProto()}}
50 default:
51 // The following nodes do not have a proto representation:
52 // - caseQ: only used internally, not by the RPC layer
53 panic(fmt.Sprintf("unknown query node %T", v))
54 }
55}
56
57func QFromProto(p *webserverv1.Q) (Q, error) {
58 switch v := p.Query.(type) {
59 case *webserverv1.Q_RawConfig:
60 return RawConfigFromProto(v.RawConfig), nil
61 case *webserverv1.Q_Regexp:
62 return RegexpFromProto(v.Regexp)
63 case *webserverv1.Q_Symbol:
64 return SymbolFromProto(v.Symbol)
65 case *webserverv1.Q_Language:
66 return LanguageFromProto(v.Language), nil
67 case *webserverv1.Q_Const:
68 return &Const{Value: v.Const}, nil
69 case *webserverv1.Q_Repo:
70 return RepoFromProto(v.Repo)
71 case *webserverv1.Q_RepoRegexp:
72 return RepoRegexpFromProto(v.RepoRegexp)
73 case *webserverv1.Q_BranchesRepos:
74 return BranchesReposFromProto(v.BranchesRepos)
75 case *webserverv1.Q_RepoIds:
76 return RepoIDsFromProto(v.RepoIds)
77 case *webserverv1.Q_RepoSet:
78 return RepoSetFromProto(v.RepoSet), nil
79 case *webserverv1.Q_FileNameSet:
80 return FileNameSetFromProto(v.FileNameSet), nil
81 case *webserverv1.Q_Type:
82 return TypeFromProto(v.Type)
83 case *webserverv1.Q_Substring:
84 return SubstringFromProto(v.Substring), nil
85 case *webserverv1.Q_And:
86 return AndFromProto(v.And)
87 case *webserverv1.Q_Or:
88 return OrFromProto(v.Or)
89 case *webserverv1.Q_Not:
90 return NotFromProto(v.Not)
91 case *webserverv1.Q_Branch:
92 return BranchFromProto(v.Branch), nil
93 case *webserverv1.Q_Boost:
94 return BoostFromProto(v.Boost)
95 default:
96 panic(fmt.Sprintf("unknown query node %T", p.Query))
97 }
98}
99
100func RegexpFromProto(p *webserverv1.Regexp) (*Regexp, error) {
101 parsed, err := syntax.Parse(p.GetRegexp(), regexpFlags)
102 if err != nil {
103 return nil, err
104 }
105 return &Regexp{
106 Regexp: parsed,
107 FileName: p.GetFileName(),
108 Content: p.GetContent(),
109 CaseSensitive: p.GetCaseSensitive(),
110 }, nil
111}
112
113func (r *Regexp) ToProto() *webserverv1.Regexp {
114 return &webserverv1.Regexp{
115 Regexp: r.Regexp.String(),
116 FileName: r.FileName,
117 Content: r.Content,
118 CaseSensitive: r.CaseSensitive,
119 }
120}
121
122func SymbolFromProto(p *webserverv1.Symbol) (*Symbol, error) {
123 expr, err := QFromProto(p.GetExpr())
124 if err != nil {
125 return nil, err
126 }
127
128 return &Symbol{
129 Expr: expr,
130 }, nil
131}
132
133func (s *Symbol) ToProto() *webserverv1.Symbol {
134 return &webserverv1.Symbol{
135 Expr: QToProto(s.Expr),
136 }
137}
138
139func LanguageFromProto(p *webserverv1.Language) *Language {
140 return &Language{
141 Language: p.GetLanguage(),
142 }
143}
144
145func (l *Language) ToProto() *webserverv1.Language {
146 return &webserverv1.Language{Language: l.Language}
147}
148
149func RepoFromProto(p *webserverv1.Repo) (*Repo, error) {
150 r, err := regexp.Compile(p.GetRegexp())
151 if err != nil {
152 return nil, err
153 }
154 return &Repo{
155 Regexp: r,
156 }, nil
157}
158
159func (q *Repo) ToProto() *webserverv1.Repo {
160 return &webserverv1.Repo{
161 Regexp: q.Regexp.String(),
162 }
163}
164
165func RepoRegexpFromProto(p *webserverv1.RepoRegexp) (*RepoRegexp, error) {
166 r, err := regexp.Compile(p.GetRegexp())
167 if err != nil {
168 return nil, err
169 }
170 return &RepoRegexp{
171 Regexp: r,
172 }, nil
173}
174
175func (q *RepoRegexp) ToProto() *webserverv1.RepoRegexp {
176 return &webserverv1.RepoRegexp{
177 Regexp: q.Regexp.String(),
178 }
179}
180
181func BranchesReposFromProto(p *webserverv1.BranchesRepos) (*BranchesRepos, error) {
182 brs := make([]BranchRepos, len(p.GetList()))
183 for i, br := range p.GetList() {
184 branchRepos, err := BranchReposFromProto(br)
185 if err != nil {
186 return nil, err
187 }
188 brs[i] = branchRepos
189 }
190 return &BranchesRepos{
191 List: brs,
192 }, nil
193}
194
195func (br *BranchesRepos) ToProto() *webserverv1.BranchesRepos {
196 list := make([]*webserverv1.BranchRepos, len(br.List))
197 for i, branchRepo := range br.List {
198 list[i] = branchRepo.ToProto()
199 }
200
201 return &webserverv1.BranchesRepos{
202 List: list,
203 }
204}
205
206func RepoIDsFromProto(p *webserverv1.RepoIds) (*RepoIDs, error) {
207 bm := roaring.NewBitmap()
208 err := bm.UnmarshalBinary(p.GetRepos())
209 if err != nil {
210 return nil, err
211 }
212
213 return &RepoIDs{
214 Repos: bm,
215 }, nil
216}
217
218func (q *RepoIDs) ToProto() *webserverv1.RepoIds {
219 b, err := q.Repos.ToBytes()
220 if err != nil {
221 panic("unexpected error marshalling bitmap: " + err.Error())
222 }
223 return &webserverv1.RepoIds{
224 Repos: b,
225 }
226}
227
228func BranchReposFromProto(p *webserverv1.BranchRepos) (BranchRepos, error) {
229 bm := roaring.NewBitmap()
230 err := bm.UnmarshalBinary(p.GetRepos())
231 if err != nil {
232 return BranchRepos{}, err
233 }
234 return BranchRepos{
235 Branch: p.GetBranch(),
236 Repos: bm,
237 }, nil
238}
239
240func (br *BranchRepos) ToProto() *webserverv1.BranchRepos {
241 b, err := br.Repos.ToBytes()
242 if err != nil {
243 panic("unexpected error marshalling bitmap: " + err.Error())
244 }
245
246 return &webserverv1.BranchRepos{
247 Branch: br.Branch,
248 Repos: b,
249 }
250}
251
252func RepoSetFromProto(p *webserverv1.RepoSet) *RepoSet {
253 return &RepoSet{
254 Set: p.GetSet(),
255 }
256}
257
258func (q *RepoSet) ToProto() *webserverv1.RepoSet {
259 return &webserverv1.RepoSet{
260 Set: q.Set,
261 }
262}
263
264func FileNameSetFromProto(p *webserverv1.FileNameSet) *FileNameSet {
265 m := make(map[string]struct{}, len(p.GetSet()))
266 for _, name := range p.GetSet() {
267 m[name] = struct{}{}
268 }
269 return &FileNameSet{
270 Set: m,
271 }
272}
273
274func (q *FileNameSet) ToProto() *webserverv1.FileNameSet {
275 s := make([]string, 0, len(q.Set))
276 for name := range q.Set {
277 s = append(s, name)
278 }
279 return &webserverv1.FileNameSet{
280 Set: s,
281 }
282}
283
284func TypeFromProto(p *webserverv1.Type) (*Type, error) {
285 child, err := QFromProto(p.GetChild())
286 if err != nil {
287 return nil, err
288 }
289
290 var kind uint8
291 switch p.GetType() {
292 case webserverv1.Type_KIND_FILE_MATCH:
293 kind = TypeFileMatch
294 case webserverv1.Type_KIND_FILE_NAME:
295 kind = TypeFileName
296 case webserverv1.Type_KIND_REPO:
297 kind = TypeRepo
298 }
299
300 return &Type{
301 Child: child,
302 // TODO: make proper enum types
303 Type: kind,
304 }, nil
305}
306
307func (q *Type) ToProto() *webserverv1.Type {
308 var kind webserverv1.Type_Kind
309 switch q.Type {
310 case TypeFileMatch:
311 kind = webserverv1.Type_KIND_FILE_MATCH
312 case TypeFileName:
313 kind = webserverv1.Type_KIND_FILE_NAME
314 case TypeRepo:
315 kind = webserverv1.Type_KIND_REPO
316 }
317
318 return &webserverv1.Type{
319 Child: QToProto(q.Child),
320 Type: kind,
321 }
322}
323
324func SubstringFromProto(p *webserverv1.Substring) *Substring {
325 return &Substring{
326 Pattern: p.GetPattern(),
327 CaseSensitive: p.GetCaseSensitive(),
328 FileName: p.GetFileName(),
329 Content: p.GetContent(),
330 }
331}
332
333func (q *Substring) ToProto() *webserverv1.Substring {
334 return &webserverv1.Substring{
335 Pattern: q.Pattern,
336 CaseSensitive: q.CaseSensitive,
337 FileName: q.FileName,
338 Content: q.Content,
339 }
340}
341
342func OrFromProto(p *webserverv1.Or) (*Or, error) {
343 children := make([]Q, len(p.GetChildren()))
344 for i, child := range p.GetChildren() {
345 c, err := QFromProto(child)
346 if err != nil {
347 return nil, err
348 }
349 children[i] = c
350 }
351 return &Or{
352 Children: children,
353 }, nil
354}
355
356func (q *Or) ToProto() *webserverv1.Or {
357 children := make([]*webserverv1.Q, len(q.Children))
358 for i, child := range q.Children {
359 children[i] = QToProto(child)
360 }
361 return &webserverv1.Or{
362 Children: children,
363 }
364}
365
366func BoostFromProto(p *webserverv1.Boost) (*Boost, error) {
367 child, err := QFromProto(p.GetChild())
368 if err != nil {
369 return nil, err
370 }
371 return &Boost{
372 Child: child,
373 Boost: p.GetBoost(),
374 }, nil
375}
376
377func (q *Boost) ToProto() *webserverv1.Boost {
378 return &webserverv1.Boost{
379 Child: QToProto(q.Child),
380 Boost: q.Boost,
381 }
382}
383
384func NotFromProto(p *webserverv1.Not) (*Not, error) {
385 child, err := QFromProto(p.GetChild())
386 if err != nil {
387 return nil, err
388 }
389 return &Not{
390 Child: child,
391 }, nil
392}
393
394func (q *Not) ToProto() *webserverv1.Not {
395 return &webserverv1.Not{
396 Child: QToProto(q.Child),
397 }
398}
399
400func AndFromProto(p *webserverv1.And) (*And, error) {
401 children := make([]Q, len(p.GetChildren()))
402 for i, child := range p.GetChildren() {
403 c, err := QFromProto(child)
404 if err != nil {
405 return nil, err
406 }
407 children[i] = c
408 }
409 return &And{
410 Children: children,
411 }, nil
412}
413
414func (q *And) ToProto() *webserverv1.And {
415 children := make([]*webserverv1.Q, len(q.Children))
416 for i, child := range q.Children {
417 children[i] = QToProto(child)
418 }
419 return &webserverv1.And{
420 Children: children,
421 }
422}
423
424func BranchFromProto(p *webserverv1.Branch) *Branch {
425 return &Branch{
426 Pattern: p.GetPattern(),
427 Exact: p.GetExact(),
428 }
429}
430
431func (q *Branch) ToProto() *webserverv1.Branch {
432 return &webserverv1.Branch{
433 Pattern: q.Pattern,
434 Exact: q.Exact,
435 }
436}
437
438func RawConfigFromProto(p *webserverv1.RawConfig) (res RawConfig) {
439 for _, protoFlag := range p.Flags {
440 switch protoFlag {
441 case webserverv1.RawConfig_FLAG_ONLY_PUBLIC:
442 res |= RcOnlyPublic
443 case webserverv1.RawConfig_FLAG_ONLY_PRIVATE:
444 res |= RcOnlyPrivate
445 case webserverv1.RawConfig_FLAG_ONLY_FORKS:
446 res |= RcOnlyForks
447 case webserverv1.RawConfig_FLAG_NO_FORKS:
448 res |= RcNoForks
449 case webserverv1.RawConfig_FLAG_ONLY_ARCHIVED:
450 res |= RcOnlyArchived
451 case webserverv1.RawConfig_FLAG_NO_ARCHIVED:
452 res |= RcNoArchived
453 }
454 }
455 return res
456}
457
458func (r RawConfig) ToProto() *webserverv1.RawConfig {
459 var flags []webserverv1.RawConfig_Flag
460 for _, flag := range flagNames {
461 if r&flag.Mask != 0 {
462 switch flag.Mask {
463 case RcOnlyPublic:
464 flags = append(flags, webserverv1.RawConfig_FLAG_ONLY_PUBLIC)
465 case RcOnlyPrivate:
466 flags = append(flags, webserverv1.RawConfig_FLAG_ONLY_PRIVATE)
467 case RcOnlyForks:
468 flags = append(flags, webserverv1.RawConfig_FLAG_ONLY_FORKS)
469 case RcNoForks:
470 flags = append(flags, webserverv1.RawConfig_FLAG_NO_FORKS)
471 case RcOnlyArchived:
472 flags = append(flags, webserverv1.RawConfig_FLAG_ONLY_ARCHIVED)
473 case RcNoArchived:
474 flags = append(flags, webserverv1.RawConfig_FLAG_NO_ARCHIVED)
475 }
476 }
477 }
478 return &webserverv1.RawConfig{Flags: flags}
479}