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