Exemplo n.º 1
0
// Range returns one or more records by the specified index within the specified range
func (n *node) Range(fieldName string, min, max, to interface{}, options ...func(*index.Options)) error {
	sink, err := newListSink(n, to)
	if err != nil {
		return err
	}

	bucketName := sink.bucketName()
	if bucketName == "" {
		return ErrNoName
	}

	ref := reflect.Indirect(reflect.New(sink.elemType))
	cfg, err := extractSingleField(&ref, fieldName)
	if err != nil {
		return err
	}

	opts := index.NewOptions()
	for _, fn := range options {
		fn(opts)
	}

	field, ok := cfg.Fields[fieldName]
	if !ok || (!field.IsID && field.Index == "") {
		sink.limit = opts.Limit
		sink.skip = opts.Skip
		query := newQuery(n, q.And(q.Gte(fieldName, min), q.Lte(fieldName, max)))

		if opts.Reverse {
			query.Reverse()
		}

		err = n.readTx(func(tx *bolt.Tx) error {
			return query.query(tx, sink)
		})

		if err != nil {
			return err
		}

		return sink.flush()
	}

	mn, err := toBytes(min, n.s.codec)
	if err != nil {
		return err
	}

	mx, err := toBytes(max, n.s.codec)
	if err != nil {
		return err
	}

	return n.readTx(func(tx *bolt.Tx) error {
		return n.rnge(tx, bucketName, fieldName, cfg, sink, mn, mx, opts)
	})
}
Exemplo n.º 2
0
// Find returns one or more records by the specified index
func (n *node) Find(fieldName string, value interface{}, to interface{}, options ...func(q *index.Options)) error {
	if value == nil {
		return ErrNotFound
	}

	sink, err := newListSink(n, to)
	if err != nil {
		return err
	}
	bucketName := sink.bucketName()
	if bucketName == "" {
		return ErrNoName
	}

	ref := reflect.Indirect(reflect.New(sink.elemType))
	cfg, err := extractSingleField(&ref, fieldName)
	if err != nil {
		return err
	}

	opts := index.NewOptions()
	for _, fn := range options {
		fn(opts)
	}

	field, ok := cfg.Fields[fieldName]
	if !ok || (!field.IsID && field.Index == "") {
		sink.limit = opts.Limit
		sink.skip = opts.Skip
		query := newQuery(n, q.StrictEq(fieldName, value))

		if opts.Reverse {
			query.Reverse()
		}

		err = n.readTx(func(tx *bolt.Tx) error {
			return query.query(tx, sink)
		})

		if err != nil {
			return err
		}

		return sink.flush()
	}

	val, err := toBytes(value, n.s.codec)
	if err != nil {
		return err
	}

	return n.readTx(func(tx *bolt.Tx) error {
		return n.find(tx, bucketName, fieldName, cfg, sink, val, opts)
	})
}
Exemplo n.º 3
0
// All gets all the records of a bucket.
// If there are no records it returns no error and the 'to' parameter is set to an empty slice.
func (n *node) All(to interface{}, options ...func(*index.Options)) error {
	opts := index.NewOptions()
	for _, fn := range options {
		fn(opts)
	}

	query := newQuery(n, nil).Limit(opts.Limit).Skip(opts.Skip)
	if opts.Reverse {
		query.Reverse()
	}

	err := query.Find(to)
	if err != nil && err != ErrNotFound {
		return err
	}

	if err == ErrNotFound {
		ref := reflect.ValueOf(to)
		results := reflect.MakeSlice(reflect.Indirect(ref).Type(), 0, 0)
		reflect.Indirect(ref).Set(results)
	}
	return nil
}
Exemplo n.º 4
0
// AllByIndex gets all the records of a bucket that are indexed in the specified index
func (n *node) AllByIndex(fieldName string, to interface{}, options ...func(*index.Options)) error {
	if fieldName == "" {
		return n.All(to, options...)
	}

	ref := reflect.ValueOf(to)

	if ref.Kind() != reflect.Ptr || ref.Elem().Kind() != reflect.Slice {
		return ErrSlicePtrNeeded
	}

	typ := reflect.Indirect(ref).Type().Elem()

	if typ.Kind() == reflect.Ptr {
		typ = typ.Elem()
	}

	newElem := reflect.New(typ)

	cfg, err := extract(&newElem)
	if err != nil {
		return err
	}

	if cfg.ID.Name == fieldName {
		return n.All(to, options...)
	}

	opts := index.NewOptions()
	for _, fn := range options {
		fn(opts)
	}

	return n.readTx(func(tx *bolt.Tx) error {
		return n.allByIndex(tx, fieldName, cfg, &ref, opts)
	})
}
Exemplo n.º 5
0
func TestListIndexRange(t *testing.T) {
	dir, _ := ioutil.TempDir(os.TempDir(), "storm")
	defer os.RemoveAll(dir)
	db, _ := storm.Open(filepath.Join(dir, "storm.db"))
	defer db.Close()

	db.Bolt.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("test"))
		assert.NoError(t, err)

		idx, err := index.NewListIndex(b, []byte("index1"))
		assert.NoError(t, err)

		for i := 0; i < 10; i++ {
			val, _ := gob.Codec.Marshal(i)
			err = idx.Add(val, val)
			assert.NoError(t, err)
		}

		min, _ := gob.Codec.Marshal(3)
		max, _ := gob.Codec.Marshal(5)
		list, err := idx.Range(min, max, nil)
		assert.Len(t, list, 3)
		assert.NoError(t, err)
		assertEncodedIntListEqual(t, []int{3, 4, 5}, list)

		min, _ = gob.Codec.Marshal(11)
		max, _ = gob.Codec.Marshal(20)
		list, err = idx.Range(min, max, nil)
		assert.Len(t, list, 0)
		assert.NoError(t, err)

		min, _ = gob.Codec.Marshal(7)
		max, _ = gob.Codec.Marshal(2)
		list, err = idx.Range(min, max, nil)
		assert.Len(t, list, 0)
		assert.NoError(t, err)

		min, _ = gob.Codec.Marshal(-5)
		max, _ = gob.Codec.Marshal(2)
		list, err = idx.Range(min, max, nil)
		assert.Len(t, list, 0)
		assert.NoError(t, err)

		min, _ = gob.Codec.Marshal(3)
		max, _ = gob.Codec.Marshal(7)
		opts := index.NewOptions()
		opts.Skip = 2
		list, err = idx.Range(min, max, opts)
		assert.Len(t, list, 3)
		assert.NoError(t, err)
		assertEncodedIntListEqual(t, []int{5, 6, 7}, list)

		opts = index.NewOptions()
		opts.Limit = 2
		list, err = idx.Range(min, max, opts)
		assert.Len(t, list, 2)
		assert.NoError(t, err)
		assertEncodedIntListEqual(t, []int{3, 4}, list)

		opts = index.NewOptions()
		opts.Reverse = true
		opts.Skip = 2
		opts.Limit = 2
		list, err = idx.Range(min, max, opts)
		assert.Len(t, list, 2)
		assert.NoError(t, err)
		assertEncodedIntListEqual(t, []int{5, 4}, list)
		return nil
	})
}
Exemplo n.º 6
0
func TestListIndexAllRecords(t *testing.T) {
	dir, _ := ioutil.TempDir(os.TempDir(), "storm")
	defer os.RemoveAll(dir)
	db, _ := storm.Open(filepath.Join(dir, "storm.db"))
	defer db.Close()

	db.Bolt.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("test"))
		assert.NoError(t, err)

		idx, err := index.NewListIndex(b, []byte("lindex1"))
		assert.NoError(t, err)

		ids, err := idx.AllRecords(nil)
		assert.NoError(t, err)
		assert.Len(t, ids, 0)

		err = idx.Add([]byte("goodbye"), []byte("id2"))
		assert.NoError(t, err)
		assert.Equal(t, 1, countItems(t, idx.IndexBucket))

		err = idx.Add([]byte("goodbye"), []byte("id1"))
		assert.NoError(t, err)
		assert.Equal(t, 2, countItems(t, idx.IndexBucket))

		err = idx.Add([]byte("hello"), []byte("id4"))
		assert.NoError(t, err)
		assert.Equal(t, 3, countItems(t, idx.IndexBucket))

		err = idx.Add([]byte("hello"), []byte("id3"))
		assert.NoError(t, err)
		assert.Equal(t, 4, countItems(t, idx.IndexBucket))

		ids, err = idx.AllRecords(nil)
		assert.NoError(t, err)
		assert.Len(t, ids, 4)
		assert.Equal(t, []byte("id1"), ids[0])
		assert.Equal(t, []byte("id2"), ids[1])
		assert.Equal(t, []byte("id3"), ids[2])
		assert.Equal(t, []byte("id4"), ids[3])

		err = idx.RemoveID([]byte("id1"))
		assert.NoError(t, err)
		assert.Equal(t, 3, countItems(t, idx.IndexBucket))

		ids, err = idx.AllRecords(nil)
		assert.NoError(t, err)
		assert.Len(t, ids, 3)
		assert.Equal(t, []byte("id2"), ids[0])

		err = idx.Add([]byte("goodbye"), []byte("id1"))
		assert.NoError(t, err)
		assert.Equal(t, 4, countItems(t, idx.IndexBucket))

		opts := index.NewOptions()
		opts.Limit = 1
		ids, err = idx.AllRecords(opts)
		assert.Len(t, ids, 1)

		opts = index.NewOptions()
		opts.Skip = 2
		ids, err = idx.AllRecords(opts)
		assert.Len(t, ids, 2)

		opts = index.NewOptions()
		opts.Skip = 2
		opts.Limit = 3
		opts.Reverse = true
		ids, err = idx.AllRecords(opts)
		assert.NoError(t, err)
		assert.Len(t, ids, 2)
		assert.Equal(t, []byte("id2"), ids[0])

		return nil
	})
}
Exemplo n.º 7
0
func TestListIndex(t *testing.T) {
	dir, _ := ioutil.TempDir(os.TempDir(), "storm")
	defer os.RemoveAll(dir)
	db, _ := storm.Open(filepath.Join(dir, "storm.db"))
	defer db.Close()

	err := db.Bolt.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("test"))
		assert.NoError(t, err)

		idx, err := index.NewListIndex(b, []byte("lindex1"))
		assert.NoError(t, err)

		err = idx.Add([]byte("hello"), []byte("id1"))
		assert.NoError(t, err)

		err = idx.Add([]byte("hello"), []byte("id1"))
		assert.NoError(t, err)

		err = idx.Add([]byte("hello"), []byte("id2"))
		assert.NoError(t, err)

		err = idx.Add([]byte("goodbye"), []byte("id2"))
		assert.NoError(t, err)

		err = idx.Add(nil, []byte("id2"))
		assert.Error(t, err)
		assert.Equal(t, index.ErrNilParam, err)

		err = idx.Add([]byte("hi"), nil)
		assert.Error(t, err)
		assert.Equal(t, index.ErrNilParam, err)

		ids, err := idx.All([]byte("hello"), nil)
		assert.NoError(t, err)
		assert.Len(t, ids, 1)
		assert.Equal(t, []byte("id1"), ids[0])

		ids, err = idx.All([]byte("goodbye"), nil)
		assert.Len(t, ids, 1)
		assert.Equal(t, []byte("id2"), ids[0])

		ids, err = idx.All([]byte("yo"), nil)
		assert.Nil(t, ids)

		err = idx.RemoveID([]byte("id2"))
		assert.NoError(t, err)

		ids, err = idx.All([]byte("goodbye"), nil)
		assert.Len(t, ids, 0)

		err = idx.RemoveID(nil)
		assert.NoError(t, err)

		err = idx.RemoveID([]byte("id1"))
		assert.NoError(t, err)
		err = idx.RemoveID([]byte("id2"))
		assert.NoError(t, err)
		err = idx.RemoveID([]byte("id3"))
		assert.NoError(t, err)

		ids, err = idx.All([]byte("hello"), nil)
		assert.NoError(t, err)
		assert.Nil(t, ids)

		err = idx.Add([]byte("hello"), []byte("id1"))
		assert.NoError(t, err)

		err = idx.Add([]byte("hi"), []byte("id2"))
		assert.NoError(t, err)

		err = idx.Add([]byte("yo"), []byte("id3"))
		assert.NoError(t, err)

		err = idx.RemoveID([]byte("id2"))
		assert.NoError(t, err)

		ids, err = idx.All([]byte("hello"), nil)
		assert.Len(t, ids, 1)
		assert.Equal(t, []byte("id1"), ids[0])
		ids, err = idx.All([]byte("hi"), nil)
		assert.Len(t, ids, 0)
		ids, err = idx.All([]byte("yo"), nil)
		assert.Len(t, ids, 1)
		assert.Equal(t, []byte("id3"), ids[0])

		err = idx.RemoveID([]byte("id2"))
		assert.NoError(t, err)
		err = idx.RemoveID([]byte("id4"))
		assert.NoError(t, err)

		err = idx.Add([]byte("hey"), []byte("id1"))
		err = idx.Add([]byte("hey"), []byte("id2"))
		err = idx.Add([]byte("hey"), []byte("id3"))
		err = idx.Add([]byte("hey"), []byte("id4"))
		ids, err = idx.All([]byte("hey"), nil)
		assert.Len(t, ids, 4)

		opts := index.NewOptions()
		opts.Limit = 1
		ids, err = idx.All([]byte("hey"), opts)
		assert.Len(t, ids, 1)

		opts = index.NewOptions()
		opts.Skip = 2
		ids, err = idx.All([]byte("hey"), opts)
		assert.Len(t, ids, 2)

		opts = index.NewOptions()
		opts.Skip = 2
		opts.Limit = 3
		opts.Reverse = true
		ids, err = idx.All([]byte("hey"), opts)
		assert.Len(t, ids, 2)
		assert.Equal(t, []byte("id2"), ids[0])

		id := idx.Get([]byte("hey"))
		assert.Equal(t, []byte("id1"), id)

		err = idx.Remove([]byte("hey"))
		assert.NoError(t, err)
		ids, err = idx.All([]byte("hey"), nil)
		assert.NoError(t, err)
		assert.Len(t, ids, 0)

		ids, err = idx.All([]byte("hey"), nil)
		assert.NoError(t, err)
		assert.Len(t, ids, 0)
		return nil
	})

	assert.NoError(t, err)
}
Exemplo n.º 8
0
func TestUniqueIndex(t *testing.T) {
	dir, _ := ioutil.TempDir(os.TempDir(), "storm")
	defer os.RemoveAll(dir)
	db, _ := storm.Open(filepath.Join(dir, "storm.db"))
	defer db.Close()

	err := db.Bolt.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("test"))
		assert.NoError(t, err)

		idx, err := index.NewUniqueIndex(b, []byte("uindex1"))
		assert.NoError(t, err)

		err = idx.Add([]byte("hello"), []byte("id1"))
		assert.NoError(t, err)

		err = idx.Add([]byte("hello"), []byte("id1"))
		assert.NoError(t, err)

		err = idx.Add([]byte("hello"), []byte("id2"))
		assert.Error(t, err)
		assert.Equal(t, index.ErrAlreadyExists, err)

		err = idx.Add(nil, []byte("id2"))
		assert.Error(t, err)
		assert.Equal(t, index.ErrNilParam, err)

		err = idx.Add([]byte("hi"), nil)
		assert.Error(t, err)
		assert.Equal(t, index.ErrNilParam, err)

		id := idx.Get([]byte("hello"))
		assert.Equal(t, []byte("id1"), id)

		id = idx.Get([]byte("goodbye"))
		assert.Nil(t, id)

		err = idx.Remove([]byte("hello"))
		assert.NoError(t, err)

		err = idx.Remove(nil)
		assert.NoError(t, err)

		id = idx.Get([]byte("hello"))
		assert.Nil(t, id)

		err = idx.Add([]byte("hello"), []byte("id1"))
		assert.NoError(t, err)

		err = idx.Add([]byte("hi"), []byte("id2"))
		assert.NoError(t, err)

		err = idx.Add([]byte("yo"), []byte("id3"))
		assert.NoError(t, err)

		list, err := idx.AllRecords(nil)
		assert.NoError(t, err)
		assert.Len(t, list, 3)

		opts := index.NewOptions()
		opts.Limit = 2
		list, err = idx.AllRecords(opts)
		assert.NoError(t, err)
		assert.Len(t, list, 2)

		opts = index.NewOptions()
		opts.Skip = 2
		list, err = idx.AllRecords(opts)
		assert.NoError(t, err)
		assert.Len(t, list, 1)
		assert.Equal(t, []byte("id3"), list[0])

		opts = index.NewOptions()
		opts.Skip = 2
		opts.Limit = 1
		opts.Reverse = true
		list, err = idx.AllRecords(opts)
		assert.NoError(t, err)
		assert.Len(t, list, 1)
		assert.Equal(t, []byte("id1"), list[0])

		err = idx.RemoveID([]byte("id2"))
		assert.NoError(t, err)

		id = idx.Get([]byte("hello"))
		assert.Equal(t, []byte("id1"), id)
		id = idx.Get([]byte("hi"))
		assert.Nil(t, id)
		id = idx.Get([]byte("yo"))
		assert.Equal(t, []byte("id3"), id)
		ids, err := idx.All([]byte("yo"), nil)
		assert.NoError(t, err)
		assert.Len(t, ids, 1)
		assert.Equal(t, []byte("id3"), ids[0])

		err = idx.RemoveID([]byte("id2"))
		assert.NoError(t, err)
		err = idx.RemoveID([]byte("id4"))
		assert.NoError(t, err)
		return nil
	})

	assert.NoError(t, err)
}