5

TL;DR A piece of Javascript code works flawlessly on Linux whilst behaving inconsistently on Windows.


I am coding an Electron app, using Vue.js for frontend, Vuex for data management and LokiJS for persistence storage (with its File System adapter at the background). I develop this application on Linux, but from time to time I have to switch to Windows to create a Windows build for the client. The Linux build always works flawlessly, the Windows one misbehaves. I assumed it was a LokiJS issue, however, upon the isolation of LokiJS-specific code, it worked properly even on Windows.

Here is simplified store.js file, which contains all relevant Vuex and LokiJS-related code in my application.

import loki from 'lokijs'
import LokiSFSAdapter from 'lokijs/src/loki-fs-structured-adapter'
import MainState from '../index' // a Vuex.Store object

const state = {
  ads: [],
  profiles: []
}

var sfsAdapter = new LokiSFSAdapter('loki')
var db = new loki('database.json', {
  autoupdate: true,
  autoload: true,
  autoloadCallback: setupHandler,
  adapter: sfsAdapter
})

function setupCollection (collectionName) {
  var collection = db.getCollection(collectionName)
  if (collection === null) {
    collection = db.addCollection(collectionName)
  }
}

function setupHandler () {
  setupCollection('ads')
  setupCollection('profiles')

  MainState.commit('updateAds')
  MainState.commit('updateProfiles')
}

window.onbeforeunload = function () {
  db.saveDatabase()
  db.close()
}

const mutations = {
  updateAds (state) {
    state.ads = db.getCollection('ads').data.slice()
  },
  updateProfiles (state) {
    state.profiles = db.getCollection('profiles').data.slice()
  }
}

const actions = {
  async addProfile (context) {
    db.getCollection('profiles').insert({ /* default data */ })
    db.saveDatabase()
    context.commit('updateProfiles')
  },
  async updateProfile (context, obj) {
    db.getCollection('profiles').update(obj)
    db.saveDatabase()
    context.commit('updateProfiles')
  },
  async deleteProfile (context, id) {
    db.getCollection('profiles').removeWhere({'$loki': {'$eq': id}})
    db.saveDatabase()
    context.commit('updateProfiles')
  },
  async addAd (context) {
    db.getCollection('ads').insert({ /* default data */ })
    db.saveDatabase()
    context.commit('updateAds')
  },
  async deleteAd (context, id) {
    db.getCollection('ads').removeWhere({'$loki': {'$eq': id}})
    db.saveDatabase()
    context.commit('updateAds')
  }
}

Behaviour on Linux

  • it calls setupHandler every time the application starts,
  • it correctly saves data to database.json and the respective collections to database.json.0 and database.json.1 for ads and profiles
  • when addAd() is called, it can access all the data properly by calling db.getCollection('ads'), and then insert() on it.

Behaviour on Windows

  • only calls setupHandler if database.json doesn't exist. It correctly creates database.json if it doesn't exist, though.
  • creates only one file - database.json.0, but doesn't save any data there, it's just an empty file. It doesn't even create database.json.1 for the second collection.
  • obviously, since no data is actually saved, db.getCollection('ads') and returns null, which results into TypeError: Cannot read property 'insert' of null when calling addAd() on the successive application runs.
  • if this run database.json was created, the application behaves normally, insert() seems to work, however, no data is saved on exit and the successive runs result in the behaviour in the point above.

Question

Is this a bug somewhere deep in LokiJS/Vuex, or is it just me misusing their API?

sjaustirni
  • 3,056
  • 7
  • 32
  • 50
  • does the process that runs all "the things" have the proper permissions for the directories? So does the file system adapter process for your database have permissions to write to that specific selected folder etc? – Tschallacka Jan 23 '18 at 14:19
  • @Tschallacka It certainly does, since it is able to create `database.json` properly in the very same directory it is supposed to create `database.json.0`, etc. – sjaustirni Jan 23 '18 at 14:21
  • What happens if you call `saveDatabases()` directly after `setupHandler()` is called? does it trigger any error, sytem log, etc..? what does the windows log say?(`start menu` > `event viewer`) – Tschallacka Jan 23 '18 at 14:28
  • @Tschallacka I have no way of calling anything directly after the autoloadCallback, since I don't control when it is called. However, if I create a dedicated callback function in which I call setupHandler and then db.saveDatabase, it behaves the same way as before. It even seems that if I pass in an error callback into the db.saveDatabase(), it doesn't even get called. – sjaustirni Jan 23 '18 at 14:53
  • Also, there is nothing in the error log – sjaustirni Jan 23 '18 at 14:58
  • Do you have the possiblity in your editor to add in a break point and then step through the code call by call? So you can see what gets called where and what it depends on? It seems that somewhere an error is caused(maybe in the native storage library) then caught and never passed on, but that error causes a break and the rest simply doesn't get called. Hence my idea that it was the windows folder permissions in the way. – Tschallacka Jan 23 '18 at 14:58
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/163728/discussion-between-tschallacka-and-sjaustirni). – Tschallacka Jan 23 '18 at 15:06

0 Answers0