@cocreate/indexeddb 1.13.4 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -41,30 +41,4 @@ jobs:
41
41
  outputs:
42
42
  new_release_published: "${{ steps.semantic.outputs.new_release_published }}"
43
43
  new_release_version: "${{ steps.semantic.outputs.new_release_version }}"
44
- upload:
45
- runs-on: ubuntu-latest
46
- needs: release
47
- if: needs.release.outputs.new_release_published == 'true'
48
- env:
49
- VERSION: "${{ needs.release.outputs.new_release_version }}"
50
- steps:
51
- - name: Checkout
52
- uses: actions/checkout@v3
53
- - name: Setup Node.js
54
- uses: actions/setup-node@v3
55
- with:
56
- node-version: 16
57
- - name: Set npm registry auth
58
- run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
59
- - name: Install dependencies
60
- run: yarn install
61
- - name: Build
62
- run: yarn build
63
- - name: Set Environment Variables
64
- run: |
65
- echo "organization_id=${{ secrets.COCREATE_ORGANIZATION_ID }}" >> $GITHUB_ENV
66
- echo "key=${{ secrets.COCREATE_KEY }}" >> $GITHUB_ENV
67
- echo "host=${{ secrets.COCREATE_HOST }}" >> $GITHUB_ENV
68
- - name: CoCreate Upload
69
- run: coc upload
70
44
 
package/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ # [1.14.0](https://github.com/CoCreate-app/CoCreate-indexeddb/compare/v1.13.5...v1.14.0) (2023-10-09)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * cursor() iteration bug ([394d1e9](https://github.com/CoCreate-app/CoCreate-indexeddb/commit/394d1e98d56f94b1495aad44a78718d56199b728))
7
+ * data.request and data.timeStamp conditions ([bf28152](https://github.com/CoCreate-app/CoCreate-indexeddb/commit/bf28152bf181ea0ad4552a5d829f5b0c0d87396c))
8
+
9
+
10
+ ### Features
11
+
12
+ * $each operator adds each item to an array ([b085764](https://github.com/CoCreate-app/CoCreate-indexeddb/commit/b08576473b25534333d768930d97834fda885ff4))
13
+ * isValidDate imported from utils to check key values for date strings and convert to object ([a822f9b](https://github.com/CoCreate-app/CoCreate-indexeddb/commit/a822f9b97bbb11ab87b0ae47dcd543877b6c1cb4))
14
+ * support update operators similar to mongodb ([dc7bd71](https://github.com/CoCreate-app/CoCreate-indexeddb/commit/dc7bd71c57bcae8ad1760b01ebfe406aec3f8800))
15
+
16
+ ## [1.13.5](https://github.com/CoCreate-app/CoCreate-indexeddb/compare/v1.13.4...v1.13.5) (2023-09-18)
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+ * Add path and pathname ([9324f2b](https://github.com/CoCreate-app/CoCreate-indexeddb/commit/9324f2b2088060ac9dd44e8479538328cacb99e7))
22
+ * Update CoCreate depndencies to latest versions ([635996b](https://github.com/CoCreate-app/CoCreate-indexeddb/commit/635996bdde146f632eab7bc8cc4f674d6f5b585f))
23
+
1
24
  ## [1.13.4](https://github.com/CoCreate-app/CoCreate-indexeddb/compare/v1.13.3...v1.13.4) (2023-09-17)
2
25
 
3
26
 
@@ -8,17 +8,16 @@ module.exports = {
8
8
  "object": {
9
9
  "_id": "637ca2aa50234ef1671ce308",
10
10
  "name": "index.html",
11
- "path": "/docs/indexeddb/index.html",
11
+ "path": "/docs/indexeddb",
12
+ "pathname": "/docs/indexeddb/index.html",
12
13
  "src": "{{./docs/index.html}}",
13
14
  "host": [
14
15
  "cocreate.app",
15
16
  "general.cocreate.app"
16
17
  ],
17
- "directory": "/docs/indexeddb",
18
- "parentDirectory": "{{parentDirectory}}",
18
+ "directory": "indexeddb",
19
19
  "content-type": "{{content-type}}",
20
- "public": "true",
21
- "website_id": "644d4bff8036fb9d1d1fd69c"
20
+ "public": "true"
22
21
  }
23
22
  }
24
23
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/indexeddb",
3
- "version": "1.13.4",
3
+ "version": "1.14.0",
4
4
  "description": "A simple indexeddb component in vanilla javascript. Easily configured using HTML5 data-attributes and/or JavaScript API.",
5
5
  "keywords": [
6
6
  "indexeddb",
@@ -58,6 +58,6 @@
58
58
  "webpack-log": "^3.0.1"
59
59
  },
60
60
  "dependencies": {
61
- "@cocreate/utils": "^1.24.0"
61
+ "@cocreate/utils": "^1.24.2"
62
62
  }
63
63
  }
package/src/index.js CHANGED
@@ -15,15 +15,18 @@
15
15
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16
16
  ********************************************************************************/
17
17
 
18
- // Commercial Licensing Information:
19
- // For commercial use of this software without the copyleft provisions of the AGPLv3,
20
- // you must obtain a commercial license from CoCreate LLC.
21
- // For details, visit <https://cocreate.app/licenses/> or contact us at sales@cocreate.app.
18
+ /**
19
+ * Commercial Licensing Information:
20
+ * For commercial use of this software without the copyleft provisions of the AGPLv3,
21
+ * you must obtain a commercial license from CoCreate LLC.
22
+ * For details, visit <https://cocreate.app/licenses/> or contact us at sales@cocreate.app
23
+ */
22
24
 
23
- import { ObjectId, dotNotationToObject, searchData, sortData, queryData } from '@cocreate/utils'
25
+ import { ObjectId, dotNotationToObject, searchData, sortData, queryData, isValidDate } from '@cocreate/utils'
24
26
 
25
27
  // let status = true;
26
28
  let indexedDbFunction
29
+
27
30
  function init() {
28
31
  // Check for support.
29
32
  if (!('indexedDB' in window)) {
@@ -73,9 +76,13 @@ async function send(data) {
73
76
  data[type] = data.request
74
77
 
75
78
  if (!data['timeStamp'])
76
- data['timeStamp'] = new Date().toISOString()
79
+ data['timeStamp'] = new Date()
80
+ else
81
+ data['timeStamp'] = new Date(data['timeStamp'])
77
82
 
78
83
  let databases = data.database;
84
+ if (!databases && data.organization_id)
85
+ databases = [data.organization_id]
79
86
  if (!Array.isArray(databases))
80
87
  databases = [databases]
81
88
 
@@ -112,8 +119,8 @@ const processDatabase = (data, newData, type) => {
112
119
  if (data.request)
113
120
  data[type] = data.request
114
121
 
115
- if (!data['timeStamp'])
116
- data['timeStamp'] = new Date().toISOString()
122
+ // if (!data['timeStamp'])
123
+ data['timeStamp'] = new Date(data['timeStamp'])
117
124
 
118
125
  if (data.method == 'read.database') {
119
126
  indexedDB.databases().then((databases) => {
@@ -121,9 +128,9 @@ const processDatabase = (data, newData, type) => {
121
128
  if (data.$filter && data.$filter.query) {
122
129
  let isFilter = queryData(database, data.$filter.query)
123
130
  if (isFilter)
124
- newData.push({ $storage: 'indexeddb', $database: database })
131
+ newData.push({ $storage: 'indexeddb', ...database })
125
132
  } else
126
- newData.push({ $storage: 'indexeddb', $database: database })
133
+ newData.push({ $storage: 'indexeddb', ...database })
127
134
  }
128
135
 
129
136
  resolve()
@@ -435,20 +442,30 @@ async function processObject(data, newData, database, array, type) {
435
442
  if (!array || !db)
436
443
  throw new Error({ error: "This is an error message.", db, array });
437
444
 
438
- let transactionType = "readwrite"
445
+ let transactionType = "readwrite" //test
439
446
  if (data.method == 'read.object')
440
447
  transactionType = "readonly"
441
448
 
442
449
  let transaction = db.transaction([array], transactionType);
443
450
  let objectStore = transaction.objectStore(array);
444
-
451
+ if (!data[type])
452
+ data[type] = []
445
453
  if (data[type] && !Array.isArray(data[type]))
446
454
  data[type] = [data[type]]
447
455
 
448
- if (isFilter && (!data[type] || !data[type].length))
456
+ if (isFilter && !data[type].length)
449
457
  data[type] = [{}]
450
458
 
459
+ let globalOperators = getGlobalOperators(data)
451
460
  let upsert = data.upsert
461
+
462
+ if (data.$filter) {
463
+ let count = objectStore.count();
464
+ count.onsuccess = function () {
465
+ data.$filter.count = count.result
466
+ }
467
+ }
468
+
452
469
  try {
453
470
 
454
471
  for (let i = 0; i < data[type].length; i++) {
@@ -457,6 +474,9 @@ async function processObject(data, newData, database, array, type) {
457
474
  delete data[type][i].$array
458
475
 
459
476
  if (data.method == 'create.object') {
477
+ if (data.organization_id)
478
+ data[type][i]['organization_id'] = data.organization_id
479
+
460
480
  if (!data[type][i]._id)
461
481
  data[type][i]['_id'] = ObjectId()
462
482
  data[type][i] = dotNotationToObject(data[type][i])
@@ -467,15 +487,15 @@ async function processObject(data, newData, database, array, type) {
467
487
  } else {
468
488
  if (data[type][i].$filter)
469
489
  isFilter = true
470
- if (data.organization_id)
471
- data[type][i]['organization_id'] = data.organization_id
490
+ // if (data.organization_id)
491
+ // data[type][i]['organization_id'] = data.organization_id
472
492
 
473
493
  if (data.method == 'update.object') {
494
+ if (data.organization_id)
495
+ data[type][i]['organization_id'] = data.organization_id
496
+
474
497
  if (data[type][i].$upsert)
475
498
  upsert = data[type][i].$upsert
476
-
477
- if (!data[type][i]._id && upsert)
478
- data[type][i]._id = ObjectId()
479
499
  data[type][i]['modified'] = { on: data.timeStamp, by: data.user_id || data.clientId }
480
500
  }
481
501
 
@@ -483,10 +503,10 @@ async function processObject(data, newData, database, array, type) {
483
503
  if (data[type][i]._id)
484
504
  range = IDBKeyRange.only(data[type][i]._id);
485
505
  else if (isFilter) {
486
- if (data.$filter || object.$filter) {
506
+ if (data.object.$filter) {
487
507
  let count = objectStore.count();
488
508
  count.onsuccess = function () {
489
- data.$filter.count = count.result
509
+ data.object.$filter.count = count.result
490
510
  }
491
511
  }
492
512
 
@@ -529,52 +549,212 @@ async function processObject(data, newData, database, array, type) {
529
549
  if (data.$filter.limit)
530
550
  limit = data.$filter.limit
531
551
  if (limit)
532
- limit = index + limit;
552
+ limit = (index || 0) + limit;
533
553
  }
534
554
  }
535
555
 
536
- let cursor = await openCursor(objectStore, range, direction)
537
- if (cursor) {
538
- let isMatch = true
539
-
540
- if (isFilter)
541
- isMatch = filter(objectStore, data[type][i], cursor.value)
542
-
543
- if (isMatch !== false) {
544
- let result
545
- if (data.method == 'create.object') {
546
- result = await add(objectStore, data[type][i])
547
- } else if (data.method == 'read.object') {
548
- result = await get(objectStore, data[type][i])
549
- } else if (data.method == 'update.object') {
550
- data[type][i] = dotNotationToObject(data[type][i], cursor.value)
551
- data[type][i] = createUpdate(data, data[type][i])
552
- result = await put(objectStore, data[type][i])
553
- } else if (data.method == 'delete.object') {
554
- result = await deleteObject(objectStore, data[type][i])
555
- }
556
+ await openCursor(objectStore, range, direction, data, newData, isFilter, limit, database, array, upsert, type, i, globalOperators);
556
557
 
557
- newData.push({ $storage: 'indexeddb', $database: database, $array: array, ...result })
558
- }
559
-
560
- limit && limit == newData.length ? '' : cursor.continue();
561
-
562
- } else if (index)
558
+ if (index)
563
559
  newData = newData.slice(index)
560
+
564
561
  }
562
+
565
563
  }
566
564
  } catch (error) {
565
+ console.log(error)
567
566
  errorHandler(data, error, database, array)
568
567
  }
569
568
 
570
569
  db.close()
571
570
  }
572
571
 
573
- function openCursor(objectStore, range, direction) {
572
+ function getGlobalOperators(data, object = {}) {
573
+ for (let operator of Object.keys(data)) {
574
+ if (!operator.startsWith('$'))
575
+ return
576
+ for (let key of Object.keys(data[operator]))
577
+ object[operator + '.' + key] = data[operator][key]
578
+ }
579
+
580
+ return object
581
+ }
582
+
583
+ function createUpdate(update, data, globalOpertors) {
584
+ let operatorKeys = {}
585
+ if (globalOpertors)
586
+ operatorKeys = { ...globalOpertors }
587
+
588
+ Object.keys(data).forEach(key => {
589
+ if (key === '_id')
590
+ return
591
+
592
+ if (key.startsWith('$')) {
593
+ if (!key.includes('.'))
594
+ for (let oldkey of Object.keys(data[key]))
595
+ operatorKeys[key + '.' + oldkey] = data[key][oldkey]
596
+ else
597
+ operatorKeys[key] = data[key]
598
+ } else if (typeof data[key] === 'string' && data[key].startsWith('$')) {
599
+ operatorKeys[data[key] + '.' + key] = data[key]
600
+ } else if (key.endsWith(']')) {
601
+ const regex = /^(.*(?:\[\d+\].*?)?)\[(.*?)\](?:\[\])?$/;
602
+ const match = key.match(regex);
603
+ if (match[2] === '')
604
+ operatorKeys['$push.' + match[1]] = data[key]
605
+ else {
606
+ let index = parseInt(match[2], 10);
607
+ if (index === NaN)
608
+ operatorKeys[match[2] + '.' + match[1]] = data[key]
609
+ else
610
+ operatorKeys[key] = data[key]
611
+ }
612
+ } else if (key.includes('.')) {
613
+ operatorKeys[key] = data[key]
614
+ } else if (data[key] === undefined) {
615
+ delete update[key]
616
+ } else
617
+ update[key] = data[key]
618
+
619
+ })
620
+
621
+ return dotNotationToObjectUpdate(operatorKeys, update)
622
+ }
623
+
624
+ function dotNotationToObjectUpdate(data, object = {}) {
625
+ try {
626
+ for (const key of Object.keys(data)) {
627
+ let value = isValidDate(data[key])
628
+ let newObject = object
629
+ let oldObject = new Object(newObject)
630
+ let keys = key.replace(/\[(\d+)\]/g, '.$1').split('.');
631
+
632
+ if (keys[0].startsWith('$'))
633
+ var operator = keys.shift()
634
+
635
+ let length = keys.length - 1
636
+ for (let i = 0; i < keys.length; i++) {
637
+ if (/^\d+$/.test(keys[i]))
638
+ keys[i] = parseInt(keys[i]);
639
+
640
+ if (length == i) {
641
+ if (operator) {
642
+ let operators = ['$rename', '$inc', '$push', '$each', '$splice', '$unset', '$delete', '$slice', '$pop', '$shift', '$addToSet', '$pull']
643
+ if (!operators.includes(operator))
644
+ continue
645
+ if (operator === '$rename') {
646
+ newObject[value] = newObject[keys[i]]
647
+ delete newObject[keys[i]]
648
+ } else if (operator === '$delete' || operator === '$unset' || operator === '$slice') {
649
+ if (typeof keys[i] === 'number')
650
+ newObject.slice(keys[i], 1);
651
+ else
652
+ delete newObject[keys[i]]
653
+ } else if (operator === '$shift') {
654
+ newObject[keys[i]].shift();
655
+ } else if (operator === '$pop') {
656
+ newObject[keys[i]].pop();
657
+ } else if (operator === '$addToSet' || operator === '$pull') {
658
+ // find matching items and update or delete
659
+ key = arrayKey
660
+ updates[key] = data[originalKey]
661
+ } else if (operator === '$push' || operator === '$splice') {
662
+ if (typeof keys[i] === 'number' && newObject.length >= keys[i])
663
+ newObject.splice(keys[i], 0, value);
664
+ else
665
+ newObject[keys[i]].push(value);
666
+ } else if (operator === '$each') {
667
+ if (!Array.isArray(value))
668
+ value = [value]
669
+ if (typeof keys[i] === 'number')
670
+ newObject.splice(keys[i], 0, ...value);
671
+ else
672
+ newObject[keys[i]].push(...value);
673
+ } else if (operator === '$inc') {
674
+ newObject[keys[i]] += value
675
+ }
676
+ } else if (value === undefined) {
677
+ if (typeof keys[i] === 'number')
678
+ newObject.slice(keys[i], 1);
679
+ else
680
+ delete newObject[keys[i]]
681
+ } else
682
+ newObject[keys[i]] = value;
683
+ } else {
684
+ newObject[keys[i]] = oldObject[keys[i]] || {};
685
+ newObject = newObject[keys[i]]
686
+ oldObject = oldObject[keys[i]]
687
+ }
688
+ }
689
+ }
690
+ return object
691
+ } catch (error) {
692
+ console.log("Error converting dot notation to object", error);
693
+ return false;
694
+ }
695
+ }
696
+
697
+ function openCursor(objectStore, range, direction, data, newData, isFilter, limit, database, array, upsert, type, i, globalOperators) {
574
698
  return new Promise(async (resolve, reject) => {
575
- const request = objectStore.openCursor(range, direction);// next, prev
576
- request.onsuccess = () => resolve(request.result);
577
- request.onerror = () => reject(request.error)
699
+ const request = objectStore.openCursor(range || null, direction);// next, prev
700
+
701
+ request.onsuccess = async () => {
702
+ let cursor = request.result
703
+
704
+ if (!cursor && data.method === 'update.object' && upsert) {
705
+ let isMatch = true
706
+ if (isFilter)
707
+ isMatch = filter(objectStore, data[type][i], data[type][i])
708
+
709
+ if (isMatch !== false) {
710
+ try {
711
+ data[type][i]._id = ObjectId(data[type][i]._id);
712
+ } catch (error) {
713
+ data[type][i]._id = ObjectId()
714
+ }
715
+
716
+ let result = await put(objectStore, data[type][i])
717
+ newData.push({ $storage: 'indexeddb', $database: database, $array: array, ...result })
718
+ }
719
+ } else if (cursor) {
720
+ let isMatch = true
721
+
722
+ if (isFilter)
723
+ isMatch = filter(objectStore, data, data[type][i], cursor.value)
724
+
725
+ if (isMatch !== false) {
726
+ let result = cursor.value
727
+ if (data.method == 'create.object') {
728
+ result = await add(objectStore, data[type][i])
729
+ } else if (data.method == 'update.object') {
730
+ let update = createUpdate(cursor.value, data[type][i], globalOperators)
731
+ if (update)
732
+ result = await put(objectStore, update)
733
+ // set dotnotation for keys with $operators for items that end in [] to be used by socket.id
734
+ // TODO: if update.$<operator>.someKey[] requires the index of inerted item added to the field name. update.$<operator>.someKey[<index>]
735
+ // TODO: if $addToSet get field name and item if it does not exist.
736
+ // TODO: if $pull get field name and find if item exist and delete.
737
+ } else if (data.method == 'delete.object') {
738
+ result = cursor.value
739
+ cursor.delete()
740
+ }
741
+
742
+ newData.push({ $storage: 'indexeddb', $database: database, $array: array, ...result })
743
+ }
744
+
745
+ if (!limit || limit && limit < newData.length) {
746
+ cursor.continue();
747
+ } else {
748
+ cursor.close()
749
+ }
750
+ } else {
751
+ resolve();
752
+ }
753
+ }
754
+
755
+ request.onerror = () => {
756
+ reject(request.error)
757
+ }
578
758
  });
579
759
  }
580
760
 
@@ -611,25 +791,7 @@ function deleteObject(objectStore, object) {
611
791
  }
612
792
 
613
793
 
614
- function createUpdate(data, object) {
615
- if (data.updateName) {
616
- for (let key of Object.keys(data.updateName)) {
617
- let val = object[key]
618
- delete object[key]
619
- object[data.updateName[key]] = val
620
- }
621
- }
622
-
623
- if (data.deleteName) {
624
- for (let key of Object.keys(data.deleteName)) {
625
- delete object[key]
626
- }
627
-
628
- }
629
- return object
630
- }
631
-
632
- function filter(data, object, result) {
794
+ function filter(objectStore, data, object, result) {
633
795
  let isMatch = true;
634
796
 
635
797
  if (data.$filter || object.$filter) {
@@ -689,4 +851,4 @@ function errorHandler(data, error, database, array) {
689
851
 
690
852
  init();
691
853
 
692
- export default { send }
854
+ export default { send, ObjectId }
package/test/index.html CHANGED
@@ -15,8 +15,9 @@
15
15
 
16
16
  <body>
17
17
  <!-- <script src="../../../CoCreateJS/dist/CoCreate.js"></script> -->
18
- <script src="https://CoCreate.app/dist/CoCreate.js"></script>
19
- <!-- <script src="../dist/CoCreate-indexeddb.js"></script> -->
18
+ <script src="https://cocreate.app/dist/CoCreate.js"></script>
19
+ <!-- <script src="../../../CoCreateJS/dist/indexeddb-chunk.js"></script> -->
20
+ <script src="./operators.js"></script>
20
21
  <script src="./databases.js"></script>
21
22
  <script src="./arrays.js"></script>
22
23
  <script src="./indexes.js"></script>
@@ -0,0 +1,105 @@
1
+ function createUpdate(update, data, globalOpertors) {
2
+ let operatorKeys = {}
3
+ if (globalOpertors)
4
+ operatorKeys = { ...globalOpertors }
5
+
6
+ Object.keys(data).forEach(key => {
7
+ if (key === '_id')
8
+ return
9
+
10
+ if (key.startsWith('$')) {
11
+ if (!key.includes('.'))
12
+ for (let oldkey of Object.keys(data[key]))
13
+ operatorKeys[key + '.' + oldkey] = data[key][oldkey]
14
+ else
15
+ operatorKeys[key] = data[key]
16
+ } else if (typeof data[key] === 'string' && data[key].startsWith('$')) {
17
+ operatorKeys[data[key] + '.' + key] = data[key]
18
+ } else if (key.endsWith(']')) {
19
+ const regex = /^(.*(?:\[\d+\].*?)?)\[(.*?)\](?:\[\])?$/;
20
+ const match = key.match(regex);
21
+ if (match[2] === '')
22
+ operatorKeys['$push.' + match[1]] = data[key]
23
+ else {
24
+ let index = parseInt(match[2], 10);
25
+ if (index === NaN)
26
+ operatorKeys[match[2] + '.' + match[1]] = data[key]
27
+ else
28
+ operatorKeys[key] = data[key]
29
+ }
30
+ } else if (key.includes('.')) {
31
+ operatorKeys[key] = data[key]
32
+ } else if (data[key] === undefined) {
33
+ delete update[key]
34
+ } else
35
+ update[key] = data[key]
36
+
37
+ })
38
+
39
+ return dotNotationToObjectUpdate(operatorKeys, update)
40
+ }
41
+
42
+ function dotNotationToObjectUpdate(data, object = {}) {
43
+ try {
44
+ for (const key of Object.keys(data)) {
45
+ let value = data[key]
46
+ let newObject = object
47
+ let oldObject = new Object(newObject)
48
+ let keys = key.replace(/\[(\d+)\]/g, '.$1').split('.');
49
+
50
+ if (keys[0].startsWith('$'))
51
+ var operator = keys.shift()
52
+
53
+ let length = keys.length - 1
54
+ for (let i = 0; i < keys.length; i++) {
55
+ if (/^\d+$/.test(keys[i]))
56
+ keys[i] = parseInt(keys[i]);
57
+
58
+ if (length == i) {
59
+ // TODO: operator updates
60
+ if (operator) {
61
+ if (operator === '$rename') {
62
+ newObject[value] = newObject[keys[i]]
63
+ delete newObject[keys[i]]
64
+ } else if (operator === '$delete' || operator === '$unset' || operator === '$slice') {
65
+ if (typeof keys[i] === 'number')
66
+ newObject.slice(keys[i], 1);
67
+ else
68
+ delete newObject[keys[i]]
69
+ } else if (operator === '$shift') {
70
+ newObject[keys[i]].shift();
71
+ } else if (operator === '$pop') {
72
+ newObject[keys[i]].pop();
73
+ } else if (operator === '$addToSet' || operator === '$pull') {
74
+ // find matching items and update or delete
75
+ key = arrayKey
76
+ updates[key] = data[originalKey]
77
+ } else if (operator === '$push' || operator === '$splice') {
78
+ // TODO: support pushing an array as values
79
+ if (typeof keys[i] === 'number' && newObject.length >= keys[i])
80
+ newObject.splice(keys[i], 0, value);
81
+ else
82
+ newObject[keys[i]].push(value);
83
+ } else if (operator === '$inc') {
84
+ newObject[keys[i]] += value
85
+ }
86
+ } else if (value === undefined) {
87
+ if (typeof keys[i] === 'number')
88
+ newObject.slice(keys[i], 1);
89
+ else
90
+ delete newObject[keys[i]]
91
+ } else
92
+ newObject[keys[i]] = value;
93
+ } else {
94
+ newObject[keys[i]] = oldObject[keys[i]] || {};
95
+ newObject = newObject[keys[i]]
96
+ oldObject = oldObject[keys[i]]
97
+ }
98
+ }
99
+ }
100
+ return object
101
+ } catch (error) {
102
+ console.log("Error converting dot notation to object", error);
103
+ return false;
104
+ }
105
+ }