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