tradle / multi-hyperbee

A LevelUP compatible leaderless multi-master database with eventual consistency, using hyperbee + CRDT + HLC. Similarly CockroachDB achieves replication on top of RocksDB, but here it is a pure P2P **streaming** database, with zero central management. LevelDB compatibility allows to use Dynalite on top to achieve DynamoDB compatibility with sophisticated auto-updated secondary indexes, and fairly complex queries. Work on Dynalite is almost completed to remove HTTP server, to make this combination perfect for serverless.
36 stars 5 forks source link

Cannot create property '_objectId' on string 'val1' #3

Closed samo3l closed 3 years ago

samo3l commented 3 years ago

Hello!

I am 100% sure that it's my mistake and misunderstanding because I am new to node.js and all the hypecore based things, but I am getting the following error trying to put some data into the database. Am I using the wrong format? Or should I add at least one peer to achieve that? Maybe something else missed...Could you please help.

script:

const MultiHyperbee = require('./multi-hyperbee')
const hyperbeeOpts = { keyEncoding: 'utf-8', valueEncoding: 'json' }
async function start() {
  const db = new MultiHyperbee('db', { hyperbeeOpts })
  try {
    return await db.put('key1', 'val1')
  } catch (err) {
    console.log(err)
  }
}
start()

error: TypeError: Cannot create property '_objectId' on string 'val1'

pgmemk commented 3 years ago

Thank you for your find. We definitely need to throw a proper error. But multi-hyperbee expects to receive an json object as a value as described here .

For the multi-hyperbee replication protocol to operate it needs the value to have 2 extra properties:

_timestamp is set internally to HLC timestamp and _object Id if not present will be set to the 'key'.

samo3l commented 3 years ago

@pgmemk Thanks for your answer. But I already tried. When I am using the JSON object as described here:

const MultiHyperbee = require('./multi-hyperbee')
const hyperbeeOpts = { keyEncoding: 'utf-8', valueEncoding: 'json' }
var data = {
    name: 'val1'
}
async function start() {
  const db = new MultiHyperbee('db', { hyperbeeOpts })
  try {
    return await db.put('key1', data)
  } catch (err) {
    console.log(err)
  }  
}
start()

or even the JSON from tests:

const MultiHyperbee = require('./multi-hyperbee')
const hyperbeeOpts = { keyEncoding: 'utf-8', valueEncoding: 'json' }
data = {
  object0: {
    _objectId: 'Contact/r1',
    firstName: 'J',
    lastName: 'S',
    friends: ['Claire', 'Martha', 'Jake', 'Sean']
  }
}
async function start() {
  const db = new MultiHyperbee('db', { hyperbeeOpts })
  try {
    return await db.put('key1', data)
  } catch (err) {
    console.log(err)
  }  
}
start()

I am getting another error like this:

TypeError [ERR_INVALID_ARG_TYPE]: The "string" argument must be of type string or an instance of Buffer or ArrayBuffer. Received an instance of Object
    at Function.byteLength (buffer.js:728:11)
    at bufferLength (/opt/rtdb/node_modules/protocol-buffers-encodings/index.js:285:53)
    at Object.encodingLength (/opt/rtdb/node_modules/protocol-buffers-encodings/index.js:66:15)
    at encodingLength (/opt/rtdb/node_modules/hyperbee/lib/messages.js:405:33)
    at Object.encode (/opt/rtdb/node_modules/hyperbee/lib/messages.js:413:40)
    at Batch._append (/opt/rtdb/node_modules/hyperbee/index.js:679:35)
    at Batch.put (/opt/rtdb/node_modules/hyperbee/index.js:572:17)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async MultiHyperbee.put (/opt/rtdb/freeton-rtdb-research/multi-hyperbee/multi-hyperbee/index.js:111:5)
    at async start (/opt/rtdb/freeton-rtdb-research/multi-hyperbee/p2.js:17:12) {
  code: 'ERR_INVALID_ARG_TYPE'
}

trying to stringify JSON also causes an error:

const MultiHyperbee = require('./multi-hyperbee')
const hyperbeeOpts = { keyEncoding: 'utf-8', valueEncoding: 'json' }
var data = {
    name: 'val1'
}
async function start() {
  const db = new MultiHyperbee('db', { hyperbeeOpts })
  try {
    return await db.put('key1', JSON.stringify(data))
  } catch (err) {
    console.log(err)
  }  
}
start()
Error: multi-hyperbee: value expected to be JSON object
    at MultiHyperbee.put (/opt/rtdb/freeton-rtdb-research/multi-hyperbee/multi-hyperbee/index.js:95:13)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async start (/opt/rtdb/freeton-rtdb-research/multi-hyperbee/p2.js:9:12)

Node version - v14.15.0

I am confused again :)

samo3l commented 3 years ago

I also noticed that if doing the same things without multi-hyperbee in one simple js file like the following, it works fine.

script:

let data = {
  object0: {
    _objectId: 'Contact/r1',
    firstName: 'J',
    lastName: 'S',
    friends: ['Claire', 'Martha', 'Jake', 'Sean']
  }
}
console.log('typeof value  -  ' + typeof data)
console.log('constructor  -  ' + data.constructor)
console.log('value  -  ' + data)
async function start() {
  try {
    return await test('Contact/r1', data)
  } catch (err) {
    console.log(err)
  }  
}
async function test(key, value) {
  value._objectId = key
  console.log(value)
  console.log(value._objectId)
}
start()

output:

typeof value  -  object
constructor  -  function Object() { [native code] }
value  -  [object Object]
{
  object0: {
    _objectId: 'Contact/r1',
    firstName: 'J',
    lastName: 'S',
    friends: [ 'Claire', 'Martha', 'Jake', 'Sean' ]
  },
  _objectId: 'Contact/r1'
}
Contact/r1

I put some console logs to multi-hyperbee lib:

//    if (!value)
//      throw new Error('multi-hyperbee: value parameter is required')
//    if (!noDiff  &&  (typeof value !== 'object'  || value.constructor !== Object))
      console.log('typeof value  -  ' + typeof value)
      console.log('constructor  -  ' + value.constructor)
      console.log('value  -  ' + value)
//      throw new Error('multi-hyperbee: value expected to be JSON object')
    if (!value._objectId)
      value._objectId = key

run script:

const MultiHyperbee = require('./multi-hyperbee')
const hyperbeeOpts = { keyEncoding: 'utf-8', valueEncoding: 'json' }
let data = {
  object0: {
    firstName: 'J',
    lastName: 'S',
    friends: ['Claire', 'Martha', 'Jake', 'Sean']
  }
}
async function start() {
  const db = new MultiHyperbee('db', { hyperbeeOpts })
  try {
    return await db.put('Contact/r1', data)
  } catch (err) {
    console.log(err)
  }  
}
start()

and output is pretty the same:

typeof value  -  object
constructor  -  function Object() { [native code] }
value  -  [object Object]
TypeError [ERR_INVALID_ARG_TYPE]: The "string" argument must be of type string or an instance of Buffer or ArrayBuffer. Received an instance of Object
    at Function.byteLength (buffer.js:728:11)
    at bufferLength (/opt/rtdb/node_modules/protocol-buffers-encodings/index.js:285:53)
    at Object.encodingLength (/opt/rtdb/node_modules/protocol-buffers-encodings/index.js:66:15)
    at encodingLength (/opt/rtdb/node_modules/hyperbee/lib/messages.js:405:33)
    at Object.encode (/opt/rtdb/node_modules/hyperbee/lib/messages.js:413:40)
    at Batch._append (/opt/rtdb/node_modules/hyperbee/index.js:679:35)
    at Batch.put (/opt/rtdb/node_modules/hyperbee/index.js:572:17)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async MultiHyperbee.put (/opt/rtdb/freeton-rtdb-research/multi-hyperbee/multi-hyperbee/index.js:115:5)
    at async start (/opt/rtdb/freeton-rtdb-research/multi-hyperbee/p2.js:16:12) {
  code: 'ERR_INVALID_ARG_TYPE'
}

but with an error :(

pgmemk commented 3 years ago

You have a typo in here:

const db = new MultiHyperbee('db', { hyperbeeOpts })

Should be

const db = new MultiHyperbee('db', hyperbeeOpts)

Good luck

samo3l commented 3 years ago

Hmm, I got it from here - https://github.com/tradle/multi-hyperbee#usage Is it a mistake in the doc or it's connected with the node version?

Thanks! I will try it.

pgmemk commented 3 years ago

Fixed the doc. Thank you