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