github.com/safing/portbase@v0.19.5/database/query/query.go (about)

     1  package query
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/safing/portbase/database/accessor"
     8  	"github.com/safing/portbase/database/record"
     9  )
    10  
    11  // Example:
    12  // q.New("core:/",
    13  //   q.Where("a", q.GreaterThan, 0),
    14  //   q.Where("b", q.Equals, 0),
    15  //   q.Or(
    16  //       q.Where("c", q.StartsWith, "x"),
    17  //       q.Where("d", q.Contains, "y")
    18  //     )
    19  //   )
    20  
    21  // Query contains a compiled query.
    22  type Query struct {
    23  	checked     bool
    24  	dbName      string
    25  	dbKeyPrefix string
    26  	where       Condition
    27  	orderBy     string
    28  	limit       int
    29  	offset      int
    30  }
    31  
    32  // New creates a new query with the supplied prefix.
    33  func New(prefix string) *Query {
    34  	dbName, dbKeyPrefix := record.ParseKey(prefix)
    35  	return &Query{
    36  		dbName:      dbName,
    37  		dbKeyPrefix: dbKeyPrefix,
    38  	}
    39  }
    40  
    41  // Where adds filtering.
    42  func (q *Query) Where(condition Condition) *Query {
    43  	q.where = condition
    44  	return q
    45  }
    46  
    47  // Limit limits the number of returned results.
    48  func (q *Query) Limit(limit int) *Query {
    49  	q.limit = limit
    50  	return q
    51  }
    52  
    53  // Offset sets the query offset.
    54  func (q *Query) Offset(offset int) *Query {
    55  	q.offset = offset
    56  	return q
    57  }
    58  
    59  // OrderBy orders the results by the given key.
    60  func (q *Query) OrderBy(key string) *Query {
    61  	q.orderBy = key
    62  	return q
    63  }
    64  
    65  // Check checks for errors in the query.
    66  func (q *Query) Check() (*Query, error) {
    67  	if q.checked {
    68  		return q, nil
    69  	}
    70  
    71  	// check condition
    72  	if q.where != nil {
    73  		err := q.where.check()
    74  		if err != nil {
    75  			return nil, err
    76  		}
    77  	}
    78  
    79  	q.checked = true
    80  	return q, nil
    81  }
    82  
    83  // MustBeValid checks for errors in the query and panics if there is an error.
    84  func (q *Query) MustBeValid() *Query {
    85  	_, err := q.Check()
    86  	if err != nil {
    87  		panic(err)
    88  	}
    89  	return q
    90  }
    91  
    92  // IsChecked returns whether they query was checked.
    93  func (q *Query) IsChecked() bool {
    94  	return q.checked
    95  }
    96  
    97  // MatchesKey checks whether the query matches the supplied database key (key without database prefix).
    98  func (q *Query) MatchesKey(dbKey string) bool {
    99  	return strings.HasPrefix(dbKey, q.dbKeyPrefix)
   100  }
   101  
   102  // MatchesRecord checks whether the query matches the supplied database record (value only).
   103  func (q *Query) MatchesRecord(r record.Record) bool {
   104  	if q.where == nil {
   105  		return true
   106  	}
   107  
   108  	acc := r.GetAccessor(r)
   109  	if acc == nil {
   110  		return false
   111  	}
   112  	return q.where.complies(acc)
   113  }
   114  
   115  // MatchesAccessor checks whether the query matches the supplied accessor (value only).
   116  func (q *Query) MatchesAccessor(acc accessor.Accessor) bool {
   117  	if q.where == nil {
   118  		return true
   119  	}
   120  	return q.where.complies(acc)
   121  }
   122  
   123  // Matches checks whether the query matches the supplied database record.
   124  func (q *Query) Matches(r record.Record) bool {
   125  	if !q.MatchesKey(r.DatabaseKey()) {
   126  		return false
   127  	}
   128  	return q.MatchesRecord(r)
   129  }
   130  
   131  // Print returns the string representation of the query.
   132  func (q *Query) Print() string {
   133  	var where string
   134  	if q.where != nil {
   135  		where = q.where.string()
   136  		if where != "" {
   137  			if strings.HasPrefix(where, "(") {
   138  				where = where[1 : len(where)-1]
   139  			}
   140  			where = fmt.Sprintf(" where %s", where)
   141  		}
   142  	}
   143  
   144  	var orderBy string
   145  	if q.orderBy != "" {
   146  		orderBy = fmt.Sprintf(" orderby %s", q.orderBy)
   147  	}
   148  
   149  	var limit string
   150  	if q.limit > 0 {
   151  		limit = fmt.Sprintf(" limit %d", q.limit)
   152  	}
   153  
   154  	var offset string
   155  	if q.offset > 0 {
   156  		offset = fmt.Sprintf(" offset %d", q.offset)
   157  	}
   158  
   159  	return fmt.Sprintf("query %s:%s%s%s%s%s", q.dbName, q.dbKeyPrefix, where, orderBy, limit, offset)
   160  }
   161  
   162  // DatabaseName returns the name of the database.
   163  func (q *Query) DatabaseName() string {
   164  	return q.dbName
   165  }
   166  
   167  // DatabaseKeyPrefix returns the key prefix for the database.
   168  func (q *Query) DatabaseKeyPrefix() string {
   169  	return q.dbKeyPrefix
   170  }