package bolt import ( "encoding/binary" "git.binarythought.com/cdramey/qurl/obj" ) var ( QURLBucket = []byte{0x00} ReverseBucket = []byte{0x01} URLField = []byte{0x00} CreatedField = []byte{0x01} IPField = []byte{0x02} BrowserField = []byte{0x03} ) func (stor *BoltStorage) AddQURL(q *obj.QURL) error { tx, err := stor.DB.Begin(true) if err != nil { return err } defer tx.Rollback() rb, err := tx.CreateBucketIfNotExists(QURLBucket) if err != nil { return err } // Populate the ID from the sequence if we don't have one if q.ID == 0 { s, err := rb.NextSequence() if err != nil { return err } // Bolt's sequence starts at 1, so for // backwards compatibility we have subtract // one so we're zero-based q.ID = (s - 1) } // Create a byte array from the ID bid := make([]byte, 8) binary.BigEndian.PutUint64(bid, q.ID) // Add an entry into the reverse indexed bucket for quickly // determining if a URL is already in the database ab, err := tx.CreateBucketIfNotExists(ReverseBucket) if err != nil { return err } err = ab.Put([]byte(q.URL), bid) qb, err := rb.CreateBucketIfNotExists(bid) if err != nil { return err } // Write the ID to URL err = qb.Put(URLField, []byte(q.URL)) if err != nil { return err } if !q.Created.IsZero() { // Create byte array from the Created date bdt, err := q.Created.MarshalBinary() if err != nil { return err } // Write the Created date err = qb.Put(CreatedField, bdt) if err != nil { return err } } if q.IP != nil { err = qb.Put(IPField, q.IP) if err != nil { return err } } if len(q.Browser) > 0 { err = qb.Put(BrowserField, []byte(q.Browser)) if err != nil { return err } } if err := tx.Commit(); err != nil { return err } return nil } func (stor *BoltStorage) SetQURLSequence(seq uint64) error { tx, err := stor.DB.Begin(true) if err != nil { return err } defer tx.Rollback() qb, err := tx.CreateBucketIfNotExists(QURLBucket) if err != nil { return err } // Since the sequence number is decremented by one // for backwards compatibility (see above) // we increment it by one when setting the sequence qb.SetSequence(seq + 1) if err := tx.Commit(); err != nil { return err } return nil } func (stor *BoltStorage) GetQURLByURL(u string) (*obj.QURL, error) { tx, err := stor.DB.Begin(false) if err != nil { return nil, err } defer tx.Rollback() ab := tx.Bucket(ReverseBucket) if ab == nil { return nil, nil } bid := ab.Get([]byte(u)) if bid == nil { return nil, nil } rb := tx.Bucket(QURLBucket) if rb == nil { return nil, nil } qb := rb.Bucket(bid) if qb == nil { return nil, nil } q := &obj.QURL{ID: binary.BigEndian.Uint64(bid)} qu := qb.Get(URLField) if qu != nil { q.URL = string(qu) } return q, nil } func (stor *BoltStorage) GetQURLByID(id uint64) (*obj.QURL, error) { tx, err := stor.DB.Begin(false) if err != nil { return nil, err } defer tx.Rollback() // Create a byte array from the ID bid := make([]byte, 8) binary.BigEndian.PutUint64(bid, id) rb := tx.Bucket(QURLBucket) if rb == nil { return nil, nil } qb := rb.Bucket(bid) if qb == nil { return nil, nil } q := &obj.QURL{ID: id} qu := qb.Get(URLField) if qu != nil { q.URL = string(qu) } return q, nil }