import * as OrbitdbStore from "orbit-db-store" ; import * as OrbitDB from "orbit-db" ; import Collection from "./Collection" ; import { Ipfs } from "ipfs" ; import { EventEmitter } from "events" ; import { IdentityProvider } from "orbit-db-identity-provider" ; import { CollectionOptions , OrbitDBOptions , IStoreOptions , IOpenOptions , ICreateOptions , } from "./interfaces" ; import { LogEntry } from "ipfs-log" ; const Index = require ( "./StoreIndex" ) ; const debug = require ( "debug" ) ( "aviondb:store" ) ; let orbitdb ; class Store extends OrbitdbStore { _type : string ; _orbitdb : OrbitDB ; openCollections : any ; _index : any ; events : EventEmitter ; address : { root : string ; path : string ; } ; constructor ( ipfs , id , dbname , options ? ) { const opts = { Index } ; Object . assign ( opts , options ) ; super ( ipfs , id , dbname , opts ) ; this . _type = "aviondb" ; if ( options . orbitdb ) { this . _orbitdb = options . orbitdb ; } this . openCollections = { } ; this . _index . store = this ; this . events . on ( "write" , ( address , entry , heads ) => { this . _index . handleEntry ( entry ) ; } ) ; this . events . on ( "replicate.progress" , ( address , hash , entry , progress , total ) => { this . _index . handleEntry ( entry ) ; } ) ; this . events . on ( "db.createCollection" , async ( name , address ) => { if ( ! this . openCollections [ name ] ) { this . openCollections [ name ] = await this . openCollection ( address ) ; } } ) ; } param { String } name param { CollectionOptions } options param { ICreateOptions } orbitDbOptions returns { Promise < Collection > } async createCollection ( name , options = { overwrite : false } , orbitDbOptions = { } ) { orbitDbOptions . meta = { parent : this . address . root , } ; const { overwrite } = options ; if ( overwrite ) { orbitDbOptions . overwrite = true ; } if ( ! name || typeof name !== "string" ) { throw "name must be a string" ; } if ( this . _index . get ( name ) && ! overwrite ) { throw `Collection with name: ${ name } already exists.` ; } const collection = await this . _orbitdb . create ( name , "aviondb.collection" , orbitDbOptions ) ; this . openCollections [ name ] = collection ; await this . _addOperation ( { op : "collection.create" , address : collection . address . toString ( ) , name , } ) ; return collection ; } param { String } name param { CollectionOptions } options param { IOpenOptions } orbitDbOptions returns { Promise < Collection > } async openCollection ( name , options = { create : false } , orbitDbOptions ? ) { const { create } = options ; if ( ! name || typeof name !== "string" ) { throw "name must be a string" ; } if ( ! this . _index . get ( name ) && create !== true ) { throw `Collection with name of "${ name }" does not exist` ; } if ( this . openCollections [ name ] ) { return this . openCollections [ name ] ; } if ( create === true ) { return await this . createCollection ( name ) ; } else { const collectionInfo = this . _index . get ( name ) ; const collection = await this . _orbitdb . open ( collectionInfo . address , orbitDbOptions ) ; await collection . load ( ) ; this . openCollections [ name ] = collection ; return collection ; } } param { string } name param { CollectionOptions } options param { IStoreOptions } orbitDbOptions returns { Promise < Collection > } async initCollection ( name , options ? , orbitDbOptions ? ) { if ( ! name || typeof name !== "string" ) { throw "name must be a string" ; } if ( this . _index . get ( name ) ) { return await this . openCollection ( name , options , orbitDbOptions ) ; } if ( ! this . _index . get ( name ) ) { return await this . createCollection ( name , options , orbitDbOptions ) ; } } param { string } name param { JSON Object async dropCollection ( name , options = { } ) { if ( ! name || typeof name !== "string" ) { throw "Name must be a string" ; } const collectionInfo = this . _index . _index [ name ] ; await this . _addOperation ( { op : "collection.drop" , address : collectionInfo . address , name , } ) ; } param { JSON Object param { JSON Object returns { Array < string > } listCollections ( filter = { } , options = { } ) { return Object . keys ( this . _index . _index ) ; } param { string } name returns { Promise < Collection > } collection ( name ) { if ( ! name || typeof name !== "string" ) { throw "Name must be a string" ; } if ( ! this . openCollections [ name ] ) { throw `Collection: ${ name } is not open.` ; } return this . openCollections [ name ] ; } param { string } name async closeCollection ( name ) { if ( this . openCollections [ name ] ) { await this . openCollections [ name ] . close ( ) ; } } async load ( number , options = { } ) { await super . load ( number , options ) ; debug ( "datastore is loading" ) ; for ( const name of this . listCollections ( ) ) { await this . openCollection ( name ) ; } } async close ( ) { for ( const name in this . openCollections ) { await this . openCollections [ name ] . close ( ) ; } await super . close ( ) ; } param { string } name param { Ipfs } ipfs param { IStoreOptions } options param { OrbitDBOptions } orbitDbOptions returns { Promise < Store > } static async create ( name , ipfs , options ? , orbitDbOptions ? ) { if ( ! orbitdb ) { orbitdb = await OrbitDB . createInstance ( ipfs , orbitDbOptions ) ; } const store = await orbitdb . create ( name , "aviondb" , options ) ; store . _orbitdb = orbitdb ; await store . load ( ) ; return store ; } param { string } address param { Ipfs } ipfs param { IStoreOptions } options param { OrbitDBOptions } orbitDbOptions returns { Promise < Store > } static async open ( address , ipfs , options ? , orbitDbOptions ? ) { if ( ! orbitdb ) { orbitdb = await OrbitDB . createInstance ( ipfs , orbitDbOptions ) ; } const store = await orbitdb . open ( address , options ) ; store . _orbitdb = orbitdb ; await store . load ( ) ; return store ; } param { string } name param { Ipfs } ipfs param { IStoreOptions } options param { OrbitDBOptions } orbitDbOptions returns { Promise < Store > } static async init ( name , ipfs , options ? , orbitDbOptions ? ) { if ( ! name || typeof name !== "string" ) { throw "name must be a string" ; } orbitdb = await OrbitDB . createInstance ( ipfs , orbitDbOptions ) ; const dbAddress = await orbitdb . _determineAddress ( name , "aviondb" , options ) ; const cache = await orbitdb . _requestCache ( dbAddress , orbitdb . directory ) ; const haveDB = await orbitdb . _haveLocalData ( cache , dbAddress ) ; if ( haveDB ) { return await Store . open ( dbAddress , ipfs , options , orbitDbOptions ) ; } else { return await Store . create ( name , ipfs , options , orbitDbOptions ) ; } } } OrbitDB . addDatabaseType ( "aviondb.collection" , Collection ) ; OrbitDB . addDatabaseType ( "aviondb" , Store ) ; export default Store ;