// SetBytes stores the given byte array assocciated with // the given key. See the documentation for Set for an // explanation of the timeout parameter func (c *Cache) SetBytes(key string, b []byte, timeout int) error { if profile.On && profile.Profiling() { defer profile.Start(cache).Note("SET", key).End() } if c.pipe != nil { var err error b, err = c.pipe.Encode(b) if err != nil { perr := &cacheError{ op: "encoding data with pipe", key: key, err: err, } c.error(perr) return perr } } k := c.backendKey(key) err := c.driver.Set(k, b, timeout) if err != nil { serr := &cacheError{ op: "setting key", key: key, err: err, } c.error(serr) return serr } c.debugf("Set key %s (%d bytes), expiring in %d", k, len(b), timeout) return nil }
// GetBytes returns the byte array assocciated with the given key func (c *Cache) GetBytes(key string) ([]byte, error) { if profile.On && profile.Profiling() { defer profile.Start(cache).Note("GET", key).End() } b, err := c.driver.Get(c.backendKey(key)) if err != nil { gerr := &cacheError{ op: "getting key", key: key, err: err, } c.error(gerr) return nil, gerr } if b == nil { return nil, ErrNotFound } if c.pipe != nil { b, err = c.pipe.Decode(b) if err != nil { perr := &cacheError{ op: "decoding data with pipe", key: key, err: err, } c.error(perr) return nil, perr } } return b, nil }
// Post is a wrapper around http.Client.Post, returning a Response rather than an // http.Response. See http.Client.Post for further details. func (c *Client) Post(url string, bodyType string, body io.Reader) (*Response, error) { if profile.On && profile.Profiling() { defer profile.Start(profileName).Note("POST", url).End() } c.debugf("POST %s", url) return makeResponse(c.c.Post(url, bodyType, body)) }
// Do is a wrapper around http.Client.Do, returning a Response rather than an // http.Response. See http.Client.Do for further details. func (c *Client) Do(req *http.Request) (*Response, error) { if profile.On && profile.Profiling() { defer profile.Start(profileName).Note(req.Method, req.URL.String()).End() } c.debugf("DO %s %s", req.Method, req.URL) return makeResponse(c.c.Do(req)) }
// Upsert tries to perform an update with the given query // and object. If there are not affected rows, it performs // an insert. Some drivers (like mongodb) are able to perform // this operation in just one query, but most require two // trips to the database. func (o *Orm) Upsert(q query.Q, obj interface{}) (Result, error) { m, err := o.model(obj) if err != nil { return nil, err } if err := m.fields.Methods.Save(obj); err != nil { return nil, err } if o.driver.Upserts() { if profile.On && profile.Profiling() { defer profile.Start(orm).Note("upsert", "").End() } return o.conn.Upsert(m, q, obj) } res, err := o.update(m, q, obj) if err != nil { return nil, err } aff, err := res.RowsAffected() if err != nil { return nil, err } if aff == 0 { res, err = o.insert(m, obj) } return res, err }
// Trip performs a roundtrip with the given http.Request, without following // any redirects, and returns the first response, which might be a redirect. // It's basically a shorthand for c.Transport().RoundTrip(req). func (c *Client) Trip(req *http.Request) (*Response, error) { if profile.On && profile.Profiling() { defer profile.Start(profileName).Note("TRIP-"+req.Method, req.URL.String()).End() } c.debugf("TRIP %s %s", req.Method, req.URL) return makeResponse(c.transport.RoundTrip(req)) }
// Head is a wrapper around http.Client.Head, returning a Response rather than an // http.Response. See http.Client.Head for further details. func (c *Client) Head(url string) (*Response, error) { if profile.On && profile.Profiling() { defer profile.Start(profileName).Note("HEAD", url).End() } c.debugf("HEAD %s", url) return makeResponse(c.c.Head(url)) }
func (d *Driver) debugq(sql string, args []interface{}) { if profile.On && profile.Profiling() { if profile.HasEvent() { profile.Notef("SQL", "%s, args %v", sql, args) if strings.HasPrefix(sql, "SELECT") { rows, _ := d.db.sqlDb.Query("EXPLAIN "+sql, args...) if rows != nil { var line string var explain []string for rows.Next() { if err := rows.Scan(&line); err != nil { explain = nil break } explain = append(explain, line) } rows.Close() if len(explain) > 0 { profile.Notef("EXPLAIN", "%s", strings.Join(explain, "\n")) } } } } } if d.logger != nil { if len(args) > 0 { d.logger.Debugf("SQL: %s with arguments %v", sql, args) } else { d.logger.Debugf("SQL: %s", sql) } } }
// GetMulti returns several objects with only one trip to the cache. // The queried keys are the ones set in the out parameter. Any key present // in out and not found when querying the cache, will be deleted. The initial // values in the out map should be any value of the type which will be used // to decode the data for the given key. // e.g. Let's suppose our cache holds 3 objects: k1 of type []int, k2 of type // float64 and k3 of type string. To query for these 3 objects using GetMulti // you would initialze out like this: // // out := map[string]interface{}{ // k1: []int(nil), // k2: float(0), // k3: "", // } // err := c.GetMulti(out, nil) // // After the GetMulti() call, any keys not present in the cache will be // deleted from out, so len(out) will be <= 3 in this example. // // Alternatively, the second argument might be used to specify the types // of the object to be decoded. Users might implement their own Typer // or use UniTyper when requesting several objects of the same type. func (c *Cache) GetMulti(out map[string]interface{}, typer Typer) error { keys := make([]string, 0, len(out)) for k := range out { keys = append(keys, k) } if profile.On && profile.Profiling() { defer profile.Startf(cache, "GET MULTI", "%v", keys).End() } qkeys := keys if c.prefixLen > 0 { qkeys = make([]string, len(keys)) for ii, v := range keys { qkeys[ii] = c.backendKey(v) } } data, err := c.driver.GetMulti(qkeys) if err != nil { gerr := &cacheError{ op: "getting multiple keys", key: strings.Join(keys, ", "), err: err, } c.error(gerr) return gerr } if typer == nil { typer = mapTyper(out) } for ii, k := range keys { value := data[qkeys[ii]] if value == nil { delete(out, k) continue } typ := typer.Type(k) if typ == nil { derr := &cacheError{ op: "determining output type for object", key: k, err: fmt.Errorf("untyped value for key %q - please, set the value type like e.g. out[%q] = ([]int)(nil) or out[%q] = float64(0)", k, k, k), } c.error(derr) return derr } val := reflect.New(typ) err := c.codec.Decode(value, val.Interface()) if err != nil { derr := &cacheError{ op: "decoding object", key: k, err: err, } c.error(derr) return derr } out[k] = val.Elem().Interface() } return nil }
// Exists returns wheter a result with the specified query // exists. func (q *Query) Exists() (bool, error) { if err := q.ensureTable("Exists"); err != nil { return false, err } if profile.On && profile.Profiling() { defer profile.Start(orm).Note("exists", q.model.String()).End() } return q.orm.driver.Exists(q.model, q.q) }
// Count returns the number of results for the query. Note that // you have to set the table manually before calling Count(). func (q *Query) Count() (uint64, error) { if err := q.ensureTable("Count"); err != nil { return 0, err } if profile.On && profile.Profiling() { defer profile.Start(orm).Note("count", q.model.String()).End() } return q.orm.driver.Count(q.model, q.q, q.opts) }
func makeResponse(r *http.Response, err error) (*Response, error) { if err != nil { return nil, err } if profile.On && profile.Profiling() { r.Body = profile.ReadCloser(r.Body, profileName, r.Request.URL.String()) } return &Response{Response: r}, nil }
func (q *Query) exec(limit *int) driver.Iter { if profile.On && profile.Profiling() { defer profile.Start(orm).Note("query", q.model.String()).End() } opts := q.opts if limit != nil { opts.Limit = *limit } return q.orm.conn.Query(q.model, q.q, opts) }
func (c *Context) WriteHeader(code int) { if c.statusCode < 0 { code = -c.statusCode } c.statusCode = code if profile.On && profile.Profiling() { header := profileHeader(c) c.Header().Set(profile.HeaderName, header) } c.ResponseWriter.WriteHeader(code) }
func (o *Orm) insert(m *model, obj interface{}) (Result, error) { if profile.On && profile.Profiling() { defer profile.Start(orm).Note("insert", m.name).End() } var pkName string var pkVal reflect.Value f := m.fields if f.AutoincrementPk { pkName, pkVal = o.primaryKey(f, obj) if pkVal.Int() == 0 && !pkVal.CanSet() { typ := reflect.TypeOf(obj) return nil, fmt.Errorf("can't set primary key field %q. Please, insert a %v rather than a %v", pkName, reflect.PtrTo(typ), typ) } } if f.Defaults != nil { val := reflect.ValueOf(obj) for k, v := range f.Defaults { indexes := f.Indexes[k] fval := o.fieldByIndexCreating(val, indexes) isTrue, _ := types.IsTrueVal(fval) if !isTrue { if !fval.CanSet() { // Need to copy to alter the fields pval := reflect.New(val.Type()) pval.Elem().Set(val) obj = pval.Interface() val = pval fval = o.fieldByIndexCreating(val, indexes) } if v.Kind() == reflect.Func { out := v.Call(nil) fval.Set(out[0]) } else { fval.Set(v) } } } } res, err := o.conn.Insert(m, obj) if err == nil && pkVal.IsValid() && pkVal.Int() == 0 { id, err := res.LastInsertId() if err == nil && id != 0 { if o.logger != nil { o.logger.Debugf("Setting primary key %q to %d on model %v", pkName, id, m.Type()) } pkVal.SetInt(id) } else if err != nil && o.logger != nil { o.logger.Errorf("could not obtain last insert id: %s", err) } } return res, err }
// LoadTemplate loads a template using the template // loader and the asset manager assocciated with // this app func (app *App) LoadTemplate(name string) (*Template, error) { app.templatesMutex.RLock() tmpl := app.templatesCache[name] app.templatesMutex.RUnlock() if tmpl == nil { var err error log.Debugf("Loading root template %s", name) if profile.On && profile.Profiling() { defer profile.Start("template").Note("load", name).End() } tmpl, err = app.loadTemplate(app.templatesFS, app.assetsManager, name) if err != nil { return nil, err } var funcs []*template.Func for _, v := range app.included { funcs = append(funcs, &template.Func{ Name: v.assetFuncName(), Fn: v.assetFunc(tmpl.tmpl), Traits: template.FuncTraitPure, }) } tmpl.tmpl.Funcs(funcs) for _, v := range app.templatePlugins { if err := tmpl.tmpl.AddPlugin(v); err != nil { return nil, fmt.Errorf("error adding plugin %q: %s", v.Template.Root(), err) } } if profile.On { if profilePlugin != nil { tmpl.tmpl.AddPlugin(profilePlugin) } } if err := tmpl.prepare(); err != nil { return nil, err } if !app.cfg.TemplateDebug { app.templatesMutex.Lock() if app.templatesCache == nil { app.templatesCache = make(map[string]*Template) } app.templatesCache[name] = tmpl app.templatesMutex.Unlock() } } return tmpl, nil }
func (o *Orm) save(m *model, obj interface{}) (Result, error) { if profile.On && profile.Profiling() { defer profile.Start(orm).Note("save", m.name).End() } var res Result var err error if m.fields.PrimaryKey >= 0 { pkName, pkVal := o.primaryKey(m.fields, obj) if driver.IsZero(pkVal) { return o.insert(m, obj) } res, err = o.update(m, Eq(pkName, pkVal.Interface()), obj) } else if len(m.fields.CompositePrimaryKey) > 0 { // Composite primary key names, values := o.compositePrimaryKey(m.fields, obj) for _, v := range values { if !driver.IsZero(v) { // We have a non-zero value, try to update qs := make([]query.Q, len(names)) for ii := range names { qs[ii] = Eq(names[ii], values[ii].Interface()) } res, err = o.update(m, And(qs...), obj) break } } if res == nil && err == nil { // Not updated. All the fields in the PK are zero return o.insert(m, obj) } } else { // No pk return o.insert(m, obj) } if err != nil { return nil, err } up, err := res.RowsAffected() if err != nil { return nil, err } if up == 0 { return o.insert(m, obj) } return res, nil }
func (t *Template) ExecuteContext(w io.Writer, data interface{}, context interface{}, vars VarMap) error { if profile.On && profile.Profiling() { ev := profile.Start("template").Note("exec", t.qname(t.name)) defer ev.End() // If the template is the final rendered template which includes // the profiling data, it must be ended when the timings are fetched. // Other templates, like asset templates, are ended by the deferred call. ev.AutoEnd() } buf := getBuffer() err := t.prog.execute(buf, t.root, data, context, vars) if err != nil { return err } if t.Minify { // Instead of using a new Buffer, make a copy of the []byte and Reset // buf. This minimizes the number of allocations while momentarily // using a bit more of memory than we need (exactly one byte per space // removed in the output). b := buf.Bytes() bc := make([]byte, len(b)) copy(bc, b) r := bytes.NewReader(bc) buf.Reset() if err := html.Minify(buf, r); err != nil { return err } } if rw, ok := w.(http.ResponseWriter); ok { header := rw.Header() header.Set("Content-Type", t.contentType) header.Set("Content-Length", strconv.Itoa(buf.Len())) } _, err = w.Write(buf.Bytes()) putBuffer(buf) return err }
func (o *Orm) update(m *model, q query.Q, obj interface{}) (Result, error) { if profile.On && profile.Profiling() { defer profile.Start(orm).Note("update", m.name).End() } return o.conn.Update(m, q, obj) }
func (o *Orm) delete(m *model, q query.Q) (Result, error) { if profile.On && profile.Profiling() { defer profile.Start(orm).Note("delete", m.name).End() } return o.conn.Delete(m, q) }