// 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)) }
// 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)) }
// 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 }
// 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)) }
// 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 }
// 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 }
// 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) }
// 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) }
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 (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) 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) }
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) }