From ff83e35a631036820aae6872e1547c715f3c89dc Mon Sep 17 00:00:00 2001
From: theia
Date: Mon, 6 Feb 2023 15:21:00 -0500
Subject: assignment in one component leads to assignment in another...
---
demo/components/moderation.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/demo/components/moderation.js b/demo/components/moderation.js
index 4cf8071..5e12fb0 100644
--- a/demo/components/moderation.js
+++ b/demo/components/moderation.js
@@ -51,7 +51,7 @@ export default {
- -
+
-
:
{{ object.message }}
--
cgit v1.2.3-70-g09d2
From 4d3c179fd1ab64eb09564cb778a16b4d8c430dd9 Mon Sep 17 00:00:00 2001
From: theia
Date: Mon, 6 Feb 2023 17:40:35 -0500
Subject: changed implimentations of object storage
---
graffiti.js | 79 +++++++++++++++++++++++++++++----------------------
plugins/vue/plugin.js | 2 +-
2 files changed, 46 insertions(+), 35 deletions(-)
diff --git a/graffiti.js b/graffiti.js
index 824fdf6..623cd0d 100644
--- a/graffiti.js
+++ b/graffiti.js
@@ -6,13 +6,13 @@ export default class {
// There needs to be a new object map for each tag
constructor(
graffitiURL="https://graffiti.garden",
- objectMapConstructor=()=>({})) {
+ objectConstructor=()=>({})) {
this.graffitiURL = graffitiURL
- this.objectMapConstructor = objectMapConstructor
this.open = false
this.eventTarget = new EventTarget()
- this.tagMap = {}
+ this.tagMap = objectConstructor() // tag->{count, Set(uuid)}
+ this.objectMap = objectConstructor() // uuid->object
this.GraffitiArray = GraffitiArray(this)
this.#initialize()
@@ -127,30 +127,29 @@ export default class {
#updateCallback(object) {
const uuid = this.#objectUUID(object)
- let originalObject = null
+ // Add the UUID to the tag map
for (const tag of object._tags) {
if (!(tag in this.tagMap)) continue
- const objectMap = this.tagMap[tag].objectMap
-
- if (uuid in objectMap) {
- // Copy the original object if
- // one exists, in case of failure
- originalObject = Object.assign({},objectMap[uuid])
-
- // Replace the object by copying
- // so references to it don't break
- this.#recursiveCopy(objectMap[uuid], object)
- } else if (!('_id' in object)) {
+ this.tagMap[tag].uuids.add(uuid)
+ }
- // Add properties to the object
- // so it can be updated and removed
- // without the collection
- Object.defineProperty(object, '_id', { value: this.#objectUUID(object) })
- Object.defineProperty(object, '_update', { value: ()=>this.update(object) })
- Object.defineProperty(object, '_remove', { value: ()=>this.remove(object) })
+ // Add the object to the object map
+ let originalObject = null
+ if (uuid in this.objectMap) {
+ originalObject = Object.assign({},this.objectMap[uuid])
- objectMap[uuid] = object
- }
+ // Replace the object by copying
+ // so references to it don't break
+ this.#recursiveCopy(this.objectMap[uuid], object)
+ } else {
+ // Add properties to the object
+ // so it can be updated and removed
+ // without the collection
+ Object.defineProperty(object, '_id', { value: this.#objectUUID(object) })
+ Object.defineProperty(object, '_update', { value: ()=>this.update(object) })
+ Object.defineProperty(object, '_remove', { value: ()=>this.remove(object) })
+
+ this.objectMap[uuid] = object
}
// Return the original in case of failure
@@ -160,14 +159,15 @@ export default class {
#removeCallback(object) {
const uuid = this.#objectUUID(object)
- let originalObject = null
+ // Remove the UUID from the tag map
for (const tag of object._tags) {
if (!(tag in this.tagMap)) continue
- const objectMap = this.tagMap[tag].objectMap
+ this.tagMap[tag].uuids.delete(uuid)
+ }
- if (!(uuid in objectMap)) return
- originalObject = Object.assign({},objectMap[uuid])
- delete objectMap[uuid]
+ // And the object map
+ if (uuid in this.objectMap) {
+ delete this.objectMap[uuid]
}
}
@@ -225,6 +225,7 @@ export default class {
}
}
+
async myTags() {
return await this.#request({ ls: null })
}
@@ -236,7 +237,7 @@ export default class {
}})
}
- objectsByTags(...tags) {
+ objects(...tags) {
tags = tags.filter(tag=> tag!=null)
for (const tag of tags) {
if (!(tag in this.tagMap)) {
@@ -244,12 +245,13 @@ export default class {
}
}
- // Merge by UUID to combine all the maps
- const combinedMaps = Object.assign({},
- ...tags.map(tag=> this.tagMap[tag].objectMap))
+ // Merge by UUIDs from all tags and
+ // convert to relevant objects
+ const uuids = new Set(tags.map(tag=>[...this.tagMap[tag].uuids]).flat())
+ const objects = [...uuids].map(uuid=>this.objectMap[uuid])
// Return an array wrapped with graffiti functions
- return new this.GraffitiArray(...Object.values(combinedMaps))
+ return new this.GraffitiArray(...objects)
}
async subscribe(...tags) {
@@ -263,7 +265,7 @@ export default class {
} else {
// Create a new slot
this.tagMap[tag] = {
- objectMap: this.objectMapConstructor(),
+ uuids: new Set(),
count: 1
}
subscribingTags.push(tag)
@@ -346,3 +348,12 @@ export default class {
}
}
+// If any in object
+//if (['_by', '_key', '_id'] in object) {
+ //throw "No predefining keys"
+//}
+
+// Add tags
+//if ('_tags' in object && !Array.isArray(object._to)) {
+ //throw new Error("_tags must be an array")
+//}
diff --git a/plugins/vue/plugin.js b/plugins/vue/plugin.js
index f789449..f04098e 100644
--- a/plugins/vue/plugin.js
+++ b/plugins/vue/plugin.js
@@ -65,7 +65,7 @@ export default {
computed: {
objects() {
- return graffiti.objectsByTags(...this.tags)
+ return graffiti.objects(...this.tags)
}
},
--
cgit v1.2.3-70-g09d2
From 5b951766757d89a4ab91457e8dbeabc50164ccdc Mon Sep 17 00:00:00 2001
From: theia
Date: Tue, 7 Feb 2023 12:52:04 -0500
Subject: update and remove implicitly via proxy
---
demo/components/chat.js | 4 +-
graffiti.js | 140 +++++++++++++++++++++++-------------------------
src/array.js | 5 +-
3 files changed, 71 insertions(+), 78 deletions(-)
diff --git a/demo/components/chat.js b/demo/components/chat.js
index 2d68ee0..52470f0 100644
--- a/demo/components/chat.js
+++ b/demo/components/chat.js
@@ -45,11 +45,11 @@ export default {
-
diff --git a/graffiti.js b/graffiti.js
index 623cd0d..59e71eb 100644
--- a/graffiti.js
+++ b/graffiti.js
@@ -128,29 +128,34 @@ export default class {
const uuid = this.#objectUUID(object)
// Add the UUID to the tag map
+ let subscribed = false
for (const tag of object._tags) {
if (!(tag in this.tagMap)) continue
this.tagMap[tag].uuids.add(uuid)
+ subscribed = true
}
- // Add the object to the object map
- let originalObject = null
- if (uuid in this.objectMap) {
- originalObject = Object.assign({},this.objectMap[uuid])
-
- // Replace the object by copying
- // so references to it don't break
- this.#recursiveCopy(this.objectMap[uuid], object)
- } else {
- // Add properties to the object
- // so it can be updated and removed
- // without the collection
- Object.defineProperty(object, '_id', { value: this.#objectUUID(object) })
- Object.defineProperty(object, '_update', { value: ()=>this.update(object) })
- Object.defineProperty(object, '_remove', { value: ()=>this.remove(object) })
-
- this.objectMap[uuid] = object
+ if (!subscribed) return
+
+ // Store the original object in case
+ // there is an error with the update
+ const originalObject = uuid in this.objectMap?
+ Object.assign({},this.objectMap[uuid]) : null
+
+ // Assign the object UUID
+ Object.defineProperty(object, '_id', { value: uuid })
+
+ // Add proxy functions so object modifications
+ // sync with the server
+ const handler = {
+ get: (target, prop, receiver)=>
+ this.#getObjectProperty(handler, target, prop, receiver),
+ set: (target, prop, val, receiver)=>
+ this.#setObjectProperty(object, target, prop, val, receiver),
+ deleteProperty: (target, prop)=>
+ this.#deleteObjectProperty(object, target, prop)
}
+ this.objectMap[uuid] = new Proxy(object, handler)
// Return the original in case of failure
return originalObject
@@ -172,17 +177,7 @@ export default class {
}
async update(object) {
- if (!this.myID) {
- throw 'you can\'t update objects without logging in!'
- }
-
- // Add by/to fields
object._by = this.myID
- if ('_to' in object && !Array.isArray(object._to)) {
- throw new Error("_to must be an array")
- }
-
- // Pre-generate the object's ID if it does not already exist
if (!object._key) object._key = crypto.randomUUID()
// Immediately replace the object
@@ -203,29 +198,54 @@ export default class {
}
}
- async remove(object) {
- if (!this.myID) {
- throw 'you can\'t remove objects without logging in!'
- }
-
- if (this.myID != object._by) {
- throw 'you can\'t remove an object that isn\'t yours!'
+ #getObjectProperty(handler, target, prop, receiver) {
+ if (typeof target[prop] === 'object' && target[prop] !== null) {
+ return new Proxy(Reflect.get(target, prop, receiver), handler)
+ } else {
+ return Reflect.get(target, prop, receiver)
}
+ }
- // Immediately remove the object
- // but store it in case there is an error
- const originalObject = this.#removeCallback(object)
+ #setObjectProperty(object, target, prop, val, receiver) {
+ // Store the original, perform the update,
+ // sync with server and restore original if error
+ const originalObject = Object.assign({}, object)
+ if (Reflect.set(target, prop, val, receiver)) {
+ this.#request({ update: object }).catch(e=> {
+ this.#updateCallback(originalObject)
+ throw e
+ })
+ return true
+ } else { return false }
+ }
- try {
- return await this.#request({ remove: object._key })
- } catch(e) {
- // Delete failed, restore the object
- if (originalObject) this.#updateCallback(originalObject)
- throw e
+ #deleteObjectProperty(object, target, prop) {
+ const originalObject = Object.assign({}, object)
+ if (object==target && ['_key', '_by', '_tags'].includes(prop)) {
+ // This is a deletion of the whole object
+ const uuid = this.#objectUUID(object)
+ for (const tag of object._tags) {
+ if (!(tag in this.tagMap)) continue
+ this.tagMap[tag].uuids.delete(uuid)
+ }
+ if (!(uuid in this.objectMap)) return false
+ delete this.objectMap[uuid]
+ this.#request({ remove: object._key }).catch(e=> {
+ this.#updateCallback(originalObject)
+ throw e
+ })
+ return true
+ } else {
+ if (Reflect.deleteProperty(target, prop)) {
+ this.#request({ update: object }).catch(e=> {
+ this.#updateCallback(originalObject)
+ throw e
+ })
+ return true
+ } else { return false }
}
}
-
async myTags() {
return await this.#request({ ls: null })
}
@@ -248,7 +268,7 @@ export default class {
// Merge by UUIDs from all tags and
// convert to relevant objects
const uuids = new Set(tags.map(tag=>[...this.tagMap[tag].uuids]).flat())
- const objects = [...uuids].map(uuid=>this.objectMap[uuid])
+ const objects = [...uuids].map(uuid=> this.objectMap[uuid])
// Return an array wrapped with graffiti functions
return new this.GraffitiArray(...objects)
@@ -309,9 +329,9 @@ export default class {
// Clear data
for (let tag in this.tagMap) {
- const objectMap = this.tagMap[tag].objectMap
- for (let uuid in objectMap) delete objectMap[uuid]
+ this.tagMap[tag].uuids = new Set()
}
+ for (let uuid in this.objectMap) delete this.objectMap[uuid]
// Resubscribe
const tags = Object.keys(this.tagMap)
@@ -330,30 +350,4 @@ export default class {
}
return object._by + object._key
}
-
- #recursiveCopy(target, source) {
- for (const field in target) {
- if (!(field in source)) {
- delete target[field]
- }
- }
-
- for (const field in source) {
- if (field in target && typeof target[field] == 'object' && typeof source[field] == 'object') {
- this.#recursiveCopy(target[field], source[field])
- } else {
- target[field] = source[field]
- }
- }
- }
}
-
-// If any in object
-//if (['_by', '_key', '_id'] in object) {
- //throw "No predefining keys"
-//}
-
-// Add tags
-//if ('_tags' in object && !Array.isArray(object._to)) {
- //throw new Error("_tags must be an array")
-//}
diff --git a/src/array.js b/src/array.js
index c53113e..ae30012 100644
--- a/src/array.js
+++ b/src/array.js
@@ -17,9 +17,8 @@ export default function(graffiti) {
return [...new Set(this.map(o=> o._by))]
}
- async removeMine() {
- await Promise.all(
- this.mine.map(async o=> await o._remove()))
+ removeMine() {
+ this.mine.map(o=> delete o._key)
}
#getProperty(obj, propertyPath) {
--
cgit v1.2.3-70-g09d2
From 7413cb9d937986fd11936730d6773f1a270eba48 Mon Sep 17 00:00:00 2001
From: theia
Date: Thu, 9 Feb 2023 13:31:50 -0500
Subject: more robust object editing
---
demo/index.html | 1 -
graffiti.js | 92 ++++++++++++++++++++++++++++-----------------------------
2 files changed, 45 insertions(+), 48 deletions(-)
diff --git a/demo/index.html b/demo/index.html
index 1f05b25..d1b5991 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -11,7 +11,6 @@
"vue": "https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.45/vue.esm-browser.prod.min.js",
"graffiti-vue": "../plugins/vue/plugin.js"
}}
-