You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	All: Improved synchronisation process and saving of models so that reducer can deal with full objects
This commit is contained in:
		| @@ -62,11 +62,12 @@ class BaseModel { | |||||||
| 		return temp; | 		return temp; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	static fieldType(name) { | 	static fieldType(name, defaultValue = null) { | ||||||
| 		let fields = this.fields(); | 		let fields = this.fields(); | ||||||
| 		for (let i = 0; i < fields.length; i++) { | 		for (let i = 0; i < fields.length; i++) { | ||||||
| 			if (fields[i].name == name) return fields[i].type; | 			if (fields[i].name == name) return fields[i].type; | ||||||
| 		} | 		} | ||||||
|  | 		if (defaultValue !== null) return defaultValue; | ||||||
| 		throw new Error('Unknown field: ' + name); | 		throw new Error('Unknown field: ' + name); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -238,6 +239,9 @@ class BaseModel { | |||||||
| 			o.updated_time = timeNow; | 			o.updated_time = timeNow; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		// The purpose of user_updated_time is to allow the user to manually set the time of a note (in which case | ||||||
|  | 		// options.autoTimestamp will be `false`). However note that if the item is later changed, this timestamp | ||||||
|  | 		// will be set again to the current time. | ||||||
| 		if (options.autoTimestamp && this.hasField('user_updated_time')) { | 		if (options.autoTimestamp && this.hasField('user_updated_time')) { | ||||||
| 			o.user_updated_time = timeNow; | 			o.user_updated_time = timeNow; | ||||||
| 		} | 		} | ||||||
| @@ -278,6 +282,18 @@ class BaseModel { | |||||||
| 		options = this.modOptions(options); | 		options = this.modOptions(options); | ||||||
| 		options.isNew = this.isNew(o, options); | 		options.isNew = this.isNew(o, options); | ||||||
|  |  | ||||||
|  | 		// Diff saving is an optimisation which takes a new version of the item and an old one, | ||||||
|  | 		// do a diff and save only this diff. IMPORTANT: When using this make sure that both | ||||||
|  | 		// models have been normalised using ItemClass.filter() | ||||||
|  | 		const isDiffSaving = options && options.oldItem && !options.isNew; | ||||||
|  |  | ||||||
|  | 		if (isDiffSaving) { | ||||||
|  | 			const newObject = BaseModel.diffObjects(options.oldItem, o); | ||||||
|  | 			newObject.type_ = o.type_; | ||||||
|  | 			newObject.id = o.id; | ||||||
|  | 			o = newObject; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		o = this.filter(o); | 		o = this.filter(o); | ||||||
|  |  | ||||||
| 		let queries = []; | 		let queries = []; | ||||||
| @@ -298,6 +314,15 @@ class BaseModel { | |||||||
| 			if ('user_updated_time' in saveQuery.modObject) o.user_updated_time = saveQuery.modObject.user_updated_time; | 			if ('user_updated_time' in saveQuery.modObject) o.user_updated_time = saveQuery.modObject.user_updated_time; | ||||||
| 			if ('user_created_time' in saveQuery.modObject) o.user_created_time = saveQuery.modObject.user_created_time; | 			if ('user_created_time' in saveQuery.modObject) o.user_created_time = saveQuery.modObject.user_created_time; | ||||||
| 			o = this.addModelMd(o); | 			o = this.addModelMd(o); | ||||||
|  |  | ||||||
|  | 			if (isDiffSaving) { | ||||||
|  | 				for (let n in options.oldItem) { | ||||||
|  | 					if (!options.oldItem.hasOwnProperty(n)) continue; | ||||||
|  | 					if (n in o) continue; | ||||||
|  | 					o[n] = options.oldItem[n]; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			return this.filter(o); | 			return this.filter(o); | ||||||
| 		}).catch((error) => { | 		}).catch((error) => { | ||||||
| 			Log.error('Cannot save model', error); | 			Log.error('Cannot save model', error); | ||||||
| @@ -328,9 +353,18 @@ class BaseModel { | |||||||
| 		let output = Object.assign({}, model); | 		let output = Object.assign({}, model); | ||||||
| 		for (let n in output) { | 		for (let n in output) { | ||||||
| 			if (!output.hasOwnProperty(n)) continue; | 			if (!output.hasOwnProperty(n)) continue; | ||||||
|  |  | ||||||
| 			// The SQLite database doesn't have booleans so cast everything to int | 			// The SQLite database doesn't have booleans so cast everything to int | ||||||
| 			if (output[n] === true) output[n] = 1; | 			if (output[n] === true) { | ||||||
| 			if (output[n] === false) output[n] = 0; | 				output[n] = 1; | ||||||
|  | 			} else if (output[n] === false) { | ||||||
|  | 				output[n] = 0;  | ||||||
|  | 			} else { | ||||||
|  | 				const t = this.fieldType(n, Database.TYPE_UNKNOWN); | ||||||
|  | 				if (t === Database.TYPE_INT) { | ||||||
|  | 					output[n] = !n ? 0 : parseInt(output[n], 10); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		return output; | 		return output; | ||||||
|   | |||||||
| @@ -308,6 +308,7 @@ class Database { | |||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | Database.TYPE_UNKNOWN = 0; | ||||||
| Database.TYPE_INT = 1; | Database.TYPE_INT = 1; | ||||||
| Database.TYPE_TEXT = 2; | Database.TYPE_TEXT = 2; | ||||||
| Database.TYPE_NUMERIC = 3; | Database.TYPE_NUMERIC = 3; | ||||||
|   | |||||||
| @@ -410,14 +410,18 @@ class Synchronizer { | |||||||
| 					let action = null; | 					let action = null; | ||||||
| 					let reason = ''; | 					let reason = ''; | ||||||
| 					let local = await BaseItem.loadItemByPath(path); | 					let local = await BaseItem.loadItemByPath(path); | ||||||
|  | 					let ItemClass = null; | ||||||
| 					let content = null; | 					let content = null; | ||||||
| 					if (!local) { | 					if (!local) { | ||||||
| 						if (remote.isDeleted !== true) { | 						if (remote.isDeleted !== true) { | ||||||
| 							action = 'createLocal'; | 							action = 'createLocal'; | ||||||
| 							reason = 'remote exists but local does not'; | 							reason = 'remote exists but local does not'; | ||||||
| 							content = await loadContent(); | 							content = await loadContent(); | ||||||
|  | 							ItemClass = content ? BaseItem.itemClass(content) : null; | ||||||
| 						} | 						} | ||||||
| 					} else { | 					} else { | ||||||
|  | 						ItemClass = BaseItem.itemClass(local); | ||||||
|  | 						local = ItemClass.filter(local); | ||||||
| 						if (remote.isDeleted) { | 						if (remote.isDeleted) { | ||||||
| 							action = 'deleteLocal'; | 							action = 'deleteLocal'; | ||||||
| 							reason = 'remote has been deleted'; | 							reason = 'remote has been deleted'; | ||||||
| @@ -440,7 +444,6 @@ class Synchronizer { | |||||||
| 							this.logger().warn('Remote has been deleted between now and the list() call? In that case it will be handled during the next sync: ' + path); | 							this.logger().warn('Remote has been deleted between now and the list() call? In that case it will be handled during the next sync: ' + path); | ||||||
| 							continue; | 							continue; | ||||||
| 						} | 						} | ||||||
| 						let ItemClass = BaseItem.itemClass(content); |  | ||||||
| 						content = ItemClass.filter(content); | 						content = ItemClass.filter(content); | ||||||
|  |  | ||||||
| 						// 2017-12-03: This was added because the new user_updated_time and user_created_time properties were added | 						// 2017-12-03: This was added because the new user_updated_time and user_created_time properties were added | ||||||
| @@ -451,34 +454,20 @@ class Synchronizer { | |||||||
| 						if (!content.user_updated_time) content.user_updated_time = content.updated_time; | 						if (!content.user_updated_time) content.user_updated_time = content.updated_time; | ||||||
| 						if (!content.user_created_time) content.user_created_time = content.created_time; | 						if (!content.user_created_time) content.user_created_time = content.created_time; | ||||||
|  |  | ||||||
| 						let newContent = null; |  | ||||||
|  |  | ||||||
| 						if (action === 'createLocal') { |  | ||||||
| 							newContent = Object.assign({}, content);							 |  | ||||||
| 						} else if (action === 'updateLocal') { |  | ||||||
| 							newContent = BaseModel.diffObjects(local, content); |  | ||||||
| 							newContent.type_ = content.type_; |  | ||||||
| 							newContent.id = content.id; |  | ||||||
| 						} else { |  | ||||||
| 							throw new Error('Unknown action: ' + action); |  | ||||||
| 						} |  | ||||||
|  |  | ||||||
| 						let options = { | 						let options = { | ||||||
| 							autoTimestamp: false, | 							autoTimestamp: false, | ||||||
| 							nextQueries: BaseItem.updateSyncTimeQueries(syncTargetId, newContent, time.unixMs()), | 							nextQueries: BaseItem.updateSyncTimeQueries(syncTargetId, content, time.unixMs()), | ||||||
| 						}; | 						}; | ||||||
| 						if (action == 'createLocal') options.isNew = true; | 						if (action == 'createLocal') options.isNew = true; | ||||||
|  | 						if (action == 'updateLocal') options.oldItem = local; | ||||||
|  |  | ||||||
| 						if (newContent.type_ == BaseModel.TYPE_RESOURCE && action == 'createLocal') { | 						if (content.type_ == BaseModel.TYPE_RESOURCE && action == 'createLocal') { | ||||||
| 							let localResourceContentPath = Resource.fullPath(newContent); | 							let localResourceContentPath = Resource.fullPath(content); | ||||||
| 							let remoteResourceContentPath = this.resourceDirName_ + '/' + newContent.id; | 							let remoteResourceContentPath = this.resourceDirName_ + '/' + content.id; | ||||||
| 							await this.api().get(remoteResourceContentPath, { path: localResourceContentPath, target: 'file' }); | 							await this.api().get(remoteResourceContentPath, { path: localResourceContentPath, target: 'file' }); | ||||||
| 						} | 						} | ||||||
|  |  | ||||||
| 						// if (!newContent.user_updated_time) newContent.user_updated_time = newContent.updated_time; | 						await ItemClass.save(content, options); | ||||||
| 						// if (!newContent.user_created_time) newContent.user_created_time = newContent.created_time; |  | ||||||
|  |  | ||||||
| 						await ItemClass.save(newContent, options); |  | ||||||
|  |  | ||||||
| 					} else if (action == 'deleteLocal') { | 					} else if (action == 'deleteLocal') { | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user