From 9dd6980da29145ebb31bd0bbcc320c3c5d741634 Mon Sep 17 00:00:00 2001 From: Zaid Abdulla Date: Fri, 30 Jun 2017 03:14:57 -0700 Subject: [PATCH] Further fixes related to the previous commit --- lib/db.coffee | 98 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 36 deletions(-) diff --git a/lib/db.coffee b/lib/db.coffee index 915e45c..ee12d7d 100644 --- a/lib/db.coffee +++ b/lib/db.coffee @@ -142,15 +142,17 @@ fetchDevice = (id, timestamp, patterns, callback) -> children = {} for pat in pats fragment = pat[0][path.length] or '*' - load = 0 + if fragment == '*' - projection[path.join('.')] = 1 + projection[path.join('.')] = 1 if pat[1] << path.length return projTree[fragment] ?= {} if pat[1] & (1 << path.length) projection[path.concat('_timestamp').join('.')] = 1 + projection[path.concat('_object').join('.')] = 1 + projection[path.concat('_instance').join('.')] = 1 projection[path.concat([fragment, '_timestamp']).join('.')] = 1 projection[path.concat([fragment, '_value']).join('.')] = 1 projection[path.concat([fragment, '_type']).join('.')] = 1 @@ -189,18 +191,20 @@ fetchDevice = (id, timestamp, patterns, callback) -> projection['_lastBootstrap'] = 1 projection['_registered'] = 1 loaded.push([['Events'], ((1 << MAX_DEPTH) - 1)]) - if k == 'Events.Inform._writable' or k == 'Events.Inform' + else if k == 'Events.Inform._writable' or k == 'Events.Inform' projection['_lastInform'] = 1 loaded.push([['Events', 'Inform'], 1 ^ ((1 << MAX_DEPTH) - 1)]) - if k == 'Events.1_BOOT._writable' or k == 'Events.1_BOOT' + else if k == 'Events.1_BOOT._writable' or k == 'Events.1_BOOT' projection['_lastBoot'] = 1 loaded.push([['Events', '1_BOOT'], 1 ^ ((1 << MAX_DEPTH) - 1)]) - if k == 'Events.0_BOOTSTRAP._writable' or k == 'Events.0_BOOTSTRAP' + else if k == 'Events.0_BOOTSTRAP._writable' or k == 'Events.0_BOOTSTRAP' projection['_lastBootstrap'] = 1 loaded.push([['Events', '0_BOOTSTRAP'], 1 ^ ((1 << MAX_DEPTH) - 1)]) - if k == 'Events.Registered._writable' or k == 'Events.Registered' + else if k == 'Events.Registered._writable' or k == 'Events.Registered' projection['_registered'] = 1 loaded.push([['Events', 'Registered'], 1 ^ ((1 << MAX_DEPTH) - 1)]) + else if k.endsWith('._writable') and k != 'Events._writable' + loaded.push([k.split('.').slice(0, 2), 1 ^ ((1 << MAX_DEPTH) - 1)]) delete projection[k] if k != '' if k == '' or k == 'DeviceID' or k.startsWith('DeviceID.') @@ -212,30 +216,37 @@ fetchDevice = (id, timestamp, patterns, callback) -> projection['_id'] = 1 projection['_deviceId'] = 1 loaded.push([['DeviceID'], ((1 << MAX_DEPTH) - 1)]) - if k == 'DeviceID.ID._writable' or k == 'DeviceID.ID' + else if k == 'DeviceID.ID._writable' or k == 'DeviceID.ID' projection['_id'] = 1 loaded.push([['DeviceID', 'ID'], 1 ^ ((1 << MAX_DEPTH) - 1)]) - if k == 'DeviceID.Manufacturer._writable' or k == 'DeviceID.DeManufacturer' + else if k == 'DeviceID.Manufacturer._writable' or k == 'DeviceID.DeManufacturer' projection['_deviceId._Manufacturer'] = 1 loaded.push([['DeviceID', 'Manufacturer'], 1 ^ ((1 << MAX_DEPTH) - 1)]) - if k == 'DeviceID.ProductClass._writable' or k == 'DeviceID.ProductClass' + else if k == 'DeviceID.ProductClass._writable' or k == 'DeviceID.ProductClass' projection['_deviceId._ProductClass'] = 1 loaded.push([['DeviceID', 'ProductClass'], 1 ^ ((1 << MAX_DEPTH) - 1)]) - if k == 'DeviceID.OUI._writable' or k == 'DeviceID.OUI' + else if k == 'DeviceID.OUI._writable' or k == 'DeviceID.OUI' projection['_deviceId._OUI'] = 1 loaded.push([['DeviceID', 'ProductClass'], 1 ^ ((1 << MAX_DEPTH) - 1)]) - if k == 'DeviceID.SerialNumber._writable' or k == 'DeviceID.SerialNumber' + else if k == 'DeviceID.SerialNumber._writable' or k == 'DeviceID.SerialNumber' projection['_deviceId._SerialNumber'] = 1 loaded.push([['DeviceID', 'SerialNumber'], 1 ^ ((1 << MAX_DEPTH) - 1)]) + else if k.endsWith('._writable') and k != 'DeviceID._writable' + loaded.push([k.split('.').slice(0, 2), 1 ^ ((1 << MAX_DEPTH) - 1)]) delete projection[k] if k != '' if k == 'Tags' or k.startsWith('Tags.') if not projection['_tags'] projection['_tags'] = 1 loaded.push([['Tags'], ((1 << MAX_DEPTH) - 1)]) - delete projection[k] if k != '' + delete projection[k] - proj = if projection[''] then {} else projection + if projection[''] + proj = {} + else if Object.keys(projection).length == 0 + proj = {'_id': 1} + else + proj = projection devicesCollection.findOne({'_id' : id}, proj, (err, device) -> return callback(err) if err or not device? @@ -246,18 +257,27 @@ fetchDevice = (id, timestamp, patterns, callback) -> else if projection[path.join('.')] descendantsFetched = true - loaded.push([path, ((1 << path.length) - 1) ^ ((1 << MAX_DEPTH) - 1)]) - if projection[path.concat('_writable').join('.')] + if path.length and projection[path.slice(0, -1).concat("_timestamp").join('.')] + thisFetched = true + loaded.push([path, ((1 << (path.length - 1)) - 1) ^ ((1 << MAX_DEPTH) - 1)]) + else + loaded.push([path, ((1 << path.length) - 1) ^ ((1 << MAX_DEPTH) - 1)]) + else if projection[path.concat('_writable').join('.')] loaded.push([path, 1 << (path.length - 1)]) thisFetched = true if obj['_timestamp']? obj['_timestamp'] = +obj['_timestamp'] + # For compatibility with v1.0 database + if obj['_instance'] and not obj['_object']? + obj['_object'] = true + if thisFetched attrs = {} - t = if obj['_timestamp'] > timestamp then obj['_timestamp'] else timestamp + t = obj['_timestamp'] or 1 + t = timestamp if timestamp > t if obj['_value']? attrs.value = [obj['_timestamp'] or 1, [obj['_value'], obj['_type']]] @@ -265,28 +285,28 @@ fetchDevice = (id, timestamp, patterns, callback) -> obj['_object'] = false if obj['_writable']? - attrs.writable = [timestamp, if obj['_writable'] then 1 else 0] + attrs.writable = [timestamp or 1, if obj['_writable'] then 1 else 0] - if obj['_object']? or obj['_instance']? - attrs.object = [t, if (obj['_object'] or obj['_instance']) then 1 else 0] + if obj['_object']? + attrs.object = [t, if obj['_object'] then 1 else 0] res.push([path, t, attrs]) for k, v of obj - if k[0] != '_' + if not k.startsWith('_') kk = k obj['_object'] = true - storeParams(v, path.concat(k), obj['_timestamp'] or 1, descendantsFetched, projTree?[k]) + storeParams(v, path.concat(k), obj['_timestamp'], descendantsFetched, projTree?[k]) delete projTree[kk] if projTree - if obj['_timestamp'] - if descendantsFetched - res.push([path.concat('*'), obj['_timestamp']]) - else - for k, v of projTree - p = path.concat(k) + if not descendantsFetched + for k, v of projTree + p = path.concat(k) + loaded.push([p, ((1 << path.length) - 1) ^ ((1 << MAX_DEPTH) - 1)]) + if (obj['_object'] or path.length == 0) and obj['_timestamp'] res.push([p, obj['_timestamp']]) - loaded.push([p, ((1 << path.length) - 1) ^ ((1 << MAX_DEPTH) - 1)]) + else if (obj['_object'] or path.length == 0) and obj['_timestamp'] + res.push([path.concat('*'), obj['_timestamp']]) for k, v of device switch k @@ -413,17 +433,17 @@ saveDevice = (deviceId, deviceData, isNew, callback) -> continue for attrName of diff[2] - if diff[2][attrName][1]? or diff[1]?[attrName]?[1]? + if diff[2][attrName][1]? switch attrName when 'value' - if not diff[1] or diff[2].value[1][0] != diff[1].value?[1][0] + if diff[2].value[1][0] != diff[1]?.value?[1]?[0] if diff[2].value[1][1] == 'xsd:dateTime' and Number.isInteger(diff[2].value[1][0]) update['$set'][path.concat('_value').join('.')] = new Date(diff[2].value[1][0]) else update['$set'][path.concat('_value').join('.')] = diff[2].value[1][0] - if not diff[1] or diff[2].value[1][1] != diff[1].value?[1][1] + if diff[2].value[1][1] != diff[1]?.value?[1]?[1] update['$set'][path.concat('_type').join('.')] = diff[2].value[1][1] - if not diff[1] or diff[2].value[0] != diff[1].value?[0] + if diff[2].value[0] != diff[1]?.value?[0] update['$set'][path.concat('_timestamp').join('.')] = new Date(diff[2].value[0]) when 'object' if not diff[1]?.object or diff[2].object[1] != diff[1].object?[1] @@ -434,12 +454,21 @@ saveDevice = (deviceId, deviceData, isNew, callback) -> if diff[1] for attrName of diff[1] - if attrName not of diff[2] + if diff[1][attrName][1]? and not diff[2]?[attrName]?[1]? update['$unset'][path.concat("_#{attrName}").join('.')] = 1 if attrName is 'value' update['$unset'][path.concat('_type').join('.')] = 1 update['$unset'][path.concat('_timestamp').join('.')] = 1 + update['$unset'] = optimizeProjection(update['$unset']) + + # Remove overlap possibly caused by parameters changing from objects + # to regular parameters or vice versa. Reason being that _timestamp + # represents two different things depending on whether the parameter + # is an object or not. + for k of update['$unset'] + delete update['$unset'][k] if update['$set'][k]? + # Remove empty keys for k of update if k == '$addToSet' @@ -452,9 +481,6 @@ saveDevice = (deviceId, deviceData, isNew, callback) -> return callback() if Object.keys(update).length == 0 - if (update['$unset']?) - update['$unset'] = optimizeProjection(update['$unset']) - if update['$addToSet'] and update['$pull'] # Mongo doesn't allow $addToSet and $pull at the same time update2 = {'$pull': update['$pull']}