handle escaping and honor root pointer

This commit is contained in:
Matt Hill
2022-09-30 22:31:03 -06:00
parent 00564ca1ca
commit 1eba576ac1
2 changed files with 31 additions and 10 deletions

View File

@@ -25,12 +25,12 @@ export type Operation<T> =
export function getValueByPointer<T extends Record<string, T>>(
data: T,
pointer: string,
path: string,
): any {
if (pointer === '/') return data
if (!path) return data
try {
return jsonPathToKeyArray(pointer).reduce((acc, next) => acc[next], data)
return arrayFromPath(path).reduce((acc, next) => acc[next], data)
} catch (e) {
return undefined
}
@@ -40,11 +40,31 @@ export function applyOperation<T>(
doc: DBCache<Record<string, any>>,
{ path, op, value }: Operation<T> & { value?: T },
) {
doc.data = recursiveApply(doc.data, jsonPathToKeyArray(path), op, value)
doc.data = recursiveApply(doc.data, arrayFromPath(path), op, value)
}
export function jsonPathToKeyArray(path: string): string[] {
return path.split('/').slice(1)
export function arrayFromPath(path: string): string[] {
return path
.split('/')
.slice(1)
.map(p =>
p.replace(new RegExp('~1', 'g'), '/').replace(new RegExp('~0', 'g'), '~'),
)
}
export function pathFromArray(args: Array<string | number>): string {
if (!args.length) return ''
return (
'/' +
args
.map(a =>
String(a)
.replace(new RegExp('~', 'g'), '~0')
.replace(new RegExp('/', 'g'), '~1'),
)
.join('/')
)
}
function recursiveApply<T extends Record<string, any> | any[]>(

View File

@@ -10,8 +10,9 @@ import {
} from 'rxjs'
import {
applyOperation,
arrayFromPath,
getValueByPointer,
jsonPathToKeyArray,
pathFromArray,
} from './json-patch-lib'
export class PatchDB<T extends { [key: string]: any }> {
@@ -133,12 +134,12 @@ export class PatchDB<T extends { [key: string]: any }> {
filter(({ sequence }) => !!sequence),
take(1),
switchMap(({ data }) => {
const path = args.length ? `/${args.join('/')}` : ''
const path = pathFromArray(args)
if (!this.watchedNodes[path]) {
const value = getValueByPointer(data, path)
this.watchedNodes[path] = {
subject: new BehaviorSubject(value),
pathArr: jsonPathToKeyArray(path),
pathArr: arrayFromPath(path),
}
}
return this.watchedNodes[path].subject
@@ -183,7 +184,7 @@ export class PatchDB<T extends { [key: string]: any }> {
}
private updateWatchedNodes(revisionPath: string, data: T): void {
const r = jsonPathToKeyArray(revisionPath)
const r = arrayFromPath(revisionPath)
Object.entries(this.watchedNodes).forEach(([path, { pathArr }]) => {
if (startsWith(pathArr, r) || startsWith(r, pathArr)) {
this.updateWatchedNode(path, data)