Example #1
0
// 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
}
Example #2
0
// 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
}
Example #3
0
// 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))
}
Example #4
0
// 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))
}
Example #5
0
// 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
}
Example #6
0
// 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))
}
Example #7
0
// 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))
}
Example #8
0
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)
		}
	}
}
Example #9
0
// 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
}
Example #10
0
// 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)
}
Example #11
0
// 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)
}
Example #12
0
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
}
Example #13
0
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)
}
Example #14
0
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)
}
Example #15
0
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
}
Example #16
0
// 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
}
Example #17
0
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
}
Example #18
0
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
}
Example #19
0
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)
}
Example #20
0
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)
}