mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Handle globbing pattern for rm and ls
This commit is contained in:
parent
62cdc30fc2
commit
ac4718ac92
@ -75,6 +75,13 @@ async function main() {
|
||||
// return;
|
||||
|
||||
|
||||
// let testglob = await Note.glob('title', 'La *', {
|
||||
// fields: ['title', 'updated_time'],
|
||||
// });
|
||||
// console.info(testglob);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -340,26 +347,37 @@ async function main() {
|
||||
});
|
||||
|
||||
commands.push({
|
||||
usage: 'rm <item-title>',
|
||||
usage: 'rm <pattern>',
|
||||
description: 'Deletes the given item. For a notebook, all the notes within that notebook will be deleted. Use `rm ../<notebook-name>` to delete a notebook.',
|
||||
action: async function(args, end) {
|
||||
let title = args['item-title'];
|
||||
let pattern = args['pattern'];
|
||||
let itemType = null;
|
||||
|
||||
if (title.substr(0, 3) == '../') {
|
||||
itemType = BaseModel.MODEL_TYPE_FOLDER;
|
||||
title = title.substr(3);
|
||||
} else {
|
||||
itemType = BaseModel.MODEL_TYPE_NOTE;
|
||||
}
|
||||
if (pattern.indexOf('*') < 0) { // Handle it as a simple title
|
||||
if (pattern.substr(0, 3) == '../') {
|
||||
itemType = BaseModel.MODEL_TYPE_FOLDER;
|
||||
pattern = pattern.substr(3);
|
||||
} else {
|
||||
itemType = BaseModel.MODEL_TYPE_NOTE;
|
||||
}
|
||||
|
||||
let item = await BaseItem.loadItemByField(itemType, 'title', title);
|
||||
if (!item) return cmdError(this, _('No item with title "%s" found.', title), end);
|
||||
await BaseItem.deleteItem(itemType, item.id);
|
||||
let item = await BaseItem.loadItemByField(itemType, 'title', pattern);
|
||||
if (!item) return cmdError(this, _('No item with title "%s" found.', pattern), end);
|
||||
await BaseItem.deleteItem(itemType, item.id);
|
||||
|
||||
if (currentFolder && currentFolder.id == item.id) {
|
||||
let f = await Folder.defaultFolder();
|
||||
switchCurrentFolder(f);
|
||||
if (currentFolder && currentFolder.id == item.id) {
|
||||
let f = await Folder.defaultFolder();
|
||||
switchCurrentFolder(f);
|
||||
}
|
||||
} else { // Handle it as a glob pattern
|
||||
let notes = await Note.previews(currentFolder.id, { titlePattern: pattern });
|
||||
if (!notes.length) return cmdError(this, _('No note matches this pattern: "%s"', pattern), end);
|
||||
let ok = await cmdPromptConfirm(this, _('%d notes match this pattern. Delete them?', notes.length));
|
||||
if (ok) {
|
||||
for (let i = 0; i < notes.length; i++) {
|
||||
await Note.delete(notes[i].id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end();
|
||||
@ -368,7 +386,7 @@ async function main() {
|
||||
});
|
||||
|
||||
commands.push({
|
||||
usage: 'ls [notebook-title]',
|
||||
usage: 'ls [pattern]',
|
||||
description: 'Displays the notes in [notebook-title]. Use `ls ..` to display the list of notebooks.',
|
||||
options: [
|
||||
['-n, --lines <num>', 'Displays only the first top <num> lines.'],
|
||||
@ -377,7 +395,7 @@ async function main() {
|
||||
['-t, --type <type>', 'Displays only the items of the specific type(s). Can be `n` for notes, `t` for todos, or `nt` for notes and todos (eg. `-tt` would display only the todos, while `-ttd` would display notes and todos.'],
|
||||
],
|
||||
action: async function(args, end) {
|
||||
let folderTitle = args['notebook-title'];
|
||||
let pattern = args['pattern'];
|
||||
let suffix = '';
|
||||
let items = [];
|
||||
let options = args.options;
|
||||
@ -395,22 +413,13 @@ async function main() {
|
||||
if (options.type.indexOf('n') >= 0) queryOptions.itemTypes.push('note');
|
||||
if (options.type.indexOf('t') >= 0) queryOptions.itemTypes.push('todo');
|
||||
}
|
||||
if (pattern) queryOptions.titlePattern = pattern;
|
||||
|
||||
if (folderTitle == '..') {
|
||||
if (pattern == '..') {
|
||||
items = await Folder.all(queryOptions);
|
||||
suffix = '/';
|
||||
} else {
|
||||
let folder = null;
|
||||
|
||||
if (folderTitle) {
|
||||
folder = await Folder.loadByField('title', folderTitle);
|
||||
} else if (currentFolder) {
|
||||
folder = currentFolder;
|
||||
}
|
||||
|
||||
if (!folder) return cmdError(this, _('Unknown notebook: "%s"', folderTitle), end);
|
||||
|
||||
items = await Note.previews(folder.id, queryOptions);
|
||||
items = await Note.previews(currentFolder.id, queryOptions);
|
||||
}
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
|
@ -133,6 +133,7 @@ class BaseModel {
|
||||
if (options.orderByDir) sql += ' ' + options.orderByDir;
|
||||
}
|
||||
if (options.limit) sql += ' LIMIT ' + options.limit;
|
||||
//if (options.fields && options.fields.length) sql = sql.replace('SELECT *', 'SELECT ' + this.db().escapeFields(options.fields).join(','));
|
||||
|
||||
return { sql: sql, params: params };
|
||||
}
|
||||
|
@ -167,6 +167,18 @@ class Database {
|
||||
});
|
||||
}
|
||||
|
||||
escapeField(field) {
|
||||
return '`' + field + '`';
|
||||
}
|
||||
|
||||
escapeFields(fields) {
|
||||
let output = [];
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
output.push(this.escapeField(fields[i]));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
selectOne(sql, params = null) {
|
||||
this.logQuery(sql, params);
|
||||
return this.driver().selectOne(sql, params).catch((error) => {
|
||||
@ -285,8 +297,10 @@ class Database {
|
||||
logQuery(sql, params = null) {
|
||||
if (!this.debugMode()) return;
|
||||
|
||||
//console.info(sql, params);
|
||||
|
||||
this.logger().debug(sql);
|
||||
if (params !== null) this.logger().debug(JSON.stringify(params));
|
||||
if (params !== null && params.length) this.logger().debug(JSON.stringify(params));
|
||||
}
|
||||
|
||||
static insertQuery(tableName, data) {
|
||||
|
@ -6,6 +6,7 @@ class Logger {
|
||||
constructor() {
|
||||
this.targets_ = [];
|
||||
this.level_ = Logger.LEVEL_ERROR;
|
||||
this.fileAppendQueue_ = []
|
||||
}
|
||||
|
||||
setLevel(level) {
|
||||
@ -64,14 +65,32 @@ class Logger {
|
||||
} else {
|
||||
serializedObject = object;
|
||||
}
|
||||
|
||||
fs.appendFile(t.path, line + serializedObject + "\n", (error) => {
|
||||
if (error) throw error;
|
||||
|
||||
this.fileAppendQueue_.push({
|
||||
path: t.path,
|
||||
line: line + serializedObject + "\n",
|
||||
});
|
||||
|
||||
this.scheduleFileAppendQueueProcessing_();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scheduleFileAppendQueueProcessing_() {
|
||||
if (this.fileAppendQueueTID_) return;
|
||||
|
||||
this.fileAppendQueueTID_ = setTimeout(async () => {
|
||||
this.fileAppendQueueTID_ = null;
|
||||
|
||||
let queue = this.fileAppendQueue_.slice(0);
|
||||
for (let i = 0; i < queue.length; i++) {
|
||||
let t = queue[i];
|
||||
await fs.appendFile(t.path, t.line);
|
||||
}
|
||||
this.fileAppendQueue_.splice(0, queue.length);
|
||||
}, 10);
|
||||
}
|
||||
|
||||
error(object) { return this.log(Logger.LEVEL_ERROR, object); }
|
||||
warn(object) { return this.log(Logger.LEVEL_WARN, object); }
|
||||
info(object) { return this.log(Logger.LEVEL_INFO, object); }
|
||||
|
@ -39,8 +39,12 @@ class Note extends BaseItem {
|
||||
return output;
|
||||
}
|
||||
|
||||
static previewFields() {
|
||||
return ['id', 'title', 'body', 'is_todo', 'todo_completed', 'parent_id', 'updated_time'];
|
||||
}
|
||||
|
||||
static previewFieldsSql() {
|
||||
return '`id`, `title`, `body`, `is_todo`, `todo_completed`, `parent_id`, `updated_time`'
|
||||
return this.db().escapeFields(this.previewFields()).join(',');
|
||||
}
|
||||
|
||||
static previews(parentId, options = null) {
|
||||
@ -49,6 +53,7 @@ class Note extends BaseItem {
|
||||
if (!options.orderByDir) options.orderByDir = 'DESC';
|
||||
|
||||
let sql = 'SELECT ' + this.previewFieldsSql() + ' FROM notes WHERE is_conflict = 0 AND parent_id = ?';
|
||||
let params = [parentId];
|
||||
if (options.itemTypes && options.itemTypes.length) {
|
||||
if (options.itemTypes.indexOf('note') >= 0 && options.itemTypes.indexOf('todo') >= 0) {
|
||||
// Fetch everything
|
||||
@ -58,7 +63,14 @@ class Note extends BaseItem {
|
||||
sql += ' AND is_todo = 1';
|
||||
}
|
||||
}
|
||||
let query = this.applySqlOptions(options, sql, [parentId]);
|
||||
|
||||
if (options.titlePattern) {
|
||||
let pattern = options.titlePattern.replace(/\*/g, '%');
|
||||
sql += ' AND title LIKE ?';
|
||||
params.push(pattern);
|
||||
}
|
||||
|
||||
let query = this.applySqlOptions(options, sql, params);
|
||||
|
||||
return this.modelSelectAll(query.sql, query.params);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user