func (q *Query) Delete() (int, error) { res, err := q.eval() if err != nil { log.Errorf("Error executing kv.Query.Delete() query=%s err=%s", q.JSON(), err.Error()) return -1, err } for id, _ := range res { q.col.Delete(id) log.V(6).Info("Deleted id=%d") } log.V(5).Info("Deleted %d objects for query=%s", len(res), q.JSON()) return len(res), nil }
func incrCount(tde *kv.TiedotEngine) int64 { mu.Lock() defer mu.Unlock() counter := new(Counter) id, err := tde.Query(counterCollection).Has(kv.Path{"Count"}).OneInto(counter) if err == kv.ErrNotFound { log.Warning("Counter not found, saving new one.") _, err = tde.Insert(counterCollection, Counter{Count: 1}) if err != nil { log.Errorf("Error saving new counter err=%s", err.Error()) } r, err := tde.All(counterCollection) log.V(3).Infof("total of %d results=%v, err=%v", len(r), r, err) return 1 } if err != nil { log.Error("Failure getting counter err:" + err.Error()) panic(err) } counter.Count++ err = tde.Update(counterCollection, id, counter) if err != nil { log.Error("Failure updating counter err:" + err.Error()) panic(err) } return counter.Count }
func (q *Query) OneInto(out interface{}) (uint64, error) { r, err := q.eval() if err != nil { log.Errorf("Error executing kv.Query.One() err=%s", err.Error()) return 0, err } for k, _ := range r { log.V(2).Infof("Found id=%d kv.Query.OneInto()", k) if _, err := q.col.Read(k, out); err != nil { log.Errorf("Failure reading id=%d err=%s", k, err.Error()) return 0, err } return k, nil } log.V(1).Infof("Nothing found for query=%s", q.JSON()) return 0, ErrNotFound }
func (t *TiedotEngine) Insert(collectionName string, item Insertable) (uint64, error) { if len(item.ToM()) == 0 { log.Warningf("Failure: No data in item=%v", item.ToM()) return 0, nil } else { log.V(3).Infof("Insertion into collection=%s item=%v", collectionName, item.ToM()) } id, err := t.tiedot.Use(collectionName).Insert(item.ToM()) if err != nil { log.Errorf("Failure inserting item=%v err=%s", item.ToM(), err.Error()) return 0, err } else { log.V(6).Infof("Added item with ID=%d, item=%v", id, item.ToM()) return id, nil } }
func countHits(tde *kv.TiedotEngine) { var key string for { key = <-hits newHitCount := incrHits(tde, key) log.V(3).Infof("[HIT]: key=%s count=%d", key, newHitCount) } }
func (q *Query) One() (uint64, interface{}, error) { r, err := q.eval() if err != nil { log.Errorf("Error executing kv.Query.One() err=%s", err.Error()) return 0, nil, err } for id, _ := range r { v, err := q.read(id) if err != nil { log.Errorf("Failure reading id=%d err=%v", id, err) return id, nil, err } log.V(2).Infof("Found id=%d val=%v for kv.Query.One()", id, v) return id, v, nil } log.V(1).Infof("Nothing found for query=%v", q.JSON()) return 0, nil, ErrNotFound }
func (t *TiedotEngine) Update(collectionName string, id uint64, item Insertable) error { err := t.tiedot.Use(collectionName).Update(id, item.ToM()) if err != nil { log.Errorf("Failure updating item=%s err=%s", item.ToM().JSON(), err.Error()) } else { log.V(3).Infof("Updating with data: %v", item.ToM()) } return err }
func retrieve(w http.ResponseWriter, r *http.Request, tde *kv.TiedotEngine, params martini.Params) { short := params["short"] domain, err := LongURL(short, tde) if err == kv.ErrNotFound { log.V(1).Info("Path /" + short + " not found") w.WriteHeader(http.StatusNotFound) return } if len(domain.Original) > 0 { log.V(3).Info("[INFO]: Served /" + short + " redirect to " + domain.Original) http.Redirect(w, r, domain.Original, http.StatusFound) hits <- short return } log.Error("retrieving long URL err:" + err.Error()) w.WriteHeader(500) if err != nil { w.Write(M{"error": err.Error()}.JSON()) } }
func (t *TiedotEngine) AddIndex(collection string, path Path) { c := t.tiedot.Use(collection) tdPath := strings.Join(path, tiedot.INDEX_PATH_SEP) if _, ok := c.SecIndexes[tdPath]; ok { log.Infof("Index on path:%v already exists for collection:%s", tdPath, collection) return } log.V(3).Infof("Adding index on path:%v to collection:%s", tdPath, collection) err := c.Index(path) log.FatalIfErr(err, "Failure creating index on collection:"+collection) }
func remove(w http.ResponseWriter, r *http.Request, tde *kv.TiedotEngine, params martini.Params) (int, []byte) { short := params["short"] _, err := tde.Query(urlCollection).Equals(kv.Path{"Short"}, base62.DecodeString(short)).Delete() if err != nil { log.Error("Failure deleting URL /" + short + " err:" + err.Error()) return 500, M{ "message": "Could not delete URL /" + short, "error": err.Error(), }.JSON() } log.V(1).Info("Deleted URL /" + short) return 200, M{ "deleted": M{"short": short}, }.JSON() }
// Create a new LevelDBEngine with the given file and options func NewTiedotEngine(directory string, collections []string, dropPref DropPreference) *TiedotEngine { db, err := tiedot.OpenDB(directory) log.FatalIfErr(err, "Failure opening tiedot basedir err:") for _, c := range collections { if _, ok := db.StrCol[c]; ok { log.V(4).Info("Collection %s already exists") if dropPref == DropIfExist { log.Info("Dropping collection %s due to dropIfExist option") err = db.Drop(c) log.FatalIfErr(err, "Failure dropping collection with name:%s err:", c) err = db.Create(c, 1) // partition DB for use by up to 1 goroutines at a time log.FatalIfErr(err, "Failure creating collection with name:%s err:", c) } } else { log.V(4).Info("Creating collection %s") err = db.Create(c, 1) // partition DB for use by up to 1 goroutines at a time log.FatalIfErr(err, "Failure creating collection with name:%s err:", c) } } tde := &TiedotEngine{ tiedot: db, } return tde }
func (q *Query) Equals(p Path, v interface{}) *Query { log.V(6).Infof("QueryBuilder: Path=%v Term=%v Value=%v", p, "Equals", v) q.q = append(q.q, M{"in": p, "eq": v}) return q }
func (q *Query) Has(p Path) *Query { log.V(6).Infof("QueryBuilder: HasPath=%v", p) q.q = append(q.q, M{"has": p}) return q }
func (q *Query) Regexp(p Path, expr string) *Query { log.V(6).Infof("QueryBuilder: Path=%v Regexp=%s", p, expr) q.q = append(q.q, M{"in": p, "re": expr}) return q }
func (q *Query) Between(p Path, start, end int64) *Query { log.V(6).Infof("QueryBuilder: Path=%v Between %d and %d", p, start, end) q.q = append(q.q, M{"in": p, "int from": start, "int to": end}) return q }
func root(w http.ResponseWriter, r *http.Request) (int, string) { log.V(3).Info("Served Homepage") return 200, ("Welcome to legowebservices.short URL shortener service.\n" + "POST to this URL with JSON matching {\"url\":\"some.long.url.com\"}\n") }