From: Lady Date: Mon, 29 May 2023 06:16:00 +0000 (-0700) Subject: Allow “silent” persisting of tags X-Git-Url: https://git.ladys.computer/Etiquette/commitdiff_plain/e3a2a78fdfb9d913f311ff1948038dfbcb758a05?ds=inline;hp=6623cbf39b85515219a3ab012e27d97884ea8aa3 Allow “silent” persisting of tags This simplifies the algorithm a little bit in the case that no output is needed. Diffs are still necessary for properties with inverses. --- diff --git a/model.js b/model.js index 9f7962d..76bf615 100644 --- a/model.js +++ b/model.js @@ -1036,6 +1036,9 @@ class Tag { * serialization of a Tag Activity representing any changes, or * `null` if no changes were made. * + * If the second argument is `true`, the `Tag` will be persisted but + * no serialization will be made. This is somewhat more efficient. + * * ※ Persistence can imply side‐effects on other objects, which are * not noted explicitly in the activity. For example, marking a tag * as broader than another causes the other tag to reciprocally be @@ -1044,17 +1047,19 @@ class Tag { * ※ The inverse terms `hasInCanon`, `isIncludedIn`, and `narrower` * will never appear in the predicates of generated activities. */ - persist() { + persist(silent = false) { const system = this.#system; const storage = this.#storage; const persistedData = this.#persistedData; const data = this.#data; const diffs = {}; for (const [key, value] of Object.entries(data)) { - // Iterate over each entry of the tag data and create a diff with - // the last persisted information. - if (SKIP_IN_DIFF.has(key)) { + // Iterate over each entry of the tag data and create a diff + // with the last persisted information. + if (SKIP_IN_DIFF.has(key) || silent && LITERAL_TERMS.has(key)) { // The current property is one which is skipped in diffs. + // + // In a silent persist, this includes any literal terms. /* do nothing */ } else { // The current property should be diffed. @@ -1130,7 +1135,7 @@ class Tag { this.#identifier = storage.add(this); } const persistedIdentifier = this.#identifier; - this.#persistedData = tagData(data); // need to clone here + this.#persistedData = tagData(data); // cloning here is necessary for ( const [term, inverse] of [ ["broader", "narrower"], @@ -1166,131 +1171,138 @@ class Tag { } } } - const activity = { - "@context": taggingDiscoveryContext, - "@type": [ - "TagActivity", - identifier == null ? "Create" : "Update", - ], - context: `${system.iri}`, - object: `${this.iri}`, - endTime: new Date().toISOString(), - ...(() => { - const statements = { - unstates: [], - states: [], - }; - const { unstates, states } = statements; - if (identifier == null) { - // This is a Create activity. - states.push({ predicate: "a", object: `${this.kind}` }); - } else { - // This is an Update activity. - /* do nothing */ - } - for ( - const [term, { - old: oldValues, - new: newValues, - }] of Object.entries(diffs) - ) { - // Iterate over the diffs of each term and state/unstate - // things as needed. - for (const oldValue of oldValues) { - // Iterate over removals and unstate them. - if (LITERAL_TERMS.has(term)) { - // This is a literal term; push the change wrapped in an - // object. - unstates.push({ - predicate: term, - object: Object(oldValue) === oldValue - ? { ...langString(oldValue) } - : { "@value": `${oldValue}` }, - }); - } else { - // This is a named term; attempt to get its I·R·I and - // push it. - try { - // Attempt to resolve the value and push the change. - const tag = storage.get(oldValue); - if (!this.#isTagInStorage(tag)) { - // The value did not resolve to a tag in storage. + if (silent) { + // This is a silent persist. + return undefined; + } else { + // This is not a silent persist; an activity needs to be + // generated if a change was made. + const activity = { + "@context": taggingDiscoveryContext, + "@type": [ + "TagActivity", + identifier == null ? "Create" : "Update", + ], + context: `${system.iri}`, + object: `${this.iri}`, + endTime: new Date().toISOString(), + ...(() => { + const statements = { + unstates: [], + states: [], + }; + const { unstates, states } = statements; + if (identifier == null) { + // This is a Create activity. + states.push({ predicate: "a", object: `${this.kind}` }); + } else { + // This is an Update activity. + /* do nothing */ + } + for ( + const [term, { + old: oldValues, + new: newValues, + }] of Object.entries(diffs) + ) { + // Iterate over the diffs of each term and state/unstate + // things as needed. + for (const oldValue of oldValues) { + // Iterate over removals and unstate them. + if (LITERAL_TERMS.has(term)) { + // This is a literal term; push the change wrapped in an + // object. + unstates.push({ + predicate: term, + object: Object(oldValue) === oldValue + ? { ...langString(oldValue) } + : { "@value": `${oldValue}` }, + }); + } else { + // This is a named term; attempt to get its I·R·I and + // push it. + try { + // Attempt to resolve the value and push the change. + const tag = storage.get(oldValue); + if (!this.#isTagInStorage(tag)) { + // The value did not resolve to a tag in storage. + /* do nothing */ + } else { + // The value resolved; push its I·R·I. + unstates.push({ + predicate: term, + object: tag.iri, + }); + } + } catch { + // Value resolution failed for some reason; perhaps the + // tag was deleted. /* do nothing */ - } else { - // The value resolved; push its I·R·I. - unstates.push({ - predicate: term, - object: tag.iri, - }); } - } catch { - // Value resolution failed for some reason; perhaps the - // tag was deleted. - /* do nothing */ } } - } - for (const newValue of newValues) { - // Iterate over additions and state them. - if (LITERAL_TERMS.has(term)) { - // This is a literal term; push the change wrapped in an - // object. - states.push({ - predicate: term, - object: Object(newValue) === newValue - ? { ...langString(newValue) } - : { "@value": `${newValue}` }, - }); - } else { - // This is a named term; attempt to get its I·R·I and - // push it. - try { - // Attempt to resolve the value and push the change. - const tag = storage.get(newValue); - if (!this.#isTagInStorage(tag)) { - // The value did not resolve to a tag in storage. + for (const newValue of newValues) { + // Iterate over additions and state them. + if (LITERAL_TERMS.has(term)) { + // This is a literal term; push the change wrapped in an + // object. + states.push({ + predicate: term, + object: Object(newValue) === newValue + ? { ...langString(newValue) } + : { "@value": `${newValue}` }, + }); + } else { + // This is a named term; attempt to get its I·R·I and + // push it. + try { + // Attempt to resolve the value and push the change. + const tag = storage.get(newValue); + if (!this.#isTagInStorage(tag)) { + // The value did not resolve to a tag in storage. + /* do nothing */ + } else { + // The value resolved; push its I·R·I. + states.push({ + predicate: term, + object: tag.iri, + }); + } + } catch { + // Value resolution failed for some reason; perhaps the + // tag was deleted. /* do nothing */ - } else { - // The value resolved; push its I·R·I. - states.push({ - predicate: term, - object: tag.iri, - }); } - } catch { - // Value resolution failed for some reason; perhaps the - // tag was deleted. - /* do nothing */ } } } - } - if (unstates.length == 0) { - // Nothing was unstated. - delete statements.unstates; - } else { - // Things were stated. - /* do nothing */ - } - if (states.length == 0) { - // Nothing was stated. - delete statements.states; - } else { - // Things were stated. - /* do nothing */ - } - return statements; - })(), - }; - if ( - !Object.hasOwn(activity, "states") && - !Object.hasOwn(activity, "unstates") - ) { - // No meaningful changes were actually persisted. - return null; - } else { - // There were meaningful changes persisted regarding this `Tag`. - return activity; + if (unstates.length == 0) { + // Nothing was unstated. + delete statements.unstates; + } else { + // Things were stated. + /* do nothing */ + } + if (states.length == 0) { + // Nothing was stated. + delete statements.states; + } else { + // Things were stated. + /* do nothing */ + } + return statements; + })(), + }; + if ( + !Object.hasOwn(activity, "states") && + !Object.hasOwn(activity, "unstates") + ) { + // No meaningful changes were actually persisted. + return null; + } else { + // There were meaningful changes persisted regarding this `Tag`. + return activity; + } } } diff --git a/model.test.js b/model.test.js index 7944238..a648d4f 100644 --- a/model.test.js +++ b/model.test.js @@ -849,6 +849,15 @@ describe("TagSystem", () => { const activity = tag.persist(); assertStrictEquals(activity, null); }); + + it("[[Call]] returns undefined for a silent persist", () => { + const broader = new Tag(); + broader.persist(); + const tag = new Tag(); + tag.prefLabel = "etaoin"; + tag.addBroaderTag(broader); + assertStrictEquals(tag.persist(true), undefined); + }); }); describe("::prefLabel", () => {