You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Chore: Migrate SQL queries in preparation for web support (#10670)
This commit is contained in:
		| @@ -346,7 +346,7 @@ class BaseModel { | ||||
| 		if (!options.fields) options.fields = '*'; | ||||
|  | ||||
| 		let sql = `SELECT ${this.db().escapeFields(options.fields)} FROM \`${this.tableName()}\``; | ||||
| 		sql += ` WHERE id IN ("${ids.join('","')}")`; | ||||
| 		sql += ` WHERE id IN ('${ids.join('\',\'')}')`; | ||||
| 		const q = this.applySqlOptions(options, sql); | ||||
| 		return this.modelSelectAll(q.sql); | ||||
| 	} | ||||
| @@ -745,7 +745,7 @@ class BaseModel { | ||||
|  | ||||
| 		options = this.modOptions(options); | ||||
| 		const idFieldName = options.idFieldName ? options.idFieldName : 'id'; | ||||
| 		const sql = `DELETE FROM ${this.tableName()} WHERE ${idFieldName} IN ("${ids.join('","')}")`; | ||||
| 		const sql = `DELETE FROM ${this.tableName()} WHERE ${idFieldName} IN ('${ids.join('\',\'')}')`; | ||||
| 		await this.db().exec(sql); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -312,7 +312,7 @@ export default class JoplinDatabase extends Database { | ||||
| 			throw new Error(`\`notes_fts\` (${countFieldsNotesFts} fields) must have the same number of fields as \`items_fts\` (${countFieldsItemsFts} fields) for the search engine BM25 algorithm to work`); | ||||
| 		} | ||||
|  | ||||
| 		const tableRows = await this.selectAll('SELECT name FROM sqlite_master WHERE type="table"'); | ||||
| 		const tableRows = await this.selectAll('SELECT name FROM sqlite_master WHERE type=\'table\''); | ||||
|  | ||||
| 		for (let i = 0; i < tableRows.length; i++) { | ||||
| 			const tableName = tableRows[i].name; | ||||
| @@ -416,7 +416,7 @@ export default class JoplinDatabase extends Database { | ||||
|  | ||||
| 			if (targetVersion === 4) { | ||||
| 				queries.push('INSERT INTO settings (`key`, `value`) VALUES (\'sync.3.context\', (SELECT `value` FROM settings WHERE `key` = \'sync.context\'))'); | ||||
| 				queries.push('DELETE FROM settings WHERE `key` = "sync.context"'); | ||||
| 				queries.push('DELETE FROM settings WHERE `key` = \'sync.context\''); | ||||
| 			} | ||||
|  | ||||
| 			if (targetVersion === 5) { | ||||
|   | ||||
| @@ -247,7 +247,7 @@ export default class BaseItem extends BaseModel { | ||||
| 		let output: any[] = []; | ||||
| 		for (let i = 0; i < classes.length; i++) { | ||||
| 			const ItemClass = this.getClass(classes[i]); | ||||
| 			const sql = `SELECT * FROM ${ItemClass.tableName()} WHERE id IN ("${ids.join('","')}")`; | ||||
| 			const sql = `SELECT * FROM ${ItemClass.tableName()} WHERE id IN ('${ids.join('\',\'')}')`; | ||||
| 			const models = await ItemClass.modelSelectAll(sql); | ||||
| 			output = output.concat(models); | ||||
| 		} | ||||
| @@ -261,7 +261,7 @@ export default class BaseItem extends BaseModel { | ||||
| 		const fields = options && options.fields ? options.fields : []; | ||||
| 		const ItemClass = this.getClassByItemType(itemType); | ||||
| 		const fieldsSql = fields.length ? this.db().escapeFields(fields) : '*'; | ||||
| 		const sql = `SELECT ${fieldsSql} FROM ${ItemClass.tableName()} WHERE id IN ("${ids.join('","')}")`; | ||||
| 		const sql = `SELECT ${fieldsSql} FROM ${ItemClass.tableName()} WHERE id IN ('${ids.join('\',\'')}')`; | ||||
| 		return ItemClass.modelSelectAll(sql); | ||||
| 	} | ||||
|  | ||||
| @@ -300,7 +300,7 @@ export default class BaseItem extends BaseModel { | ||||
| 		// since no other client have (or should have) them. | ||||
| 		let conflictNoteIds: string[] = []; | ||||
| 		if (this.modelType() === BaseModel.TYPE_NOTE) { | ||||
| 			const conflictNotes = await this.db().selectAll(`SELECT id FROM notes WHERE id IN ("${ids.join('","')}") AND is_conflict = 1`); | ||||
| 			const conflictNotes = await this.db().selectAll(`SELECT id FROM notes WHERE id IN ('${ids.join('\',\'')}') AND is_conflict = 1`); | ||||
| 			conflictNoteIds = conflictNotes.map((n: NoteEntity) => { | ||||
| 				return n.id; | ||||
| 			}); | ||||
| @@ -654,7 +654,7 @@ export default class BaseItem extends BaseModel { | ||||
| 				whereSql = [`(encryption_applied = 1 OR (${blobDownloadedButEncryptedSql})`]; | ||||
| 			} | ||||
|  | ||||
| 			if (exclusions.length) whereSql.push(`id NOT IN ("${exclusions.join('","')}")`); | ||||
| 			if (exclusions.length) whereSql.push(`id NOT IN ('${exclusions.join('\',\'')}')`); | ||||
|  | ||||
| 			const sql = sprintf( | ||||
| 				` | ||||
| @@ -936,7 +936,7 @@ export default class BaseItem extends BaseModel { | ||||
| 			}); | ||||
| 			if (!ids.length) continue; | ||||
|  | ||||
| 			await this.db().exec(`UPDATE sync_items SET force_sync = 1 WHERE item_id IN ("${ids.join('","')}")`); | ||||
| 			await this.db().exec(`UPDATE sync_items SET force_sync = 1 WHERE item_id IN ('${ids.join('\',\'')}')`); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -247,7 +247,7 @@ export default class Folder extends BaseItem { | ||||
| 	// The remaining folders, that don't contain any notes are sorted by their own user_updated_time | ||||
| 	public static async orderByLastModified(folders: FolderEntity[], dir = 'DESC') { | ||||
| 		dir = dir.toUpperCase(); | ||||
| 		const sql = 'select parent_id, max(user_updated_time) content_updated_time from notes where parent_id != "" group by parent_id'; | ||||
| 		const sql = 'select parent_id, max(user_updated_time) content_updated_time from notes where parent_id != \'\' group by parent_id'; | ||||
| 		const rows = await this.db().selectAll(sql); | ||||
|  | ||||
| 		const folderIdToTime: Record<string, number> = {}; | ||||
| @@ -388,7 +388,7 @@ export default class Folder extends BaseItem { | ||||
| 	} | ||||
|  | ||||
| 	public static async rootSharedFolders(): Promise<FolderEntity[]> { | ||||
| 		return this.db().selectAll('SELECT id, share_id FROM folders WHERE parent_id = "" AND share_id != ""'); | ||||
| 		return this.db().selectAll('SELECT id, share_id FROM folders WHERE parent_id = \'\' AND share_id != \'\''); | ||||
| 	} | ||||
|  | ||||
| 	public static async rootShareFoldersByKeyId(keyId: string): Promise<FolderEntity[]> { | ||||
| @@ -431,9 +431,9 @@ export default class Folder extends BaseItem { | ||||
| 		// if they've been moved out of a shared folder. | ||||
| 		// await this.unshareItems(ModelType.Folder, sharedFolderIds); | ||||
|  | ||||
| 		const sql = ['SELECT id, parent_id FROM folders WHERE share_id != ""']; | ||||
| 		const sql = ['SELECT id, parent_id FROM folders WHERE share_id != \'\'']; | ||||
| 		if (sharedFolderIds.length) { | ||||
| 			sql.push(` AND id NOT IN ("${sharedFolderIds.join('","')}")`); | ||||
| 			sql.push(` AND id NOT IN ('${sharedFolderIds.join('\',\'')}')`); | ||||
| 		} | ||||
|  | ||||
| 		const foldersToUnshare: FolderEntity[] = await this.db().selectAll(sql.join(' ')); | ||||
| @@ -650,7 +650,7 @@ export default class Folder extends BaseItem { | ||||
|  | ||||
| 			const query = activeShareIds.length ? ` | ||||
| 				SELECT ${this.db().escapeFields(fields)} FROM ${tableName} | ||||
| 				WHERE share_id != "" AND share_id NOT IN ("${activeShareIds.join('","')}") | ||||
| 				WHERE share_id != '' AND share_id NOT IN ('${activeShareIds.join('\',\'')}') | ||||
| 			` : ` | ||||
| 				SELECT ${this.db().escapeFields(fields)} FROM ${tableName} | ||||
| 				WHERE share_id != '' | ||||
|   | ||||
| @@ -896,7 +896,7 @@ export default class Note extends BaseItem { | ||||
| 				const sql = ` | ||||
| 					UPDATE notes | ||||
| 					SET	${updateSql.join(', ')}						 | ||||
| 					WHERE id IN ("${processIds.join('","')}") | ||||
| 					WHERE id IN ('${processIds.join('\',\'')}') | ||||
| 				`; | ||||
|  | ||||
| 				await this.db().exec({ sql, params }); | ||||
|   | ||||
| @@ -91,7 +91,7 @@ export default class NoteResource extends BaseModel { | ||||
| 			FROM note_resources | ||||
| 			LEFT JOIN notes | ||||
| 			ON notes.id = note_resources.note_id | ||||
| 			WHERE resource_id IN ("${resourceIds.join('", "')}") AND is_associated = 1 | ||||
| 			WHERE resource_id IN ('${resourceIds.join('\', \'')}') AND is_associated = 1 | ||||
| 		`); | ||||
|  | ||||
| 		const output: Record<string, NoteEntity[]> = {}; | ||||
|   | ||||
| @@ -12,7 +12,7 @@ export default class NoteTag extends BaseItem { | ||||
|  | ||||
| 	public static async byNoteIds(noteIds: string[]) { | ||||
| 		if (!noteIds.length) return []; | ||||
| 		return this.modelSelectAll(`SELECT * FROM note_tags WHERE note_id IN ("${noteIds.join('","')}")`); | ||||
| 		return this.modelSelectAll(`SELECT * FROM note_tags WHERE note_id IN ('${noteIds.join('\',\'')}')`); | ||||
| 	} | ||||
|  | ||||
| 	public static async tagIdsByNoteId(noteId: string) { | ||||
|   | ||||
| @@ -76,7 +76,7 @@ export default class Resource extends BaseItem { | ||||
| 	// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied | ||||
| 	public static fetchStatuses(resourceIds: string[]): Promise<any[]> { | ||||
| 		if (!resourceIds.length) return Promise.resolve([]); | ||||
| 		return this.db().selectAll(`SELECT resource_id, fetch_status FROM resource_local_states WHERE resource_id IN ("${resourceIds.join('","')}")`); | ||||
| 		return this.db().selectAll(`SELECT resource_id, fetch_status FROM resource_local_states WHERE resource_id IN ('${resourceIds.join('\',\'')}')`); | ||||
| 	} | ||||
|  | ||||
| 	public static sharedResourceIds(): Promise<string[]> { | ||||
| @@ -107,7 +107,7 @@ export default class Resource extends BaseItem { | ||||
| 	} | ||||
|  | ||||
| 	public static async resetFetchErrorStatus(resourceId: string) { | ||||
| 		await this.db().exec('UPDATE resource_local_states SET fetch_status = ?, fetch_error = "" WHERE resource_id = ?', [Resource.FETCH_STATUS_IDLE, resourceId]); | ||||
| 		await this.db().exec('UPDATE resource_local_states SET fetch_status = ?, fetch_error = \'\' WHERE resource_id = ?', [Resource.FETCH_STATUS_IDLE, resourceId]); | ||||
| 		await this.resetOcrStatus(resourceId); | ||||
| 	} | ||||
|  | ||||
| @@ -368,7 +368,7 @@ export default class Resource extends BaseItem { | ||||
| 	public static async downloadedButEncryptedBlobCount(excludedIds: string[] = null) { | ||||
| 		let excludedSql = ''; | ||||
| 		if (excludedIds && excludedIds.length) { | ||||
| 			excludedSql = `AND resource_id NOT IN ("${excludedIds.join('","')}")`; | ||||
| 			excludedSql = `AND resource_id NOT IN ('${excludedIds.join('\',\'')}')`; | ||||
| 		} | ||||
|  | ||||
| 		const r = await this.db().selectOne(` | ||||
| @@ -520,7 +520,7 @@ export default class Resource extends BaseItem { | ||||
| 				WHERE | ||||
| 					ocr_status = ? AND | ||||
| 					encryption_applied = 0 AND | ||||
| 					mime IN ("${supportedMimeTypes.join('","')}") | ||||
| 					mime IN ('${supportedMimeTypes.join('\',\'')}') | ||||
| 			`, | ||||
| 			params: [ | ||||
| 				ResourceOcrStatus.Todo, | ||||
| @@ -536,7 +536,7 @@ export default class Resource extends BaseItem { | ||||
|  | ||||
| 	public static async needOcr(supportedMimeTypes: string[], skippedResourceIds: string[], limit: number, options: LoadOptions): Promise<ResourceEntity[]> { | ||||
| 		const query = this.baseNeedOcrQuery(this.selectFields(options), supportedMimeTypes); | ||||
| 		const skippedResourcesSql = skippedResourceIds.length ? `AND resources.id NOT IN  ("${skippedResourceIds.join('","')}")` : ''; | ||||
| 		const skippedResourcesSql = skippedResourceIds.length ? `AND resources.id NOT IN  ('${skippedResourceIds.join('\',\'')}')` : ''; | ||||
|  | ||||
| 		return await this.db().selectAll(` | ||||
| 			${query.sql} | ||||
| @@ -576,7 +576,7 @@ export default class Resource extends BaseItem { | ||||
| 	public static async resourceOcrTextsByIds(ids: string[]): Promise<ResourceEntity[]> { | ||||
| 		if (!ids.length) return []; | ||||
| 		ids = unique(ids); | ||||
| 		return this.modelSelectAll(`SELECT id, ocr_text FROM resources WHERE id IN ("${ids.join('","')}")`); | ||||
| 		return this.modelSelectAll(`SELECT id, ocr_text FROM resources WHERE id IN ('${ids.join('\',\'')}')`); | ||||
| 	} | ||||
|  | ||||
| 	public static async allForNormalization(updatedTime: number, id: string, limit = 100, options: LoadOptions = null) { | ||||
| @@ -595,7 +595,7 @@ export default class Resource extends BaseItem { | ||||
| 				sql: ` | ||||
| 					SELECT ${this.selectFields(options)} FROM resources | ||||
| 					WHERE ${whereSql} | ||||
| 					AND ocr_text != "" | ||||
| 					AND ocr_text != '' | ||||
| 					AND ocr_status = ? | ||||
| 					ORDER BY updated_time ASC, id ASC | ||||
| 					LIMIT ? | ||||
|   | ||||
| @@ -214,7 +214,7 @@ export default class Revision extends BaseItem { | ||||
|  | ||||
| 	public static async itemsWithRevisions(itemType: ModelType, itemIds: string[]) { | ||||
| 		if (!itemIds.length) return []; | ||||
| 		const rows = await this.db().selectAll(`SELECT distinct item_id FROM revisions WHERE item_type = ? AND item_id IN ("${itemIds.join('","')}")`, [itemType]); | ||||
| 		const rows = await this.db().selectAll(`SELECT distinct item_id FROM revisions WHERE item_type = ? AND item_id IN ('${itemIds.join('\',\'')}')`, [itemType]); | ||||
|  | ||||
| 		return rows.map((r: RevisionEntity) => r.item_id); | ||||
| 	} | ||||
|   | ||||
| @@ -39,7 +39,7 @@ export default class Tag extends BaseItem { | ||||
|  | ||||
| 		return Note.previews( | ||||
| 			null, | ||||
| 			{ ...options, conditions: [`id IN ("${noteIds.join('","')}")`] }, | ||||
| 			{ ...options, conditions: [`id IN ('${noteIds.join('\',\'')}')`] }, | ||||
| 		); | ||||
| 	} | ||||
|  | ||||
| @@ -153,7 +153,7 @@ export default class Tag extends BaseItem { | ||||
|  | ||||
| 		const tagIds = await NoteTag.tagIdsByNoteId(noteId); | ||||
| 		if (!tagIds.length) return []; | ||||
| 		return this.modelSelectAll(`SELECT ${options.fields ? this.db().escapeFields(options.fields) : '*'} FROM tags WHERE id IN ("${tagIds.join('","')}")`); | ||||
| 		return this.modelSelectAll(`SELECT ${options.fields ? this.db().escapeFields(options.fields) : '*'} FROM tags WHERE id IN ('${tagIds.join('\',\'')}')`); | ||||
| 	} | ||||
|  | ||||
| 	public static async commonTagsByNoteIds(noteIds: string[]) { | ||||
| @@ -168,7 +168,7 @@ export default class Tag extends BaseItem { | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		return this.modelSelectAll(`SELECT * FROM tags WHERE id IN ("${commonTagIds.join('","')}")`); | ||||
| 		return this.modelSelectAll(`SELECT * FROM tags WHERE id IN ('${commonTagIds.join('\',\'')}')`); | ||||
| 	} | ||||
|  | ||||
| 	public static async loadByTitle(title: string): Promise<TagEntity> { | ||||
|   | ||||
| @@ -54,7 +54,7 @@ export default class ResourceService extends BaseService { | ||||
|  | ||||
| 				// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied | ||||
| 				const noteIds = changes.map((a: any) => a.item_id); | ||||
| 				const notes = await Note.modelSelectAll(`SELECT id, title, body, encryption_applied FROM notes WHERE id IN ("${noteIds.join('","')}")`); | ||||
| 				const notes = await Note.modelSelectAll(`SELECT id, title, body, encryption_applied FROM notes WHERE id IN ('${noteIds.join('\',\'')}')`); | ||||
|  | ||||
| 				const noteById = (noteId: string) => { | ||||
| 					for (let i = 0; i < notes.length; i++) { | ||||
|   | ||||
| @@ -138,7 +138,7 @@ export default class RevisionService extends BaseService { | ||||
| 				if (!changes.length) break; | ||||
|  | ||||
| 				const noteIds = changes.map((a) => a.item_id); | ||||
| 				const notes = await Note.modelSelectAll(`SELECT * FROM notes WHERE is_conflict = 0 AND encryption_applied = 0 AND id IN ("${noteIds.join('","')}")`); | ||||
| 				const notes = await Note.modelSelectAll(`SELECT * FROM notes WHERE is_conflict = 0 AND encryption_applied = 0 AND id IN ('${noteIds.join('\',\'')}')`); | ||||
|  | ||||
| 				for (let i = 0; i < changes.length; i++) { | ||||
| 					const change = changes[i]; | ||||
|   | ||||
| @@ -136,7 +136,7 @@ export default class SearchEngine { | ||||
| 			const notes = await Note.modelSelectAll(` | ||||
| 				SELECT ${SearchEngine.relevantFields} | ||||
| 				FROM notes | ||||
| 				WHERE id IN ("${currentIds.join('","')}") AND is_conflict = 0 AND encryption_applied = 0 AND deleted_time = 0`); | ||||
| 				WHERE id IN ('${currentIds.join('\',\'')}') AND is_conflict = 0 AND encryption_applied = 0 AND deleted_time = 0`); | ||||
| 			const queries = []; | ||||
|  | ||||
| 			for (let i = 0; i < notes.length; i++) { | ||||
| @@ -219,7 +219,7 @@ export default class SearchEngine { | ||||
| 				const noteIds = changes.map(a => a.item_id); | ||||
| 				const notes = await Note.modelSelectAll(` | ||||
| 					SELECT ${SearchEngine.relevantFields} | ||||
| 					FROM notes WHERE id IN ("${noteIds.join('","')}") AND is_conflict = 0 AND encryption_applied = 0 AND deleted_time = 0`, | ||||
| 					FROM notes WHERE id IN ('${noteIds.join('\',\'')}') AND is_conflict = 0 AND encryption_applied = 0 AND deleted_time = 0`, | ||||
| 				); | ||||
|  | ||||
| 				for (let i = 0; i < changes.length; i++) { | ||||
|   | ||||
| @@ -58,7 +58,7 @@ export default class SearchEngineUtils { | ||||
| 		// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied | ||||
| 		const previewOptions: any = { order: [], | ||||
| 			fields: fields, | ||||
| 			conditions: [`id IN ("${noteIds.join('","')}")`], ...options }; | ||||
| 			conditions: [`id IN ('${noteIds.join('\',\'')}')`], ...options }; | ||||
|  | ||||
| 		const notes = await Note.previews(null, previewOptions); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user