├── .gitignore ├── README.md ├── package.json └── src ├── collection.js ├── compassdb.js ├── constants.js ├── document.js └── response.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CompassDB 2 | 3 | CompassDB is an open soruce ORM for [Gaia] (https://github.com/blockstack/gaia) storage. 4 | 5 | It provides an abstraction of a database over the file-based storage system provided by Gaia. 6 | It’s compatible with the Blockstack ecosystem which leverages the Gaia storage, to provide database methods for developers. 7 | ## Getting Started 8 | To get started, 9 | > `npm install compass-db` 10 | 11 | Or you can download the compassDB-min-js from here. 12 | 13 | ### Example: Initialization 14 | 15 | ```javascript 16 | // Create reliable connection with CompassDB 17 | const compassdb = new CompassDB(); 18 | 19 | // Creating a collection 20 | const collection = compassdb.newCollectionInstance(COLLECTION_NAME, true); 21 | collection.createCollection() 22 | .then((successResponse) => { 23 | // Promise Resolved 24 | .catch((failureResponse) => { 25 | // Promise Rejected 26 | }); 27 | }); 28 | 29 | ``` 30 | ## Core Components 31 | 32 | CompassDB uses abstraction concepts to render the database and create a relationship with the actual Gaia storage. 33 | 34 | The two main components are: 35 | 36 | * **Documents:** These are the basic structural unit of the database. Every document contains a group of key-value pairs. These are used to identify and manage request of files in the storage. 37 | A basic constructor declaration is done with `constructor(collectionName, encrypt_decrypt).` 38 | 39 | * **Collections** Collections are described as a set of Documents. Every Collection instance contains the name of all the Documents within that set and their status. 40 | 41 | To setup a new connection, we must first create an instance of CompassDB followed by creating a new collection for usage(as shown in the example previously). 42 | 43 | ## Methods 44 | ### Collection Operations 45 | 46 | * **createCollection:** Creates a new collection. 47 | * **dropCollection:** Drops an existing collection 48 | 49 | ### Document Operations 50 | 51 | * **insert:** inserts value within a document 52 | * **update:** updates document with help of Id reference 53 | * **findOne:** Finds document within collection 54 | * **findAll:** Finds all documents with certain properties within a collection 55 | * **deleteOne:** Deletes one document from the collection 56 | * **deleteAll:** Deletes all documents with certain properties within a collection 57 | 58 | ### Types of Response 59 | 60 | * **successResponse:** 61 | Status code: 200, Status text: `SUCCESS` , Description and Payload 62 | 63 | * **failureResponse:** 64 | Status code: 400, Status text: `FAILURE`, Description 65 | 66 | 67 | 68 | ----------------------- 69 | ## createCollection 70 | `.createCollection()` creates a new collection. It fetches the list of existing collections and verifies if the requested collection exists or not. 71 | 72 | 73 | #### Arguments: 74 | No arguments; But to instantiate a Collection object, collectionName, encrypt_decrypt these two infomration are required. 75 | 76 | #### Returns: 77 | Promise. 78 | 79 | #### Example: 80 | ```javascript 81 | const collection = compassdb.newCollectionInstance(COLLECTION_NAME, true); 82 | collection.createCollection() 83 | .then((successResponse) => { 84 | // Promise Resolved 85 | }) 86 | .catch((failureResponse) => { 87 | // Promise Rejected 88 | }); 89 | ``` 90 | 91 | ## dropCollection 92 | `.dropCollection()` implements a soft delete of the collection. It changes the `activeState` to false. 93 | 94 | #### Arguments: 95 | No arguments; 96 | 97 | #### Returns: 98 | Promise. 99 | 100 | 101 | #### Example: 102 | ```javascript 103 | collection.dropCollection() 104 | .then((successResponse) => { 105 | // Promise Resolved 106 | }) 107 | .catch((failureResponse) => { 108 | // Promise Rejected 109 | }); 110 | ``` 111 | 112 | ## insert 113 | 114 | `.insert(newDocument)` puts a document into the collection. 115 | 116 | #### Arguments: 117 | `newDocument`, reference to the document that is to be pushed into the collection. 118 | 119 | #### Returns: 120 | Promise. 121 | 122 | If successful then will return the inserted `Document Object` in successResponse.payload 123 | 124 | #### Example: 125 | ```javascript 126 | collection.insert(newDocument) 127 | .then((successResponse) => { 128 | // Promise Resolved 129 | }) 130 | .catch((failureResponse) => { 131 | // Promise Rejected 132 | }); 133 | ``` 134 | 135 | ## update 136 | 137 | `.update(id,queries)` is used for updating documents already inserted in a collection. 138 | 139 | #### Arguments: 140 | `id` and `query`. 141 | The id is used to find the particular document in the collection and after that, the requested queries are processed if eligible. 142 | 143 | #### Returns: 144 | Promise. 145 | 146 | If successful then will return the updated `Document Object` in successResponse.payload 147 | 148 | #### Example: 149 | ```javascript 150 | const id = 1; 151 | collection.update(id, { 'title' : 'CompassDB', 'note' : 'Most promising ORM' }) 152 | .then((successResponse) => { 153 | // Promise Resolved 154 | }) 155 | .catch((failureResponse) => { 156 | // Promise Rejected 157 | }); 158 | ``` 159 | 160 | ## findOne 161 | 162 | `.findOne(queries)` fetches the first document in the collection that contains the given queries. 163 | 164 | #### Arguments: 165 | `query`. 166 | The search result brings the first document that matches the description of the key-value pair of the queries. If not found, it gives a `failureResponse` in return. 167 | 168 | #### Returns: 169 | Promise 170 | 171 | If successful then will return the `Document Object` in successResponse.payload 172 | 173 | #### Example: 174 | ```javascript 175 | collection.findOne({ 'title' : 'CompassDB', 'note' : 'Most promising ORM' }) 176 | .then((successResponse) => { 177 | // Promise Resolved 178 | }) 179 | .catch((failureResponse) => { 180 | // Promise Rejected 181 | }); 182 | ``` 183 | 184 | ## findAll 185 | 186 | `.findAll(queries)` fetches all the documents in the collection that contains the given queries as an array of object. 187 | 188 | #### Arguments: 189 | `query`. 190 | The search result brings all documents that match the description of the key-value pair of the queries. If not a single document found, it gives a `failureResponse` in return. 191 | 192 | #### Returns: 193 | Promise 194 | 195 | If successful then will return an array of `Document Objects` in successResponse.payload 196 | 197 | #### Example: 198 | ```javascript 199 | collection.findAll({ 'title' : 'CompassDB', 'note' : 'Most promising ORM' }) 200 | .then((successResponse) => { 201 | // Promise Resolved 202 | }) 203 | .catch((failureResponse) => { 204 | // Promise Rejected 205 | }); 206 | ``` 207 | 208 | ## deleteOne 209 | 210 | `.deleteOne(query)` removes the first document that is found matching the query. Here, the `isActive` state of the document is changed to false. 211 | 212 | #### Arguments: 213 | `query` 214 | deletes the first document that matches the description of the key-value pair of the queries. If not found, it gives a `failureResponse` in return. 215 | 216 | #### Returns: 217 | Promise. 218 | 219 | If successful then will return the deleted `Document Object` in successResponse.payload 220 | 221 | #### Example: 222 | 223 | ```javascript 224 | collection.deleteOne({ 'title' : 'another', 'note' : 'test' }) 225 | .then((successResponse) => { 226 | // Promise Resolved 227 | }) 228 | .catch((failureResponse) => { 229 | // Promise Rejected 230 | }); 231 | ``` 232 | 233 | ## deleteAll 234 | 235 | `.deleteAll(query)` removes the all the documents that match the query. Here, the `isActive` state of the documents are changed to false. 236 | 237 | #### Arguments: 238 | `query` 239 | deletes all documents that match the description of the key-value pair of the queries. If not found, it gives a `failureResponse` in return. 240 | 241 | #### Returns: 242 | Promise. 243 | 244 | If successful then will return an array of deleted `Document Objects` in successResponse.payload 245 | 246 | #### Example: 247 | 248 | ```javascript 249 | collection.deleteAll({ 'title' : 'check', 'note' : 'check' }) 250 | .then((successResponse) => { 251 | // Promise Resolved 252 | }) 253 | .catch((failureResponse) => { 254 | // Promise Rejected 255 | }); 256 | ``` 257 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "compass-db", 3 | "version": "0.1.0", 4 | "description": "Open Source ORM for Gaia", 5 | "main": "src/compassdb.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/eder-ai/compass-db.git" 12 | }, 13 | "keywords": [ 14 | "gaia", 15 | "blockstack", 16 | "blockstack-storage" 17 | ], 18 | "author": "Eder AI (http://www.eder.io/)", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/eder-ai/compass-db/issues" 22 | }, 23 | "homepage": "https://github.com/eder-ai/compass-db#readme" 24 | } 25 | -------------------------------------------------------------------------------- /src/collection.js: -------------------------------------------------------------------------------- 1 | import { successResponse, failureResponse } from './response'; 2 | import { 3 | COLLECTION_ALREADY_EXISTS, 4 | SOFT_DELETED_THE_COLLECTION, 5 | SOME_PROBLEM_OCCURED, 6 | ERROR_IN_DROPING_COLLECTION, 7 | ALREADY_INACTIVE_COLLECTION, 8 | COLLECTION_DOESNT_EXIST, 9 | LIST_UPDATED, 10 | ERROR_LIST_NOT_UPDATED, 11 | COLLECTION_MASTER 12 | } from './constants'; 13 | 14 | class Collection { 15 | 16 | constructor(collectionName, encrypt_decrypt) { 17 | this.collectionName = collectionName; 18 | this.encrypt_decrypt = encrypt_decrypt; 19 | this.collectionExists = false; 20 | this.collectionIsActive = false; 21 | this.LIST_OF_ALL_COLLECTIONS = COLLECTION_MASTER; 22 | } 23 | 24 | createCollection() { 25 | return new Promise((resolve, reject) => { 26 | blockstack.getFile(this.LIST_OF_ALL_COLLECTIONS, this.encrypt_decrypt) 27 | // if the Library is not being called for the first time 28 | // then use list_of_all_collections.json to check whether a collection exists or not 29 | .then((fileText) => { 30 | const content = JSON.parse(fileText); 31 | console.log(content); 32 | let items = []; 33 | // check if list_of_all_collections.json contains collection 34 | content.forEach((eachCollection) => { 35 | // if collection is in list_of_all_collections.json then don't create a new one 36 | // and set the properties of the collection for this.instance 37 | if(eachCollection.name === this.collectionName){ 38 | this.collectionExists = true; 39 | this.collectionIsActive = eachCollection.isActive; 40 | successResponse.description = COLLECTION_ALREADY_EXISTS; 41 | resolve(successResponse); 42 | } 43 | items.push(eachCollection); 44 | }); 45 | 46 | // if list_of_all_collections.json doesn't have collection then create a new one 47 | if(!this.collectionExists){ 48 | const item = { 49 | name: this.collectionName, 50 | isActive: true 51 | } 52 | items.push(item); 53 | // add this new collection in list_of_all_collections.json 54 | // console.log('collection doesn\'t exist but list_of_all_collections does exist'); 55 | this.updateEntryInList(items) 56 | .then((messageFromUpdateEntryInList) => { 57 | this.collectionExists = true; 58 | this.collectionIsActive = true; 59 | successResponse.description = messageFromUpdateEntryInList; 60 | resolve(successResponse); 61 | }) 62 | .catch((messageFromUpdateEntryInList) => { 63 | failureResponse.description = messageFromUpdateEntryInList; 64 | reject(failureResponse); 65 | }); 66 | } 67 | }) 68 | // if the Library is called for the first time 69 | // then create a file list_of_all_collections.json to store details of all collections, 70 | // it will help us in knowing whether a collection is active or not 71 | .catch(() => { 72 | let items = []; 73 | const item = { 74 | name: this.collectionName, 75 | isActive: true 76 | } 77 | items.push(item); 78 | // console.log('Library is being called for the first time'); 79 | this.updateEntryInList(items) 80 | .then((messageFromUpdateEntryInList) => { 81 | this.collectionExists = true; 82 | this.collectionIsActive = true; 83 | successResponse.description = messageFromUpdateEntryInList; 84 | resolve(successResponse); 85 | }) 86 | .catch((messageFromUpdateEntryInList) => { 87 | failureResponse.description = messageFromUpdateEntryInList; 88 | reject(failureResponse); 89 | }); 90 | }); 91 | }); 92 | } 93 | 94 | // get current status of the collection 95 | getCollectionStatus() { 96 | console.log(this.collectionName, this.collectionExists, this.collectionIsActive); 97 | } 98 | 99 | dropCollection() { 100 | return new Promise((resolve, reject) => { 101 | // if collection exists and is active 102 | if(this.collectionExists && this.collectionIsActive) { 103 | // get the list of collections 104 | blockstack.getFile(this.LIST_OF_ALL_COLLECTIONS, this.encrypt_decrypt) 105 | .then((fileText) => { 106 | const content = JSON.parse(fileText); 107 | 108 | let items = []; 109 | // update this collection to be inactive 110 | content.forEach((eachCollection) => { 111 | if(eachBrickset.name === this.collectionName){ 112 | eachBrickset.isActive = false; 113 | } 114 | 115 | items.push(eachCollection); 116 | 117 | this.updateEntryInList(items) 118 | .then((messageFromUpdateEntryInList) => { 119 | this.collectionIsActive = false; 120 | successResponse.description = SOFT_DELETED_THE_COLLECTION; 121 | successResponse.moreDescription = messageFromUpdateEntryInList; 122 | resolve(successResponse); 123 | }) 124 | .catch((messageFromUpdateEntryInList) => { 125 | failureResponse.description = `${SOME_PROBLEM_OCCURED}: ${messageFromUpdateEntryInList}`; 126 | reject(failureResponse); 127 | }); 128 | }); 129 | }) 130 | .catch((err) => { 131 | failureResponse.description = `${ERROR_IN_DROPING_COLLECTION}: ${err}`; 132 | reject(failureResponse); 133 | }); 134 | } else { 135 | if (!this.collectionIsActive){ 136 | successResponse.description = ALREADY_INACTIVE_COLLECTION; 137 | } else { 138 | successResponse.description = COLLECTION_DOESNT_EXIST; 139 | } 140 | resolve(successResponse); 141 | } 142 | }); 143 | } 144 | 145 | // common code to update list_of_all_collections.json 146 | updateEntryInList(items) { 147 | return new Promise((resolve, reject) => { 148 | blockstack.putFile(this.LIST_OF_ALL_COLLECTIONS, JSON.stringify(items), this.encrypt_decrypt) 149 | .then(() => { 150 | let message = LIST_UPDATED; 151 | resolve(message); 152 | }) 153 | .catch((err) => { 154 | let message = `${ERROR_LIST_NOT_UPDATED} : ${err}`; 155 | reject(message); 156 | }); 157 | }); 158 | } 159 | 160 | } 161 | 162 | export default Collection; 163 | -------------------------------------------------------------------------------- /src/compassdb.js: -------------------------------------------------------------------------------- 1 | import Document from './document'; 2 | 3 | class CompassDB { 4 | 5 | constructor() { 6 | this.init(); 7 | } 8 | 9 | init() { 10 | //add connection logic - if required 11 | console.log('Setting up connection'); 12 | } 13 | 14 | newCollectionInstance(collectionName, encrypt_decrypt) { 15 | return new Document(collectionName, encrypt_decrypt); 16 | } 17 | 18 | } 19 | 20 | export default CompassDB; 21 | -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | export const COLLECTION_ALREADY_EXISTS = 'Collection already exists'; 2 | export const SOFT_DELETED_THE_COLLECTION = 'Soft-deleted the collection'; 3 | export const SOME_PROBLEM_OCCURED = 'Some problem occurred'; 4 | export const ERROR_IN_DROPING_COLLECTION = 'Error in collection'; 5 | export const ALREADY_INACTIVE_COLLECTION = 'Already inactive collection'; 6 | export const COLLECTION_DOESNT_EXIST = 'Collection doesn\'t exist'; 7 | export const LIST_UPDATED = 'list_of_all_collections.json updated'; 8 | export const ERROR_LIST_NOT_UPDATED = 'Error while operating list_of_all_collections.json file'; 9 | export const COLLECTION_NOT_ACTIVE = 'This Collection is not active'; 10 | 11 | export const DOCUMENT_ADDED = 'Document has been added to the collection'; 12 | export const ERROR_IN_ADDING_DOCUMENT = 'Some problem occured while adding the document'; 13 | export const DOCUMENT_FOUND = 'Found the document'; 14 | export const DOCUMENT_NOT_FOUND = 'Not able to find the document'; 15 | export const ERROR_IN_FINDING_DOCUMENT = 'Error in finding the document'; 16 | export const DOCUMENT_DELETED = 'Document has been deleted from the collection'; 17 | export const ERROR_IN_DELETING_DOCUMENT = 'Some problem occured while deleting the document'; 18 | export const DOCUMENT_UPDATED = 'Document has been updated from the collection'; 19 | export const ERROR_IN_UPDATING_DOCUMENT = 'Some problem occured while updating the document'; 20 | 21 | export const COLLECTION_MASTER = 'compassCollectionMaster.json'; 22 | -------------------------------------------------------------------------------- /src/document.js: -------------------------------------------------------------------------------- 1 | import Collection from './collection'; 2 | import { successResponse, failureResponse } from './response'; 3 | import { 4 | DOCUMENT_ADDED, 5 | ERROR_IN_ADDING_DOCUMENT, 6 | COLLECTION_NOT_ACTIVE, 7 | COLLECTION_DOESNT_EXIST, 8 | DOCUMENT_FOUND, 9 | DOCUMENT_NOT_FOUND, 10 | ERROR_IN_FINDING_DOCUMENT, 11 | DOCUMENT_DELETED, 12 | ERROR_IN_DELETING_DOCUMENT, 13 | DOCUMENT_UPDATED, 14 | ERROR_IN_UPDATING_DOCUMENT 15 | } from './constants'; 16 | 17 | class Document extends Collection { 18 | 19 | constructor(collectionName, encrypt_decrypt) { 20 | super(collectionName, encrypt_decrypt); 21 | } 22 | 23 | insert(newDocument) { 24 | return new Promise((resolve, reject) => { 25 | // if collection exists and is active 26 | if(this.collectionExists && this.collectionIsActive) { 27 | blockstack.getFile(this.collectionName, this.encrypt_decrypt) 28 | .then((fileText) => { 29 | let items = JSON.parse(fileText); 30 | 31 | newDocument.id = items.length; 32 | newDocument.createdAt = Date.now(); 33 | newDocument.isActive = true; 34 | 35 | items.push(newDocument); 36 | 37 | blockstack.putFile(this.collectionName, JSON.stringify(items), this.encrypt_decrypt) 38 | .then(() => { 39 | successResponse.description = DOCUMENT_ADDED; 40 | successResponse.payload = newDocument; 41 | resolve(successResponse); 42 | }) 43 | .catch(() => { 44 | failureResponse.description = ERROR_IN_ADDING_DOCUMENT; 45 | reject(failureResponse); 46 | }); 47 | }) 48 | .catch(() => { 49 | // collection is not a file yet 50 | let items = []; 51 | newDocument.id = items.length; 52 | newDocument.createdAt = Date.now(); 53 | newDocument.isActive = true; 54 | 55 | items.push(newDocument); 56 | 57 | blockstack.putFile(this.collectionName, JSON.stringify(items), this.encrypt_decrypt) 58 | .then(() => {; 59 | successResponse.description = DOCUMENT_ADDED; 60 | successResponse.payload = newDocument; 61 | resolve(successResponse); 62 | }) 63 | .catch(() => { 64 | failureResponse.description = ERROR_IN_ADDING_DOCUMENT; 65 | reject(failureResponse); 66 | }); 67 | }); 68 | } else { 69 | if (!this.collectionIsActive){ 70 | failureResponse.description = COLLECTION_NOT_ACTIVE; 71 | } else { 72 | failureResponse.description = COLLECTION_DOESNT_EXIST; 73 | } 74 | reject(failureResponse); 75 | } 76 | }); 77 | } 78 | 79 | findOne(query) { 80 | const keys = Object.getOwnPropertyNames(query); 81 | 82 | return new Promise((resolve, reject) => { 83 | // if collection exists and is active 84 | if(this.collectionExists && this.collectionIsActive) { 85 | blockstack.getFile(this.collectionName, this.encrypt_decrypt) 86 | .then((fileText) => { 87 | const content = JSON.parse(fileText); 88 | 89 | let checkSearchParameters = []; 90 | let addToList = true; 91 | let index = 0; 92 | 93 | for(let i = 0; i < keys.length; i++){ 94 | checkSearchParameters[i] = false; 95 | } 96 | 97 | content.forEach((item) => { 98 | index = 0; 99 | addToList = true; 100 | 101 | keys.forEach((key) => { 102 | if (item.hasOwnProperty(key)) { 103 | if((item[key] === query[key]) && item.isActive) { 104 | checkSearchParameters[index] = true; 105 | } 106 | } 107 | index++; 108 | }); 109 | 110 | checkSearchParameters.forEach((value) => { 111 | if (!value) { 112 | addToList = false; 113 | } 114 | }); 115 | 116 | if (addToList) { 117 | successResponse.description = DOCUMENT_FOUND; 118 | successResponse.payload = item; 119 | resolve(successResponse); 120 | } 121 | 122 | for(let i = 0; i < keys.length; i++){ 123 | checkSearchParameters[i] = false; 124 | } 125 | }); 126 | failureResponse.description = DOCUMENT_NOT_FOUND; 127 | reject(failureResponse); 128 | }) 129 | .catch(() => { 130 | failureResponse.description = ERROR_IN_FINDING_DOCUMENT; 131 | reject(failureResponse); 132 | }); 133 | } else { 134 | if (!this.collectionIsActive){ 135 | failureResponse.description = COLLECTION_NOT_ACTIVE; 136 | } else { 137 | failureResponse.description = COLLECTION_DOESNT_EXIST; 138 | } 139 | reject(failureResponse); 140 | } 141 | }); 142 | } 143 | 144 | findAll(query) { 145 | const keys = Object.getOwnPropertyNames(query); 146 | 147 | return new Promise((resolve, reject) => { 148 | // if collection exists and is active 149 | if(this.collectionExists && this.collectionIsActive) { 150 | blockstack.getFile(this.collectionName, this.encrypt_decrypt) 151 | .then((fileText) => { 152 | const content = JSON.parse(fileText); 153 | 154 | let found = false; 155 | let items = []; 156 | let checkSearchParameters = []; 157 | let addToList = true; 158 | let index = 0; 159 | 160 | for(let i = 0; i < keys.length; i++){ 161 | checkSearchParameters[i] = false; 162 | } 163 | 164 | content.forEach((item) => { 165 | index = 0; 166 | addToList = true; 167 | 168 | keys.forEach((key) => { 169 | if (item.hasOwnProperty(key)) { 170 | if((item[key] === query[key]) && item.isActive) { 171 | checkSearchParameters[index] = true; 172 | } 173 | } 174 | index++; 175 | }); 176 | 177 | checkSearchParameters.forEach((value) => { 178 | if (!value) { 179 | addToList = false; 180 | } 181 | }); 182 | 183 | if (addToList) { 184 | items.push(item); 185 | found = true; 186 | } 187 | 188 | for(let i = 0; i < keys.length; i++){ 189 | checkSearchParameters[i] = false; 190 | } 191 | }); 192 | 193 | if (found) { 194 | successResponse.description = DOCUMENT_FOUND; 195 | successResponse.payload = items; 196 | resolve(successResponse); 197 | } else { 198 | failureResponse.description = DOCUMENT_NOT_FOUND; 199 | reject(failureResponse); 200 | } 201 | }) 202 | .catch(() => { 203 | failureResponse.description = ERROR_IN_FINDING_DOCUMENT; 204 | reject(failureResponse); 205 | }); 206 | } else { 207 | if (!this.collectionIsActive){ 208 | failureResponse.description = COLLECTION_NOT_ACTIVE; 209 | } else { 210 | failureResponse.description = COLLECTION_DOESNT_EXIST; 211 | } 212 | reject(failureResponse); 213 | } 214 | }); 215 | } 216 | 217 | deleteOne(query) { 218 | const keys = Object.getOwnPropertyNames(query); 219 | 220 | return new Promise((resolve, reject) => { 221 | // if collection exists and is active 222 | if(this.collectionExists && this.collectionIsActive) { 223 | blockstack.getFile(this.collectionName, this.encrypt_decrypt) 224 | .then((fileText) => { 225 | const content = JSON.parse(fileText); 226 | 227 | let items = []; 228 | let deleted = false; 229 | let deletedItem; 230 | let checkSearchParameters = []; 231 | let addToList = true; 232 | let index = 0; 233 | 234 | for(let i = 0; i < keys.length; i++){ 235 | checkSearchParameters[i] = false; 236 | } 237 | 238 | content.forEach((item) => { 239 | index = 0; 240 | addToList = true; 241 | 242 | keys.forEach((key) => { 243 | if (item.hasOwnProperty(key)) { 244 | if((item[key] === query[key]) && item.isActive) { 245 | checkSearchParameters[index] = true; 246 | } 247 | } 248 | index++; 249 | }); 250 | 251 | checkSearchParameters.forEach((value) => { 252 | if (!value) { 253 | addToList = false; 254 | } 255 | }); 256 | 257 | if (addToList && !deleted) { 258 | item.isActive = false; 259 | deletedItem = item; 260 | deleted = true; 261 | } 262 | 263 | items.push(item); 264 | 265 | for(let i = 0; i < keys.length; i++){ 266 | checkSearchParameters[i] = false; 267 | } 268 | }); 269 | 270 | if(deleted) { 271 | blockstack.putFile(this.collectionName, JSON.stringify(items), this.encrypt_decrypt) 272 | .then(() => { 273 | successResponse.description = DOCUMENT_DELETED; 274 | successResponse.payload = deletedItem; 275 | resolve(successResponse); 276 | }) 277 | .catch(() => { 278 | failureResponse.description = ERROR_IN_DELETING_DOCUMENT; 279 | reject(failureResponse); 280 | }); 281 | } else { 282 | failureResponse.description = DOCUMENT_NOT_FOUND; 283 | reject(failureResponse); 284 | } 285 | }) 286 | .catch(() => { 287 | failureResponse.description = ERROR_IN_DELETING_DOCUMENT; 288 | reject(failureResponse); 289 | }); 290 | } else { 291 | if (!this.collectionIsActive){ 292 | failureResponse.description = COLLECTION_NOT_ACTIVE; 293 | } else { 294 | failureResponse.description = COLLECTION_DOESNT_EXIST; 295 | } 296 | reject(failureResponse); 297 | } 298 | }); 299 | } 300 | 301 | deleteAll(query) { 302 | const keys = Object.getOwnPropertyNames(query); 303 | 304 | return new Promise((resolve, reject) => { 305 | // if collection exists and is active 306 | if(this.collectionExists && this.collectionIsActive) { 307 | blockstack.getFile(this.collectionName, this.encrypt_decrypt) 308 | .then((fileText) => { 309 | const content = JSON.parse(fileText); 310 | 311 | let items = []; 312 | let deleted = false; 313 | let deletedItems = []; 314 | 315 | let checkSearchParameters = []; 316 | let addToList = true; 317 | let index = 0; 318 | 319 | for(let i = 0; i < keys.length; i++){ 320 | checkSearchParameters[i] = false; 321 | } 322 | 323 | content.forEach((item) => { 324 | index = 0; 325 | addToList = true; 326 | 327 | keys.forEach((key) => { 328 | if (item.hasOwnProperty(key)) { 329 | if((item[key] === query[key]) && item.isActive) { 330 | checkSearchParameters[index] = true; 331 | } 332 | } 333 | index++; 334 | }); 335 | 336 | checkSearchParameters.forEach((value) => { 337 | if (!value) { 338 | addToList = false; 339 | } 340 | }); 341 | 342 | if (addToList) { 343 | item.isActive = false; 344 | deletedItems.push(item); 345 | deleted = true; 346 | } 347 | 348 | items.push(item); 349 | 350 | for(let i = 0; i < keys.length; i++){ 351 | checkSearchParameters[i] = false; 352 | } 353 | }); 354 | 355 | if(deleted) { 356 | blockstack.putFile(this.collectionName, JSON.stringify(items), this.encrypt_decrypt) 357 | .then(() => { 358 | successResponse.description = DOCUMENT_DELETED; 359 | successResponse.payload = deletedItems; 360 | resolve(resolvedItem); 361 | }) 362 | .catch(() => { 363 | failureResponse.description = ERROR_IN_DELETING_DOCUMENT; 364 | reject(failureResponse); 365 | }); 366 | } else { 367 | failureResponse.description = DOCUMENT_NOT_FOUND; 368 | reject(failureResponse); 369 | } 370 | }) 371 | .catch(() => { 372 | failureResponse.description = ERROR_IN_DELETING_DOCUMENT; 373 | reject(failureResponse); 374 | }); 375 | } else { 376 | if (!this.collectionIsActive){ 377 | failureResponse.description = COLLECTION_NOT_ACTIVE; 378 | } else { 379 | failureResponse.description = COLLECTION_DOESNT_EXIST; 380 | } 381 | reject(failureResponse); 382 | } 383 | }); 384 | } 385 | 386 | update(id, query) { 387 | const keys = Object.getOwnPropertyNames(query); 388 | 389 | return new Promise((resolve, reject) => { 390 | // if collection exists and is active 391 | if(this.collectionExists && this.collectionIsActive) { 392 | blockstack.getFile(this.collectionName, this.encrypt_decrypt) 393 | .then((fileText) => { 394 | const content = JSON.parse(fileText); 395 | 396 | let items = []; 397 | let updated = false; 398 | let updatedItem; 399 | 400 | content.forEach((item) => { 401 | if ((item.id === id) && item.isActive) { 402 | 403 | // logic to update the document 404 | keys.forEach((key) => { 405 | if (item.hasOwnProperty(key)) { 406 | item[key] = query[key]; 407 | } 408 | }); 409 | 410 | updated = true; 411 | updatedItem = item; 412 | } 413 | items.push(item); 414 | }); 415 | 416 | if (updated) { 417 | blockstack.putFile(this.collectionName, JSON.stringify(items), this.encrypt_decrypt) 418 | .then(() => { 419 | successResponse.description = DOCUMENT_UPDATED; 420 | successResponse.payload = updatedItem; 421 | resolve(successResponse); 422 | }) 423 | .catch(() => { 424 | failureResponse.description = ERROR_IN_UPDATING_DOCUMENT; 425 | reject(failureResponse); 426 | }); 427 | } else { 428 | failureResponse.description = DOCUMENT_NOT_FOUND; 429 | reject(failureResponse); 430 | } 431 | 432 | }) 433 | .catch(() => { 434 | failureResponse.description = ERROR_IN_UPDATING_DOCUMENT; 435 | reject(failureResponse); 436 | }); 437 | } else { 438 | if (!this.collectionIsActive){ 439 | failureResponse.description = COLLECTION_NOT_ACTIVE; 440 | } else { 441 | failureResponse.description = COLLECTION_DOESNT_EXIST; 442 | } 443 | reject(failureResponse); 444 | } 445 | }); 446 | } 447 | 448 | } 449 | 450 | export default Document; 451 | -------------------------------------------------------------------------------- /src/response.js: -------------------------------------------------------------------------------- 1 | export let successResponse = { 2 | statusCode: 200, 3 | statusText: 'SUCCESS' 4 | }; 5 | 6 | export let failureResponse = { 7 | statusCode: 400, 8 | statusText: 'FAILURE' 9 | }; 10 | --------------------------------------------------------------------------------