mirror of
				https://github.com/flynx/pWiki.git
				synced 2025-10-31 11:00:08 +00:00 
			
		
		
		
	experimenting with new index on paths/names...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
		
							parent
							
								
									2129c967e5
								
							
						
					
					
						commit
						66e3c622b2
					
				| @ -24,10 +24,12 @@ var pwpath = require('../path') | |||||||
| // 		- group operations:
 | // 		- group operations:
 | ||||||
| // 				- reset (cache)			   	- DONE
 | // 				- reset (cache)			   	- DONE
 | ||||||
| // 				- custom				   	- DONE
 | // 				- custom				   	- DONE
 | ||||||
|  | // XXX move .paths()/.names() to this...
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| //
 | //
 | ||||||
|  | //	makeIndex(<name>[, <options>])
 | ||||||
| //	makeIndex(<name>, <generate>[, <options>])
 | //	makeIndex(<name>, <generate>[, <options>])
 | ||||||
| //		-> <index-handler> 
 | //		-> <index-handler> 
 | ||||||
| //
 | //
 | ||||||
| @ -64,6 +66,10 @@ var pwpath = require('../path') | |||||||
| // 	.__<name>_merge__(<data>)
 | // 	.__<name>_merge__(<data>)
 | ||||||
| // 		-> <data>
 | // 		-> <data>
 | ||||||
| //
 | //
 | ||||||
|  | // 	Test if cache is valid...
 | ||||||
|  | // 	.__<name>_test__(<timestamp>)
 | ||||||
|  | // 		-> <bool>
 | ||||||
|  | //
 | ||||||
| // 	Handle custom action...
 | // 	Handle custom action...
 | ||||||
| // 	.__<name>_<action-name>__(<data>. ...)
 | // 	.__<name>_<action-name>__(<data>. ...)
 | ||||||
| // 		-> <data>
 | // 		-> <data>
 | ||||||
| @ -75,6 +81,9 @@ var pwpath = require('../path') | |||||||
| // 	Cached data...
 | // 	Cached data...
 | ||||||
| // 	.__<name>_cache / .<name>
 | // 	.__<name>_cache / .<name>
 | ||||||
| //
 | //
 | ||||||
|  | // 	Modification time...
 | ||||||
|  | // 	.__<name>_modified
 | ||||||
|  | //
 | ||||||
| //
 | //
 | ||||||
| // Options format:
 | // Options format:
 | ||||||
| // 	{
 | // 	{
 | ||||||
| @ -100,9 +109,17 @@ var pwpath = require('../path') | |||||||
| // 	}
 | // 	}
 | ||||||
| //
 | //
 | ||||||
| //
 | //
 | ||||||
|  | // XXX do we separate internal methods and actions???
 | ||||||
|  | // 		i.e. __<name>_merge__(..) / __<name>_test__(..) and the rest...
 | ||||||
| var makeIndex =  | var makeIndex =  | ||||||
| module.makeIndex = | module.makeIndex = | ||||||
| function(name, generate, options={}){ | function(name, generate, options={}){ | ||||||
|  | 	// makeIndex(<name>, <options>)
 | ||||||
|  | 	if(generate  | ||||||
|  | 			&& typeof(generate) != 'function'){ | ||||||
|  | 		options = generate  | ||||||
|  | 		generate = options.generate } | ||||||
|  | 
 | ||||||
| 	// attr names...
 | 	// attr names...
 | ||||||
| 	var cache =  | 	var cache =  | ||||||
| 		typeof(options.attr) == 'string' ? | 		typeof(options.attr) == 'string' ? | ||||||
| @ -112,14 +129,18 @@ function(name, generate, options={}){ | |||||||
| 			name | 			name | ||||||
| 		: `__${name}_cache` | 		: `__${name}_cache` | ||||||
| 	var merge = `__${name}_merge__` | 	var merge = `__${name}_merge__` | ||||||
|  | 	var test = `__${name}_test__` | ||||||
| 	var special = `__${name}__` | 	var special = `__${name}__` | ||||||
|  | 	var modified = `__${name}_modified` | ||||||
| 
 | 
 | ||||||
| 	// make local cache...
 | 	// make local cache...
 | ||||||
| 	var _make = function(){ | 	var _make = function(){ | ||||||
| 		var res = this[special] != null ? | 		var res =  | ||||||
| 			this[special]() | 			this[special] != null ? | ||||||
| 			: generate.call(this)  | 				this[special]() | ||||||
| 		meth.modified = Date.now() | 				: (generate  | ||||||
|  | 					&& generate.call(this)) | ||||||
|  | 		this[modified] = Date.now() | ||||||
| 		return res } | 		return res } | ||||||
| 	// unwrap a promised value into cache...
 | 	// unwrap a promised value into cache...
 | ||||||
| 	var _await = function(obj, val){ | 	var _await = function(obj, val){ | ||||||
| @ -140,14 +161,19 @@ function(name, generate, options={}){ | |||||||
| 			// action: clear...
 | 			// action: clear...
 | ||||||
| 			if(action == 'clear'){ | 			if(action == 'clear'){ | ||||||
| 				return } | 				return } | ||||||
| 			// check dependencies (timestamps)...
 | 			// validate cache...
 | ||||||
| 			if(cache in this  | 			if(cache in this){ | ||||||
| 					&& meth.options.depends){ | 				var cur = this[modified] | ||||||
| 				var cur = meth.modified | 				// user test...
 | ||||||
| 				for(var dep of meth.options.depends){ | 				if(test in this  | ||||||
| 					if(this[dep].modified > cur){ | 						&& !this[test](cur)){ | ||||||
| 						delete this[cache] | 					delete this[cache] | ||||||
| 						break } } } | 				// check dependencies...
 | ||||||
|  | 				} else if(meth.options.depends){ | ||||||
|  | 					for(var dep of meth.options.depends){ | ||||||
|  | 						if(this[`__${this[dep].attr}_modified`] > cur){ | ||||||
|  | 							delete this[cache] | ||||||
|  | 							break } } } } | ||||||
| 			// action: other...
 | 			// action: other...
 | ||||||
| 			if(action != 'get'  | 			if(action != 'get'  | ||||||
| 					&& action != 'reset'){ | 					&& action != 'reset'){ | ||||||
| @ -165,7 +191,7 @@ function(name, generate, options={}){ | |||||||
| 						options[action].call(this, cur, ...args) | 						options[action].call(this, cur, ...args) | ||||||
| 					: cur)  | 					: cur)  | ||||||
| 				res !== cur | 				res !== cur | ||||||
| 					&& (meth.modified = Date.now()) | 					&& (this[modified] = Date.now()) | ||||||
| 				return res } | 				return res } | ||||||
| 			// action: get/local...
 | 			// action: get/local...
 | ||||||
| 			return _await(this, | 			return _await(this, | ||||||
| @ -282,6 +308,14 @@ IndexManagerMixin({ | |||||||
| 		], }), | 		], }), | ||||||
| 	get sum(){ | 	get sum(){ | ||||||
| 		return this.__sum() }, | 		return this.__sum() }, | ||||||
|  | 
 | ||||||
|  | 	__merged__: function(){ | ||||||
|  | 		return 777 }, | ||||||
|  | 	__merged_merge__: async function(data){ | ||||||
|  | 		return (await data) + 777 }, | ||||||
|  | 	__merged: makeIndex('merged'), | ||||||
|  | 	get merged(){ | ||||||
|  | 		return this.__merged() }, | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -354,6 +388,7 @@ function(name, get, update, ...args){ | |||||||
| // 				-> <path-list>
 | // 				-> <path-list>
 | ||||||
| // 			.names()
 | // 			.names()
 | ||||||
| // 				-> <name-index>
 | // 				-> <name-index>
 | ||||||
|  | //
 | ||||||
| // 			.exists(<path>)
 | // 			.exists(<path>)
 | ||||||
| // 				-> <real-path>
 | // 				-> <real-path>
 | ||||||
| // 				-> false
 | // 				-> false
 | ||||||
| @ -427,10 +462,76 @@ module.BaseStore = { | |||||||
| 		this.__data = value }, | 		this.__data = value }, | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | 	// XXX INDEX...
 | ||||||
|  | 	__xpaths__: async function(){ | ||||||
|  | 		return Object.keys(this.data) }, | ||||||
|  | 	// XXX unique???
 | ||||||
|  | 	__xpaths_merge__: async function(data){ | ||||||
|  | 		return (await data) | ||||||
|  | 			.concat((this.next  | ||||||
|  | 					&& 'xpaths' in this.next) ? | ||||||
|  | 				await this.next.xpaths | ||||||
|  | 				: []) }, | ||||||
|  | 	__xpaths_test__: function(t){ | ||||||
|  | 		var changed =  | ||||||
|  | 			!!this.__xpaths_next_exists != !!this.next | ||||||
|  | 				|| (!!this.next  | ||||||
|  | 					&& this.next.__xpaths_modified > t) | ||||||
|  | 		this.__xpaths_next_exists = !this.next | ||||||
|  | 		return changed }, | ||||||
|  | 	__xpaths: makeIndex('xpaths', { | ||||||
|  | 		update: async function(data, path){ | ||||||
|  | 			data = await data | ||||||
|  | 			// XXX normalize???
 | ||||||
|  | 			data.includes(path) | ||||||
|  | 				|| data.push(path) | ||||||
|  | 			return data },  | ||||||
|  | 		remove: async function(data, path){ | ||||||
|  | 			data = await data | ||||||
|  | 			// XXX normalize???
 | ||||||
|  | 			data.includes(path) | ||||||
|  | 				&& data.splice(data.indexOf(path), 1) | ||||||
|  | 			return data }, }), | ||||||
|  | 	// XXX should this clone the data???
 | ||||||
|  | 	get xpaths(){ | ||||||
|  | 		return this.__xpaths() }, | ||||||
|  | 
 | ||||||
|  | 	// NOTE: this is build from .paths so there is no need to define a 
 | ||||||
|  | 	// 		way to merge...
 | ||||||
|  | 	__xnames: makeIndex('xnames',  | ||||||
|  | 		function(){ | ||||||
|  | 			return this.xpaths | ||||||
|  | 				.iter() | ||||||
|  | 				.reduce(function(res, path){ | ||||||
|  | 					var n = pwpath.basename(path) | ||||||
|  | 					if(!n.includes('*')){ | ||||||
|  | 						(res[n] = res[n] ?? []).push(path) } | ||||||
|  | 					return res }, {}) }, { | ||||||
|  | 		update: async function(data, path){ | ||||||
|  | 			data = await data | ||||||
|  | 			// XXX normalize???
 | ||||||
|  | 			var n = pwpath.basename(path) | ||||||
|  | 			if(!n.includes('*')  | ||||||
|  | 					&& !data[n].includes(path)){ | ||||||
|  | 				(data[n] = data[n] ?? []).push(path) } | ||||||
|  | 			return data }, | ||||||
|  | 		remove: async function(data, path){ | ||||||
|  | 			data = await data | ||||||
|  | 			// XXX normalize???
 | ||||||
|  | 			var n = pwpath.basename(path) | ||||||
|  | 			data[n].includes(path) | ||||||
|  | 				&& data[n].splice(data[n].indexOf(path), 1) | ||||||
|  | 			data[n].length == 0 | ||||||
|  | 				&& (delete data[n]) | ||||||
|  | 			return data }, }), | ||||||
|  | 	// XXX should this clone the data???
 | ||||||
|  | 	get xnames(){ | ||||||
|  | 		return this.__xnames() }, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 	// XXX might be a good idea to cache this...
 | 	// XXX might be a good idea to cache this...
 | ||||||
| 	__paths__: async function(){ | 	__paths__: async function(){ | ||||||
| 		return Object.keys(this.data) }, | 		return Object.keys(this.data) }, | ||||||
| 
 |  | ||||||
| 	// local paths...
 | 	// local paths...
 | ||||||
| 	__paths: cached('paths', async function(){ | 	__paths: cached('paths', async function(){ | ||||||
| 		return this.__paths__() }), | 		return this.__paths__() }), | ||||||
| @ -442,6 +543,7 @@ module.BaseStore = { | |||||||
| 			.concat((!local && (this.next || {}).paths) ?  | 			.concat((!local && (this.next || {}).paths) ?  | ||||||
| 				this.next.paths()  | 				this.next.paths()  | ||||||
| 				: []) }, | 				: []) }, | ||||||
|  | 
 | ||||||
| 	// XXX BUG: after caching this will ignore the local argument....
 | 	// XXX BUG: after caching this will ignore the local argument....
 | ||||||
| 	names: cached('names', async function(local=false){ | 	names: cached('names', async function(local=false){ | ||||||
| 		return this.paths(local) | 		return this.paths(local) | ||||||
| @ -870,6 +972,7 @@ module.BaseStore = { | |||||||
| 			: res }, | 			: res }, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | IndexManagerMixin(BaseStore) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 | ||||||
| @ -952,6 +1055,38 @@ module.MetaStore = { | |||||||
| 	// 		store adapters that can overload the level1 API to implement 
 | 	// 		store adapters that can overload the level1 API to implement 
 | ||||||
| 	// 		their own stuff...
 | 	// 		their own stuff...
 | ||||||
| 
 | 
 | ||||||
|  | 	// XXX INDEX...
 | ||||||
|  | 	__xpaths_merge__: async function(data){ | ||||||
|  | 		var that = this | ||||||
|  | 		var stores = await Promise.iter( | ||||||
|  | 				Object.entries(this.substores ?? {}) | ||||||
|  | 					.map(function([path, store]){ | ||||||
|  | 						return store.paths() | ||||||
|  | 								.iter() | ||||||
|  | 								.map(function(s){ | ||||||
|  | 									return pwpath.join(path, s) }) })) | ||||||
|  | 			.flat() | ||||||
|  | 		return object.parentCall(MetaStore.__xpaths_merge__, this, ...arguments) | ||||||
|  | 			.iter() | ||||||
|  | 			.concat(stores) }, | ||||||
|  | 	// XXX
 | ||||||
|  | 	__xpaths_test__: function(t){ | ||||||
|  | 		if(!this.substores){ | ||||||
|  | 			return true } | ||||||
|  | 		// match substore list...
 | ||||||
|  | 		var cur = Object.keys(this.substores) | ||||||
|  | 		var prev = this.__xpaths_substores | ||||||
|  | 		if(!prev){ | ||||||
|  | 			this.__xpaths_substores = cur | ||||||
|  | 		} else if(prev.length != cur.length | ||||||
|  | 				|| (new Set([...cur, ...prev])).length != cur.length){ | ||||||
|  | 			return false } | ||||||
|  | 		// check timestamps...
 | ||||||
|  | 		for(var store of Object.values(this.substores ?? {})){ | ||||||
|  | 			if(store.__xpaths_modified > t){ | ||||||
|  | 				return false } } | ||||||
|  | 		return object.parentCall(MetaStore.__xpaths_test__, this, ...arguments) }, | ||||||
|  | 
 | ||||||
| 	paths: async function(){ | 	paths: async function(){ | ||||||
| 		var that = this | 		var that = this | ||||||
| 		var stores = await Promise.iter( | 		var stores = await Promise.iter( | ||||||
|  | |||||||
| @ -564,6 +564,20 @@ module.FileStoreRO = { | |||||||
| 		return pwpath.join(...path) | 		return pwpath.join(...path) | ||||||
| 			.replace(/\$PWIKI/, this.__pwiki_path__) }, | 			.replace(/\$PWIKI/, this.__pwiki_path__) }, | ||||||
| 
 | 
 | ||||||
|  | 	// XXX INDEX...
 | ||||||
|  | 	__xpaths__: async function(){ | ||||||
|  | 		var that = this | ||||||
|  | 		return new Promise(function(resolve, reject){ | ||||||
|  | 			glob(pwpath.join(that.__path__, '**/*')) | ||||||
|  | 				.on('end', function(paths){ | ||||||
|  | 					Promise.all(paths | ||||||
|  | 							.map(async function(path){ | ||||||
|  | 								return await module.exists(path) ? | ||||||
|  | 									decode(path) | ||||||
|  | 										.slice(that.__path__.length) | ||||||
|  | 									: [] })) | ||||||
|  | 						.then(function(paths){ | ||||||
|  | 							resolve(paths.flat()) }) }) }) }, | ||||||
| 	// XXX do we remove the extension???
 | 	// XXX do we remove the extension???
 | ||||||
| 	// XXX cache???
 | 	// XXX cache???
 | ||||||
| 	__paths__: async function(){ | 	__paths__: async function(){ | ||||||
|  | |||||||
| @ -33,6 +33,10 @@ module.IndexedDBStore = { | |||||||
| 		return this.__data  | 		return this.__data  | ||||||
| 			?? (this.__data = idb.createStore(this.__db__, this.__store__)) }, | 			?? (this.__data = idb.createStore(this.__db__, this.__store__)) }, | ||||||
| 	 | 	 | ||||||
|  | 	// XXX INDEX...
 | ||||||
|  | 	__xpaths__: function(){ | ||||||
|  | 		return idb.keys(this.data) }, | ||||||
|  | 
 | ||||||
| 	__paths__: function(){ | 	__paths__: function(){ | ||||||
| 		return idb.keys(this.data) }, | 		return idb.keys(this.data) }, | ||||||
| 	__exists__: function(path){ | 	__exists__: function(path){ | ||||||
|  | |||||||
| @ -29,6 +29,16 @@ module.localStorageStore = { | |||||||
| 			localStorage | 			localStorage | ||||||
| 			: undefined, | 			: undefined, | ||||||
| 	 | 	 | ||||||
|  | 	// XXX INDEX...
 | ||||||
|  | 	__xpaths__: function(){ | ||||||
|  | 		var that = this | ||||||
|  | 		return Object.keys(this.data) | ||||||
|  | 			.map(function(k){  | ||||||
|  | 				return k.startsWith(that.__prefix__) ? | ||||||
|  | 					k.slice((that.__prefix__ ?? '').length)  | ||||||
|  | 					: [] })  | ||||||
|  | 			.flat() }, | ||||||
|  | 
 | ||||||
| 	__paths__: function(){ | 	__paths__: function(){ | ||||||
| 		var that = this | 		var that = this | ||||||
| 		return Object.keys(this.data) | 		return Object.keys(this.data) | ||||||
|  | |||||||
| @ -34,6 +34,14 @@ module.PouchDBStore = { | |||||||
| 	set data(value){ | 	set data(value){ | ||||||
| 		this.__data = value }, | 		this.__data = value }, | ||||||
| 
 | 
 | ||||||
|  | 	// XXX INDEX...
 | ||||||
|  | 	__xpaths__: async function(){ | ||||||
|  | 		var that = this | ||||||
|  | 		// XXX not sure if this is a good idea...
 | ||||||
|  | 		return (await this.data.allDocs()).rows | ||||||
|  | 			.map(function(e){  | ||||||
|  | 				return e.id.slice(that.__key_prefix__.length) }) }, | ||||||
|  | 
 | ||||||
| 	// XXX cache???
 | 	// XXX cache???
 | ||||||
| 	__paths__: async function(){ | 	__paths__: async function(){ | ||||||
| 		var that = this | 		var that = this | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user