Skip to content

anyproto/any-store

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Any Store

Any Store is a document-oriented database with a MongoDB-like query language. It is built on top of SQLite. The database supports transactions and indexes.

Warning: This library is not well tested and the API is still unstable. However, it is under active development.

Installation

To install Any Store, run:

go get github.com/anyproto/any-store

For the CLI interface, run:

go install github.com/anyproto/any-store/cmd/any-store-cli@latest

Usage Example

Here is an all-in-one example demonstrating various operations with Any Store:

package main

import (
	"context"
	"fmt"
	"log"

	anystore "github.com/anyproto/any-store"
	"github.com/anyproto/any-store/anyenc"
)

var ctx = context.Background()

func main() {
	// open database
	db, err := anystore.Open(ctx, "/tmp/file.db", nil)
	if err != nil {
		log.Fatalf("unable to open db: %v", err)
	}

	defer func() {
		if err = db.Close(); err != nil {
			log.Fatalf("close db eroor: %v", err)
		}
	}()

	coll, err := db.Collection(ctx, "users")
	if err != nil {
		log.Fatalf("unable to open collection: %v", err)
	}

	// insert document, convert from json
	doc := anyenc.MustParseJson(`{"id":1, "name": "John"}`)
	err = coll.Insert(ctx, doc)
	if err != nil {
		log.Fatalf("unable to insert document: %v", err)
	}

	// create document
	a := &anyenc.Arena{}
	doc = a.NewObject()
	doc.Set("id", a.NewNumberInt(2))
	doc.Set("name", a.NewString("Jane"))
	err = coll.Insert(ctx, doc)
	if err != nil {
		log.Fatalf("unable to insert document: %v", err)
	}

	// batch insert
	if err = coll.Insert(ctx,
		anyenc.MustParseJson(`{"id":3, "name": "Alex"}`),
		anyenc.MustParseJson(`{"id":4, "name": "rob"}`),
		anyenc.MustParseJson(`{"id":5, "name": "Paul"}`),
	); err != nil {
		log.Fatalf("unable to insert document: %v", err)
	}

	// upsert
	err = coll.UpsertOne(ctx, anyenc.MustParseJson(`{"id":6, "name": "Mike"}`))
	if err != nil {
		log.Fatalf("unable to insert document: %v", err)
	}

	// update one
	if err = coll.UpdateOne(ctx, anyenc.MustParseJson(`{"id":4, "name": "Rob"}`)); err != nil {
		log.Fatalf("unable to update document: %v", err)
	}

	// find by id
	res, err := coll.FindId(ctx, 2)
	if err != nil {
		log.Fatalf("unable to find document: %v", err)
	}
	fmt.Println("document found:", res.Value().String())

	// collection count
	count, err := coll.Count(ctx)
	if err != nil {
		log.Fatalf("unable to count documents: %v", err)
	}
	fmt.Println("document count:", count)

	// find many with condition
	iter, err := coll.Find(`{"id":{"$in":[1,2,3]}}`).Sort("-name").Limit(2).Offset(1).Iter(ctx)
	if err != nil {
		log.Fatalf("query failed: %v", err)
	}
	defer func() {
		if err = iter.Close(); err != nil {
			log.Fatalf("unable to close iterator: %v", err)
		}
	}()
	for iter.Next() {
		res, err = iter.Doc()
		if err != nil {
			log.Fatalf("load document error: %v", err)
		}
		fmt.Println("findMany:", res.Value().String())
	}

	// create index
	if err = coll.EnsureIndex(ctx, anystore.IndexInfo{Fields: []string{"name"}}); err != nil {
		fmt.Println("unable to ensure index:", err)
	}

	// update many
	result, err := coll.Find(`{"name": {"$in": ["Rob","Alex"]}}`).Update(ctx, `{"$inc":{"rating":0.1}}`)
	if err != nil {
		log.Fatalf("cannot update document: %v", err)
	}
	fmt.Printf("updated documents count: %d\n", result.Modified)

	// transaction
	tx, err := db.WriteTx(ctx)
	if err != nil {
		log.Fatalf("cannot create tx: %v", err)
	}

	// it's important to pass tx.Context() to any operations within transaction
	// because sqlite can handle only one transaction in time - passing ctx instead tx.Context() will cause possibly deadlock
	result, err = coll.Find(`{"name": "Mike"}`).Delete(tx.Context())
	if err != nil {
		log.Fatalf("cannot delete document: %v", err)
	}
	fmt.Println("deleted count:", result.Modified)

	// document is deleted inside transaction
	count, err = coll.Find(`{"name": "Mike"}`).Count(tx.Context())
	if err != nil {
		log.Fatalf("cannot count documents: %v", err)
	}
	fmt.Println("count within transaction:", count)

	// by passing other ctx we can find Mike in other transaction
	count, err = coll.Find(`{"name": "Mike"}`).Count(ctx)
	if err != nil {
		log.Fatalf("cannot count documents: %v", err)
	}
	fmt.Println("count outside transaction:", count)

	if err = tx.Commit(); err != nil {
		log.Fatalf("cannot commit transaction: %v", err)
	}

}

License

This project is licensed under the MIT License. See the LICENSE file for details.

About

No description, website, or topics provided.

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •