Mass delete query results

  • Preparation:
    • Add a macro inside file config.edn , inside macros{} :
    :deleteparent "<button class='kit eval' data-kit='massdelete'>► !!! DELETE !!! query results of parent block !!!</button>"
    
    • The code below requires having kits inside file custom.js .
    • Inside page MassDelete in Logseq, put the following code in a javascript code-block:
      const LS = logseq.api
      const Module = logseq.Module
      const Kits = Module.Kits
      const Msg = Module.Msg
      
      function advancedQuery(content, queryWord){
          const queryStart = content.indexOf("[", queryWord + 5)
      	if (queryStart < 0) return
      
          var queryEnd = queryStart + 1
          var n = 1
          while (n > 0) {
            const close = content.indexOf("]", queryEnd)
            if (close < 0) return
      
            const open = content.indexOf("[", queryEnd)
            if (close < open || open < 0) {
                queryEnd = close + 1
                n -= 1
                continue
            }
      
            queryEnd = open + 1
            n += 1
          }
      
          return content.slice(queryStart, queryEnd)
      }
      
      function simpleQuery(content, queryWord){
          const queryStart = queryWord + 6
          const queryEnd = content.indexOf("}}", queryStart)
          return content.slice(queryStart, queryEnd)
      }
      
      function getBlocks(content, queryWord){
      	if (queryWord < 0) return
      
          if (content[queryWord - 1] === ":") {
              const query = advancedQuery(content, queryWord)
              if (query) return LS.datascript_query(query).flat()
          } else if (content.slice(queryWord - 2, queryWord) === "{{") {
              const query = simpleQuery(content, queryWord)
              if (query) return LS.custom_query(query)
          }
      }
      
      logseq.kits.massdelete = Kits.addClickEventToButton.bind(null, function onDeleteParentClicked(e){
          const child = e.target.closest("div.ls-block")
          const parent = child.parentElement.closest("div.ls-block")
          const blockId = parent.getAttribute("blockid")
          const block = logseq.api.get_block(blockId)
          const content = block.content.replace(/\n?.*[:][:].*\n?/g, "\n").trim()
      
          const queryWord = content.indexOf("query")
          const res = getBlocks(content, queryWord)
      	if (!res) return Msg.ofStatus("Missing query", "warning")
      
          res.forEach( (r)=>{
              const name = r.name
              if (name) LS.delete_page(name)
              else LS.remove_block(r.uuid)
          })
          Msg.ofStatus("Deleted " + res.length, "success")
      })
      
  • Usage:
    • Create a query that returns the items for deletion:
      • either simple or advanced
      • either blocks or pages
      • keep it simple, as this is not tested with every possible query
    • Check the results to make sure that all of them are meant for deletion.
      • This code deletes information, so use with caution !
        • Ensure that you have a backup, just in case.
    • Put the macro at a child block under the query:
      • i.e. {{deleteparent}}
    • Press the button. This should automatically:
      • try reading the query from the parent block
        • the parser is basic, so avoid special strings
      • run the query again
      • delete without confirmation everything returned one-by-one
        • this is important, because it may be undoable
      • show a success message with the number of deleted items