-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathquery.go
153 lines (140 loc) · 6.63 KB
/
query.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package zoom
// Query represents a query which will retrieve some models from
// the database. A Query may consist of one or more query modifiers
// (e.g. Filter or Order) and may be executed with a query finisher
// (e.g. Run or IDs).
type Query struct {
*query
}
// NewQuery is used to construct a query. The query returned can be chained
// together with one or more query modifiers (e.g. Filter or Order), and then
// executed using the Run, RunOne, Count, or IDs methods. If no query modifiers
// are used, running the query will return all models of the given type in
// unspecified order. Queries use delayed execution, so nothing touches the
// database until you execute them.
func (collection *Collection) NewQuery() *Query {
return &Query{
query: newQuery(collection),
}
}
// Order specifies a field by which to sort the models. fieldName should be a
// field in the struct type corresponding to the Collection used in the query
// constructor. By default, the records are sorted by ascending order by the
// given field. To sort by descending order, put a negative sign before the
// field name. Zoom can only sort by fields which have been indexed, i.e. those
// which have the `zoom:"index"` struct tag. Only one order may be specified per
// Order will set an error on the query if the fieldName is invalid, if another
// order has already been applied to the query, or if the fieldName specified
// does not correspond to an indexed field. The error, same as any other error
// that occurs during the lifetime of the query, is not returned until the query
// is executed.
func (q *Query) Order(fieldName string) *Query {
q.query.Order(fieldName)
return q
}
// Limit specifies an upper limit on the number of models to return. If amount
// is 0, no limit will be applied and any number of models may be returned. The
// default value is 0.
func (q *Query) Limit(amount uint) *Query {
q.query.Limit(amount)
return q
}
// Offset specifies a starting index (inclusive) from which to start counting
// models that will be returned. For example, if offset is 10, the first 10
// models that the query would otherwise return will be skipped. The default
// value is 0.
func (q *Query) Offset(amount uint) *Query {
q.query.Offset(amount)
return q
}
// Include specifies one or more field names which will be read from the
// database and scanned into the resulting models when the query is run. Field
// names which are not specified in Include will not be read or scanned. You can
// only use one of Include or Exclude, not both on the same query. Include will
// set an error if you try to use it with Exclude on the same query. The error,
// same as any other error that occurs during the lifetime of the query, is not
// returned until the query is executed.
func (q *Query) Include(fields ...string) *Query {
q.query.Include(fields...)
return q
}
// Exclude specifies one or more field names which will *not* be read from the
// database and scanned. Any other fields *will* be read and scanned into the
// resulting models when the query is run. You can only use one of Include or
// Exclude, not both on the same query. Exclude will set an error if you try to
// use it with Include on the same query. The error, same as any other error
// that occurs during the lifetime of the query, is not returned until the query
// is executed.
func (q *Query) Exclude(fields ...string) *Query {
q.query.Exclude(fields...)
return q
}
// Filter applies a filter to the query, which will cause the query to only
// return models with field values matching the expression. filterString should
// be an expression which includes a fieldName, a space, and an operator in that
// order. For example: Filter("Age >=", 30) would only return models which have
// an Age value greater than or equal to 30. Operators must be one of "=", "!=",
// ">", "<", ">=", or "<=". You can only use Filter on fields which are indexed,
// i.e. those which have the `zoom:"index"` struct tag. If multiple filters are
// applied to the same query, the query will only return models which have
// matches for *all* of the filters. Filter will set an error on the query if
// the arguments are improperly formated, if the field you are attempting to
// filter is not indexed, or if the type of value does not match the type of the
// field. The error, same as any other error that occurs during the lifetime of
// the query, is not returned until the query is executed.
func (q *Query) Filter(filterString string, value interface{}) *Query {
q.query.Filter(filterString, value)
return q
}
// Run executes the query and scans the results into models. The type of models
// should be a pointer to a slice of Models. If no models fit the criteria, Run
// will set the length of models to 0 but will *not* return an error. Run will
// return the first error that occurred during the lifetime of the query (if
// any), or if models is the wrong type.
func (q *Query) Run(models interface{}) error {
tx := q.pool.NewTransaction()
newTransactionQuery(q.query, tx).Run(models)
return tx.Exec()
}
// RunOne is exactly like Run but finds only the first model that fits the query
// criteria and scans the values into model. If no model fits the criteria,
// RunOne *will* return a ModelNotFoundError.
func (q *Query) RunOne(model Model) error {
tx := q.pool.NewTransaction()
newTransactionQuery(q.query, tx).RunOne(model)
return tx.Exec()
}
// Count counts the number of models that would be returned by the query without
// actually retrieving the models themselves. Count will also return the first
// error that occurred during the lifetime of the query (if any).
func (q *Query) Count() (int, error) {
tx := q.pool.NewTransaction()
var count int
newTransactionQuery(q.query, tx).Count(&count)
if err := tx.Exec(); err != nil {
return 0, err
}
return count, nil
}
// IDs returns only the ids of the models without actually retrieving the
// models themselves. IDs will return the first error that occurred during the
// lifetime of the query (if any).
func (q *Query) IDs() ([]string, error) {
tx := q.pool.NewTransaction()
ids := []string{}
newTransactionQuery(q.query, tx).IDs(&ids)
if err := tx.Exec(); err != nil {
return nil, err
}
return ids, nil
}
// StoreIDs executes the query and stores the model ids matching the query
// criteria in a list identified by destKey. The list will be completely
// overwritten, and the model ids stored there will be in the correct order if
// the query includes an Order modifier. StoreIDs will return the first error
// that occurred during the lifetime of the query (if any).
func (q *Query) StoreIDs(destKey string) error {
tx := q.pool.NewTransaction()
newTransactionQuery(q.query, tx).StoreIDs(destKey)
return tx.Exec()
}