Comparing version 0.0.10-alpha to 0.0.11-alpha
@@ -5,7 +5,7 @@ import { TableDefinition } from "./dto/table-definition"; | ||
private ipfs; | ||
static MFS_DB: string; | ||
static SCHEMA_FILENAME: string; | ||
private selectedDatabase; | ||
private activeTransaction; | ||
private indexService; | ||
private pathService; | ||
private schemaService; | ||
constructor(ipfs: any); | ||
@@ -28,12 +28,7 @@ createDatabase(name: string): Promise<void>; | ||
private queueChange; | ||
private getDatabasePath; | ||
private getTableDirectoryName; | ||
private getDefinitionForIndex; | ||
private getSchemaForTable; | ||
private getIndexMap; | ||
private updateIndex; | ||
private flushIndexes; | ||
private fileExists; | ||
private getFileContent; | ||
} | ||
export { MFdb }; |
{ | ||
"name": "mfdb", | ||
"version": "0.0.10-alpha", | ||
"version": "0.0.11-alpha", | ||
"description": "MFdb is a portable P2P database backed by the IPFS Mutable File System.", | ||
"main": "./dist/index.js", | ||
"main": "./dist/index-node.js", | ||
"browser": "./dist/index-browser.js", | ||
"types": "./dist/index.d.ts", | ||
@@ -38,4 +39,6 @@ "homepage": "https://gitlab.com/american-space-software/mfdb", | ||
"@babel/preset-env": "7.11.5", | ||
"@types/node": "14.10.3" | ||
"@types/node": "14.10.3", | ||
"webpack-merge": "5.7.3", | ||
"webpack-node-externals": "2.5.2" | ||
} | ||
} |
190
src/mfdb.ts
@@ -1,2 +0,2 @@ | ||
import { IndexService } from "./index-service" | ||
import { IndexService } from "./service/index-service" | ||
import { Schema } from "./dto/schema" | ||
@@ -9,21 +9,24 @@ import { TableDefinition } from "./dto/table-definition" | ||
const stringify = require('fast-json-stable-stringify') | ||
const toBuffer = require('it-to-buffer') | ||
const all = require('it-all') | ||
import CID from "cids" | ||
import { PathService } from "./service/path-service" | ||
import { SchemaService } from "./service/schema-service" | ||
class MFdb { | ||
static MFS_DB = "mfdb" | ||
static SCHEMA_FILENAME = "schema.json" | ||
private selectedDatabase: string | ||
private activeTransaction:Transaction | ||
private activeTransaction: Transaction | ||
private indexService:IndexService | ||
private indexService: IndexService | ||
private pathService: PathService | ||
private schemaService:SchemaService | ||
constructor( | ||
private ipfs | ||
) { | ||
) { | ||
this.indexService = new IndexService() | ||
this.pathService = new PathService(this.ipfs) | ||
this.schemaService = new SchemaService(this.pathService, this.ipfs) | ||
} | ||
@@ -37,6 +40,6 @@ | ||
console.debug(`Creating database ${name} at ${this.getDatabasePath(name)}`) | ||
console.debug(`Creating database ${name} at ${this.pathService.getDatabasePath(name)}`) | ||
//Create the directory | ||
await this.ipfs.files.mkdir(this.getDatabasePath(name), { | ||
await this.ipfs.files.mkdir(this.pathService.getDatabasePath(name), { | ||
parents: true | ||
@@ -49,3 +52,3 @@ }) | ||
let schemaPath = `${this.getTableDirectoryName(definition.database, definition.name)}/_metadata/${MFdb.SCHEMA_FILENAME}` | ||
let schemaPath = `${this.pathService.getTableDirectoryName(definition.database, definition.name)}/_metadata/${SchemaService.SCHEMA_FILENAME}` | ||
@@ -57,9 +60,10 @@ console.debug(`Saving schema for table ${definition.name} (${definition.database}) at ${schemaPath}`) | ||
create: true, | ||
parents: true | ||
parents: true, | ||
flush: true | ||
}) | ||
} | ||
async databaseExists(name: string) { | ||
return this.fileExists(this.getDatabasePath(name)) | ||
return this.pathService.fileExists(this.pathService.getDatabasePath(name)) | ||
} | ||
@@ -71,3 +75,3 @@ | ||
try { | ||
await this.ipfs.files.rm(this.getDatabasePath(name), { | ||
await this.ipfs.files.rm(this.pathService.getDatabasePath(name), { | ||
recursive: true | ||
@@ -92,3 +96,3 @@ }) | ||
async commit() { | ||
console.debug(`Commiting ${this.activeTransaction.changes.length} changes to: ${this.activeTransaction.tables}`) | ||
@@ -115,22 +119,23 @@ | ||
//Get existing value | ||
let existing = await this.get(table, key) | ||
this.queueChange(table, async () => { | ||
//Get schema | ||
let schema = await this.getSchemaForTable(table) | ||
//Save value | ||
let path = `${this.pathService.getTableDirectoryName(this.selectedDatabase, table)}/${key}` | ||
//Get existing value | ||
let existing | ||
if (await this.pathService.fileExists(path)) { | ||
existing = await this.get(table, key) | ||
} | ||
//Update indexes | ||
for (let indexName in schema) { | ||
this.queueChange(table, async () => { | ||
//Get schema | ||
let schema = await this.schemaService.getSchemaForTable(this.selectedDatabase, table) | ||
//Update indexes | ||
for (let indexName in schema) { | ||
console.debug(`Updating ${indexName} index in ${table}`) | ||
await this.updateIndex(table, indexName, key, value[indexName], existing ? existing[indexName] : undefined) | ||
}) | ||
} | ||
} | ||
this.queueChange(table, async () => { | ||
let path = `${this.getTableDirectoryName(this.selectedDatabase, table)}/${key}` | ||
if (await this.fileExists(path)) { | ||
if (await this.pathService.fileExists(path)) { | ||
await this.ipfs.files.rm(path) | ||
@@ -142,3 +147,4 @@ } | ||
await this.ipfs.files.write(path, stringify(value), { | ||
create: true | ||
create: true, | ||
flush: true | ||
}) | ||
@@ -155,4 +161,7 @@ }) | ||
let path = `${this.pathService.getTableDirectoryName(this.selectedDatabase, table)}/${key}` | ||
try { | ||
value = await this.getFileContent(`${this.getTableDirectoryName(this.selectedDatabase, table)}/${key}`) | ||
console.debug(`Getting value from MFS at ${path}`) | ||
value = await this.pathService.getFileContent(path) | ||
} catch (ex) { } | ||
@@ -164,4 +173,4 @@ | ||
async getCID(table: string, key: any) : Promise<CID> { | ||
let stat = await this.ipfs.files.stat(`${this.getTableDirectoryName(this.selectedDatabase, table)}/${key}`) | ||
async getCID(table: string, key: any): Promise<CID> { | ||
let stat = await this.ipfs.files.stat(`${this.pathService.getTableDirectoryName(this.selectedDatabase, table)}/${key}`) | ||
return stat.cid | ||
@@ -174,3 +183,3 @@ } | ||
let schema = await this.getSchemaForTable(table) | ||
let schema = await this.schemaService.getSchemaForTable(this.selectedDatabase, table) | ||
let definition = schema[indexName] | ||
@@ -237,3 +246,3 @@ let indexMap = await this.getIndexMap(table, indexName) | ||
const fileList = await all(this.ipfs.files.ls(`${this.getTableDirectoryName(this.selectedDatabase, table)}`)) | ||
const fileList = await all(this.ipfs.files.ls(`${this.pathService.getTableDirectoryName(this.selectedDatabase, table)}`)) | ||
@@ -246,31 +255,30 @@ let records = fileList.filter(file => file.type == 'file').length | ||
async delete(table:string, key: any) { | ||
async delete(table: string, key: any) { | ||
if (!this.selectedDatabase) throw Error("No database selected") | ||
if (!this.activeTransaction) throw Error("No transaction started") | ||
//Get existing value | ||
let existing = await this.get(table, key) | ||
this.queueChange(table, async () => { | ||
//Get schema | ||
let schema = await this.getSchemaForTable(table) | ||
//Get existing value | ||
let existing = await this.get(table, key) | ||
//Remove from all indexes | ||
for (let indexName in schema) { | ||
//Get schema | ||
let schema = await this.schemaService.getSchemaForTable(this.selectedDatabase, table) | ||
this.queueChange(table, async () => { | ||
//Remove from all indexes | ||
for (let indexName in schema) { | ||
console.debug(`Updating ${indexName} index in ${table}`) | ||
await this.updateIndex(table, indexName, key, undefined, existing ? existing[indexName] : undefined) | ||
}) | ||
} | ||
} | ||
this.queueChange(table, async () => { | ||
let path = `${this.getTableDirectoryName(this.selectedDatabase, table)}/${key}` | ||
let path = `${this.pathService.getTableDirectoryName(this.selectedDatabase, table)}/${key}` | ||
console.debug(`Removivng file from MFS at ${path}`) | ||
if (await this.fileExists(path)) { | ||
await this.ipfs.files.rm(path) | ||
if (await this.pathService.fileExists(path)) { | ||
await this.ipfs.files.rm(path, { | ||
flush: true | ||
}) | ||
} | ||
@@ -288,3 +296,3 @@ | ||
let stat = await this.ipfs.files.stat(this.getDatabasePath(name)) | ||
let stat = await this.ipfs.files.stat(this.pathService.getDatabasePath(name)) | ||
@@ -295,13 +303,13 @@ return stat.cid | ||
async updateFromCid(name:string, cid:string) { | ||
async updateFromCid(name: string, cid: string) { | ||
console.log(`Updating ${name} from ${cid}`) | ||
await this.ipfs.files.rm(this.getDatabasePath(name), { recursive: true }) | ||
await this.ipfs.files.cp(`/ipfs/${cid}`, this.getDatabasePath(name)) | ||
await this.ipfs.files.rm(this.pathService.getDatabasePath(name), { recursive: true }) | ||
await this.ipfs.files.cp(`/ipfs/${cid}`, this.pathService.getDatabasePath(name)) | ||
} | ||
private queueChange(table:string, f:Function) { | ||
private queueChange(table: string, f: Function) { | ||
//Add to changes | ||
@@ -311,3 +319,3 @@ this.activeTransaction.changes.push(f) | ||
//Add table | ||
let existing = this.activeTransaction.tables.filter( t => t == table ) | ||
let existing = this.activeTransaction.tables.filter(t => t == table) | ||
if (existing.length == 0) this.activeTransaction.tables.push(table) | ||
@@ -317,27 +325,11 @@ | ||
private getDatabasePath(name: string) { | ||
return `/${MFdb.MFS_DB}/${name}` | ||
} | ||
private getTableDirectoryName(database: string, table: string) { | ||
return `${this.getDatabasePath(database)}/${table}` | ||
} | ||
private async getDefinitionForIndex(table: string, index: string) { | ||
let schema: Schema = await this.getSchemaForTable(table) | ||
let schema: Schema = await this.schemaService.getSchemaForTable(this.selectedDatabase, table) | ||
return schema[index] | ||
} | ||
private async getSchemaForTable(table: string): Promise<Schema> { | ||
let schema: Schema | ||
try { | ||
schema = await this.getFileContent(`${this.getTableDirectoryName(this.selectedDatabase, table)}/_metadata/${MFdb.SCHEMA_FILENAME}`) | ||
} catch (ex) { } | ||
return schema | ||
} | ||
private async getIndexMap(table: string, index: string) { | ||
@@ -353,11 +345,11 @@ | ||
try { | ||
let path = `${this.getTableDirectoryName(this.selectedDatabase, table)}/_indexMaps/${index}` | ||
let path = `${this.pathService.getTableDirectoryName(this.selectedDatabase, table)}/_indexMaps/${index}` | ||
await this.ipfs.files.stat(path) | ||
let loadedMap = await this.getFileContent(path) | ||
let loadedMap = await this.pathService.getFileContent(path) | ||
indexMap = SortedMap(loadedMap) | ||
} catch (ex) { | ||
} catch (ex) { | ||
// console.log(ex) | ||
@@ -398,6 +390,6 @@ } | ||
//Otherwise we're storing a list of values. Append this to it. | ||
let isNew:boolean = ( Boolean(!existingMapKey) && Boolean(mapKey) ) | ||
let isChanged:boolean = (!isNew && (mapKey != existingMapKey)) | ||
let isNew: boolean = (Boolean(!existingMapKey) && Boolean(mapKey)) | ||
let isChanged: boolean = (!isNew && (mapKey != existingMapKey)) | ||
if (existingMapKey && isChanged) { | ||
@@ -440,13 +432,15 @@ //Remove from current list | ||
//Get schema | ||
let schema = await this.getSchemaForTable(table) | ||
let schema = await this.schemaService.getSchemaForTable(this.selectedDatabase, table) | ||
for (let indexName in schema) { | ||
let filename = `${this.getTableDirectoryName(this.selectedDatabase, table)}/_indexMaps/${indexName}` | ||
let indexMap = this.indexService.getCachedIndexMap(this.selectedDatabase, table, indexName) | ||
let filename = `${this.pathService.getTableDirectoryName(this.selectedDatabase, table)}/_indexMaps/${indexName}` | ||
let indexMap = this.indexService.getCachedIndexMap(this.selectedDatabase, table, indexName) | ||
if (indexMap) { | ||
if (await this.fileExists(filename)) { | ||
await this.ipfs.files.rm(filename) | ||
if (await this.pathService.fileExists(filename)) { | ||
await this.ipfs.files.rm(filename, { | ||
flush: true | ||
}) | ||
} | ||
@@ -458,4 +452,5 @@ | ||
create: true, | ||
parents: true | ||
}) | ||
parents: true, | ||
flush: true | ||
}) | ||
} | ||
@@ -467,16 +462,3 @@ | ||
private async fileExists(path:string) { | ||
try { | ||
await this.ipfs.files.stat(path) | ||
return true | ||
} catch (ex) { | ||
return false | ||
} | ||
} | ||
private async getFileContent(filename) { | ||
let bufferedContents = await toBuffer(this.ipfs.files.read(filename)) // a buffer | ||
let content = bufferedContents.toString() | ||
return JSON.parse(content) | ||
} | ||
} | ||
@@ -483,0 +465,0 @@ |
import assert from 'assert' | ||
import { MFdb } from "../src/index" | ||
import { SchemaService } from '../src/service/schema-service' | ||
@@ -79,3 +80,3 @@ const toBuffer = require('it-to-buffer') | ||
//Check that schema exists in right place | ||
let schemaBuffer = await toBuffer(ipfs.files.read(`/mfdb/test/test-table/_metadata/${MFdb.SCHEMA_FILENAME}`)) | ||
let schemaBuffer = await toBuffer(ipfs.files.read(`/mfdb/test/test-table/_metadata/${SchemaService.SCHEMA_FILENAME}`)) | ||
let readSchema = JSON.parse(schemaBuffer.toString()) | ||
@@ -82,0 +83,0 @@ assert.notStrictEqual(schema, readSchema) |
const path = require('path') | ||
import { merge } from 'webpack-merge' | ||
const nodeExternals = require('webpack-node-externals') | ||
@@ -13,5 +15,6 @@ | ||
let config = { | ||
let web = { | ||
name: "web", | ||
entry: './src/index.ts', | ||
mode: "production", | ||
module: { | ||
@@ -34,3 +37,3 @@ rules: [ | ||
output: { | ||
filename: 'index.js', | ||
filename: 'index-browser.js', | ||
libraryTarget: 'umd', | ||
@@ -42,2 +45,39 @@ globalObject: 'this', | ||
export default config | ||
let node = { | ||
name: "node", | ||
entry: './src/index.ts', | ||
target: "node", | ||
mode: "production", | ||
externals: [nodeExternals()], | ||
module: { | ||
rules: [ | ||
{ | ||
test: /\.js$/, | ||
use: [babelLoader] | ||
}, | ||
{ | ||
test: /\.tsx?$/, | ||
exclude: '/node_modules/', | ||
loader: [babelLoader, 'ts-loader'] | ||
}, | ||
], | ||
}, | ||
resolve: { | ||
extensions: ['*', '.js', '.jsx', '.tsx', '.ts'], | ||
}, | ||
output: { | ||
filename: 'index-node.js', | ||
libraryTarget: 'umd', | ||
path: path.resolve(__dirname, 'dist'), | ||
} | ||
} | ||
export default [ | ||
web, | ||
node | ||
] |
Sorry, the diff of this file is too big to display
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
609772
30
2817
17
2