Level / level

Universal abstract-level database for Node.js and browsers.
MIT License
1.55k stars 106 forks source link

When the database is empty, using the ‘createReadStream’ method, no event is triggered #167

Closed xupengkun closed 4 years ago

xupengkun commented 4 years ago
db.createReadStream()
  .on('data', function (data) {
    console.log(data.key, '=', data.value)
  })
  .on('error', function (err) {
    console.log('Oh my!', err)
  })
  .on('close', function () {
    console.log('Stream closed')
  })
  .on('end', function () {
    console.log('Stream ended')
  })

tip: db database is empty

  .on('end', function () {
    console.log('Stream ended')
  })

event is not trigger

vweevers commented 4 years ago

Can you post a full example, including require statements and creating the db?

Because with the following code I cannot replicate:

const level = require('level')
const db = level('test')

db.createReadStream()
  .resume()
  .on('end', function () {
    console.log('ok')
  })
xupengkun commented 4 years ago

@vweevers Thanks

const level = electron.remote.require('level');
const DB = level('./myDB');

DB.createValueStream({})
          .on('data', function (data) {
            console.log('level-data----------');
          })
          .on('end', function () {
            console.log('level-end----------');
          })
          .on('error', function (err) {
            console.error(err, '----------get-level-err');
          })
          .on('close', function () {
            console.error('level-close----------');
          });

maybe because I did not use .resume() ?

vweevers commented 4 years ago

Attaching a data event listener has the same effect as .resume(), so that's not it.

What does electron.remote.require() do? Where is this code running?

xupengkun commented 4 years ago

I started a local service in electron, so I will use this method to introduce the library

"electron": "^5.0.4",
 "level": "^6.0.0",

Insert can be used normally, and ‘createValueStream’ method can be used normally when there is data in the database

vweevers commented 4 years ago

Could you share a repository or gist that I can clone + install + run, to replicate?

xupengkun commented 4 years ago

Sorry, this is an internal project, but I can give you the code related to the warehouse

xupengkun commented 4 years ago

const electron = require('electron'); const level = electron.remote.require('level');

const path = electron.remote.require('path'); const userData = electron.remote.app.getPath('userData'); export default class Tool { constructor() { this.SetStaticDBPath(); };

USERPATH = ''; DBPATH = ''; DBDIR = ''; DBPath = '';

DBMap = {};

SetStaticDBPath = (pathName = 'default') => { this.USERPATH = pathName; this.DBPATH = 'DBDIR' + '/' + this.USERPATH; this.DBDIR = path.join(userData, this.DBPATH); this.DBPath = path.join(this.DBDIR, './defaultDB'); this.setDBPath(); this.CheckDBState(); }; setDBPath = () => { $BG.pathMap.setPath('DBDIR', this.DBDIR); }; CreateDB = (DBName) => { let DB; try { DB = level(path.join(this.DBDIR, './', DBName)); } catch (e) { console.log(e); } this.DBMap[DBName] = DB; window.onbeforeunload = () => { Object.keys(this.DBMap).map((item) => { this.DBMap[item].close(); }); }; return DB; }; Clear = (DBName) => { if (!this.DBMap.hasOwnProperty(DBName)) this.CreateDB(DBName); return new Promise((resolve, reject) => { this.DBMap[DBName].clear(() => { resolve(); }); }); }; CheckDBState = () => { if (!this.DBMap.hasOwnProperty('MsgDB')) this.CreateDB('MsgDB'); if (!this.DBMap.hasOwnProperty('LinkDB')) this.CreateDB('LinkDB'); }; PutHandle = (chatId, data) => { this.CheckDBState(); const MsgDBKey = data.id; const LinkDBKey = chatId + '' + data.time + '' + MsgDBKey; return Promise.all([ this.HandleMsgDB([{ type: 'put', key: MsgDBKey, value: JSON.stringify(data) }]), this.HandleLinkDB([{ type: 'put', key: LinkDBKey, value: MsgDBKey }]) ]); }; DeleteHandle = (msgId) => { return this.HandleMsgDB([{ type: 'del', key: msgId }]); }; HandleLinkDB = (BatchData) => { return new Promise((resolve, reject) => { this.DBMap['LinkDB'].batch(BatchData, (err) => { try { if (err) { reject(err) } else { resolve(); } } catch (e) { reject(e); } }) }) }; HandleMsgDB = (BatchData) => { return new Promise((resolve, reject) => { this.DBMap['MsgDB'].batch(BatchData, (err) => { try { if (err) { reject(err) } else { resolve(); } } catch (e) { reject(e); } }) }) }; GetHandle = async (chatId, params, onProgress = () => {}) => { this.CheckDBState();

const msgIdList = await this.GetMsgIdList( chatId, params );
const msgDataList = await this.GetMsgDataByMsgId(msgIdList);

return msgDataList;

}; GetMsgIdList = (chatId, params) => { const list = []; return new Promise((resolve, reject) => { const searchParams = { limit: params.limit, reverse: params.reverse, keys: false, values: true }; if (params.startTime) searchParams.lte = chatId + '' + params.startTime; if (params.endTime) searchParams.gte = chatId + '' + params.endTime; try { this.DBMap['LinkDB'].createValueStream(searchParams) .on('data', function (data) { console.log('level-data----------'); list.push(data); }) .on('end', function () { console.log('level-end----------'); resolve(list); }) .on('error', function (err) { console.error(err, '----------get-level-err'); reject(err); }) .on('close', function () { console.error('level-close----------'); reject(); }); } catch (e) { console.log(e); }

})

}; GetMsgDataByMsgId = (msgIdList) => { return Promise.all(msgIdList.map((item) => { return this.GetItemByKey(item); })); }; GetItemByKey = (key = '') => { if (key) { return new Promise((resolve, reject) => { this.DBMap['MsgDB'].get(key, { asBuffer: false }, (err, val) => { try { if (err) { reject(err); } else { resolve(val && JSON.parse(val)); } } catch (e) { reject(e); } }); }); } else { return Promise.resolve(); } } }

xupengkun commented 4 years ago

This is my tool class

vweevers commented 4 years ago

That's not enough to work with, could you please put it in a new repository (or gist) including a package.json and instructions on how to run? You don't have to share private code, just a stripped down version that demonstrates the problem.

xupengkun commented 4 years ago

mmmmmmm When I put it in an empty project, it works again

xupengkun commented 4 years ago

I'm sorry, but I don't know exactly what happened in my code

vweevers commented 4 years ago

If I had to guess, it's something to do with remote.require. I don't know how that works exactly, it somehow makes a module from the main process available to renderer processes?

xupengkun commented 4 years ago

such: The main rendering process of electron renders a webpack service. I write these codes in the webpack folder and then call the method of the main process to get the level.

xupengkun commented 4 years ago

Is it because the code is parsed by webpack?

vweevers commented 4 years ago

Maybe, if webpack is configured to resolve the browser field of package.json in which case level does not use LevelDB as the underlying store, but IndexedDB.

Do you see your db folder (path.join(this.DBDIR, './', DBName)) getting created on disk?

xupengkun commented 4 years ago

yes

xupengkun commented 4 years ago

At the same time, the folder http_localhost_9080.indexeddb.leveldb was added to my disk.

vweevers commented 4 years ago

That suggests it's somehow using both LevelDB and IndexedDB.

At this point though, unless you manage to replicate the issue outside of your project, I'm afraid I can't help any further. We can conclude there's no bug in level.

xupengkun commented 4 years ago

Yes, this is not a bug. This should be my problem. I will close this problem until I can reproduce it in an empty project. All in all, thanks for reminding

vweevers commented 4 years ago

Good luck!