block_ref_query.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. // SiYuan - Refactor your thinking
  2. // Copyright (c) 2020-present, b3log.org
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Affero General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Affero General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Affero General Public License
  15. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. package sql
  17. import (
  18. "database/sql"
  19. "sort"
  20. "strings"
  21. "github.com/88250/gulu"
  22. "github.com/88250/lute/parse"
  23. "github.com/emirpasic/gods/sets/hashset"
  24. "github.com/siyuan-note/logging"
  25. "github.com/siyuan-note/siyuan/kernel/search"
  26. )
  27. func GetRefDuplicatedDefRootIDs() (ret []string) {
  28. rows, err := query("SELECT DISTINCT def_block_root_id FROM `refs` GROUP BY def_block_id, def_block_root_id, block_id HAVING COUNT(*) > 1")
  29. if nil != err {
  30. logging.LogErrorf("sql query failed: %s", err)
  31. return
  32. }
  33. defer rows.Close()
  34. for rows.Next() {
  35. var id string
  36. rows.Scan(&id)
  37. ret = append(ret, id)
  38. }
  39. return
  40. }
  41. func QueryVirtualRefKeywords(name, alias, anchor, doc bool) (ret []string) {
  42. if name {
  43. ret = append(ret, queryNames()...)
  44. }
  45. if alias {
  46. ret = append(ret, queryAliases()...)
  47. }
  48. if anchor {
  49. ret = append(ret, queryRefTexts()...)
  50. }
  51. if doc {
  52. ret = append(ret, queryDocTitles()...)
  53. }
  54. ret = gulu.Str.RemoveDuplicatedElem(ret)
  55. sort.SliceStable(ret, func(i, j int) bool {
  56. return len(ret[i]) >= len(ret[j])
  57. })
  58. return
  59. }
  60. func queryRefTexts() (ret []string) {
  61. ret = []string{}
  62. sqlStmt := "SELECT DISTINCT content FROM refs LIMIT 10240"
  63. rows, err := query(sqlStmt)
  64. if nil != err {
  65. logging.LogErrorf("sql query failed: %s", sqlStmt, err)
  66. return
  67. }
  68. defer rows.Close()
  69. set := hashset.New()
  70. for rows.Next() {
  71. var refText string
  72. rows.Scan(&refText)
  73. if "" == strings.TrimSpace(refText) {
  74. continue
  75. }
  76. set.Add(refText)
  77. }
  78. for _, refText := range set.Values() {
  79. ret = append(ret, refText.(string))
  80. }
  81. return
  82. }
  83. func QueryRefCount(defIDs []string) (ret map[string]int) {
  84. ret = map[string]int{}
  85. ids := strings.Join(defIDs, "','")
  86. ids = "('" + ids + "')"
  87. rows, err := query("SELECT def_block_id, COUNT(*) AS ref_cnt FROM refs WHERE def_block_id IN " + ids + " GROUP BY def_block_id")
  88. if nil != err {
  89. logging.LogErrorf("sql query failed: %s", err)
  90. return
  91. }
  92. defer rows.Close()
  93. for rows.Next() {
  94. var id string
  95. var cnt int
  96. if err = rows.Scan(&id, &cnt); nil != err {
  97. logging.LogErrorf("query scan field failed: %s", err)
  98. return
  99. }
  100. ret[id] = cnt
  101. }
  102. return
  103. }
  104. func QueryRootChildrenRefCount(defRootID string) (ret map[string]int) {
  105. ret = map[string]int{}
  106. rows, err := query("SELECT def_block_id, COUNT(*) AS ref_cnt FROM refs WHERE def_block_root_id = ? GROUP BY def_block_id", defRootID)
  107. if nil != err {
  108. logging.LogErrorf("sql query failed: %s", err)
  109. return
  110. }
  111. defer rows.Close()
  112. for rows.Next() {
  113. var id string
  114. var cnt int
  115. if err = rows.Scan(&id, &cnt); nil != err {
  116. logging.LogErrorf("query scan field failed: %s", err)
  117. return
  118. }
  119. ret[id] = cnt
  120. }
  121. return
  122. }
  123. func QueryRootBlockRefCount() (ret map[string]int) {
  124. ret = map[string]int{}
  125. rows, err := query("SELECT def_block_root_id, COUNT(*) AS ref_cnt FROM refs GROUP BY def_block_root_id")
  126. if nil != err {
  127. logging.LogErrorf("sql query failed: %s", err)
  128. return
  129. }
  130. defer rows.Close()
  131. for rows.Next() {
  132. var id string
  133. var cnt int
  134. if err = rows.Scan(&id, &cnt); nil != err {
  135. logging.LogErrorf("query scan field failed: %s", err)
  136. return
  137. }
  138. ret[id] = cnt
  139. }
  140. return
  141. }
  142. func QueryDefRootBlocksByRefRootID(refRootID string) (ret []*Block) {
  143. rows, err := query("SELECT * FROM blocks WHERE id IN (SELECT DISTINCT def_block_root_id FROM refs WHERE root_id = ?)", refRootID)
  144. if nil != err {
  145. logging.LogErrorf("sql query failed: %s", err)
  146. return
  147. }
  148. defer rows.Close()
  149. for rows.Next() {
  150. if block := scanBlockRows(rows); nil != block {
  151. ret = append(ret, block)
  152. }
  153. }
  154. return
  155. }
  156. func QueryRefRootBlocksByDefRootIDs(defRootIDs []string) (ret map[string][]*Block) {
  157. ret = map[string][]*Block{}
  158. stmt := "SELECT r.def_block_root_id, b.* FROM refs AS r, blocks AS b ON r.def_block_root_id IN ('" + strings.Join(defRootIDs, "','") + "')" + " AND b.id = r.root_id"
  159. rows, err := query(stmt)
  160. if nil != err {
  161. logging.LogErrorf("sql query failed: %s", err)
  162. return
  163. }
  164. defer rows.Close()
  165. for rows.Next() {
  166. var block Block
  167. var defRootID string
  168. if err := rows.Scan(&defRootID, &block.ID, &block.ParentID, &block.RootID, &block.Hash, &block.Box, &block.Path, &block.HPath, &block.Name, &block.Alias, &block.Memo, &block.Tag, &block.Content, &block.FContent, &block.Markdown, &block.Length, &block.Type, &block.SubType, &block.IAL, &block.Sort, &block.Created, &block.Updated); nil != err {
  169. logging.LogErrorf("query scan field failed: %s\n%s", err, logging.ShortStack())
  170. return
  171. }
  172. if nil == ret[defRootID] {
  173. ret[defRootID] = []*Block{&block}
  174. } else {
  175. ret[defRootID] = append(ret[defRootID], &block)
  176. }
  177. }
  178. return
  179. }
  180. func GetRefText(defBlockID string) (ret string) {
  181. ret = getRefText(defBlockID)
  182. ret = strings.ReplaceAll(ret, search.SearchMarkLeft, "")
  183. ret = strings.ReplaceAll(ret, search.SearchMarkRight, "")
  184. return
  185. }
  186. func getRefText(defBlockID string) string {
  187. block := GetBlock(defBlockID)
  188. if nil == block {
  189. if strings.HasPrefix(defBlockID, "assets") {
  190. return defBlockID
  191. }
  192. return "block not found"
  193. }
  194. if "" != block.Name {
  195. return block.Name
  196. }
  197. switch block.Type {
  198. case "d":
  199. return block.Content
  200. case "query_embed":
  201. return "Query Embed Block " + block.Markdown
  202. case "av":
  203. return "Database " + block.Markdown
  204. case "iframe":
  205. return "IFrame " + block.Markdown
  206. case "tb":
  207. return "Thematic Break"
  208. case "video":
  209. return "Video " + block.Markdown
  210. case "audio":
  211. return "Audio " + block.Markdown
  212. }
  213. if block.IsContainerBlock() {
  214. subTree := parse.Parse("", []byte(block.Markdown), luteEngine.ParseOptions)
  215. return GetContainerText(subTree.Root)
  216. }
  217. return block.Content
  218. }
  219. func QueryBlockDefIDsByRefText(refText string, excludeIDs []string) (ret []string) {
  220. ret = queryDefIDsByDefText(refText, excludeIDs)
  221. ret = append(ret, queryDefIDsByNameAlias(refText, excludeIDs)...)
  222. ret = append(ret, queryDocIDsByTitle(refText, excludeIDs)...)
  223. ret = gulu.Str.RemoveDuplicatedElem(ret)
  224. return
  225. }
  226. func queryDefIDsByDefText(keyword string, excludeIDs []string) (ret []string) {
  227. ret = []string{}
  228. notIn := "('" + strings.Join(excludeIDs, "','") + "')"
  229. q := "SELECT DISTINCT(def_block_id) FROM refs WHERE content LIKE ? AND def_block_id NOT IN " + notIn
  230. if caseSensitive {
  231. q = "SELECT DISTINCT(def_block_id) FROM refs WHERE content = ? AND def_block_id NOT IN " + notIn
  232. }
  233. rows, err := query(q, keyword)
  234. if nil != err {
  235. logging.LogErrorf("sql query failed: %s", err)
  236. return
  237. }
  238. defer rows.Close()
  239. for rows.Next() {
  240. var id string
  241. if err = rows.Scan(&id); nil != err {
  242. logging.LogErrorf("query scan field failed: %s", err)
  243. return
  244. }
  245. ret = append(ret, id)
  246. }
  247. return
  248. }
  249. func queryDefIDsByNameAlias(keyword string, excludeIDs []string) (ret []string) {
  250. ret = []string{}
  251. notIn := "('" + strings.Join(excludeIDs, "','") + "')"
  252. rows, err := query("SELECT DISTINCT(id), name, alias FROM blocks WHERE (name = ? OR alias LIKE ?) AND id NOT IN "+notIn, keyword, "%"+keyword+"%")
  253. if nil != err {
  254. logging.LogErrorf("sql query failed: %s", err)
  255. return
  256. }
  257. defer rows.Close()
  258. for rows.Next() {
  259. var id, name, alias string
  260. if err = rows.Scan(&id, &name, &alias); nil != err {
  261. logging.LogErrorf("query scan field failed: %s", err)
  262. return
  263. }
  264. if name == keyword {
  265. ret = append(ret, id)
  266. continue
  267. }
  268. var hitAlias bool
  269. aliases := strings.Split(alias, ",")
  270. for _, a := range aliases {
  271. if "" == a {
  272. continue
  273. }
  274. if keyword == a {
  275. hitAlias = true
  276. }
  277. }
  278. if strings.Contains(alias, keyword) && !hitAlias {
  279. continue
  280. }
  281. ret = append(ret, id)
  282. }
  283. return
  284. }
  285. func QueryChildDefIDsByRootDefID(rootDefID string) (ret []string) {
  286. ret = []string{}
  287. rows, err := query("SELECT DISTINCT(def_block_id) FROM refs WHERE def_block_root_id = ?", rootDefID)
  288. if nil != err {
  289. logging.LogErrorf("sql query failed: %s", err)
  290. return
  291. }
  292. defer rows.Close()
  293. for rows.Next() {
  294. var id string
  295. if err = rows.Scan(&id); nil != err {
  296. logging.LogErrorf("query scan field failed: %s", err)
  297. return
  298. }
  299. ret = append(ret, id)
  300. }
  301. return
  302. }
  303. func QueryRefIDsByDefID(defID string, containChildren bool) (refIDs, refTexts []string) {
  304. refIDs = []string{}
  305. var rows *sql.Rows
  306. var err error
  307. if containChildren {
  308. rows, err = query("SELECT block_id, content FROM refs WHERE def_block_root_id = ?", defID)
  309. } else {
  310. rows, err = query("SELECT block_id, content FROM refs WHERE def_block_id = ?", defID)
  311. }
  312. if nil != err {
  313. logging.LogErrorf("sql query failed: %s", err)
  314. return
  315. }
  316. defer rows.Close()
  317. for rows.Next() {
  318. var id, content string
  319. if err = rows.Scan(&id, &content); nil != err {
  320. logging.LogErrorf("query scan field failed: %s", err)
  321. return
  322. }
  323. refIDs = append(refIDs, id)
  324. refTexts = append(refTexts, content)
  325. }
  326. return
  327. }
  328. func QueryRefsRecent(onlyDoc bool) (ret []*Ref) {
  329. stmt := "SELECT * FROM refs AS r"
  330. if onlyDoc {
  331. stmt = "SELECT r.* FROM refs AS r, blocks AS b WHERE b.type = 'd' AND b.id = r.def_block_id"
  332. }
  333. stmt += " GROUP BY r.def_block_id ORDER BY r.id DESC LIMIT 32"
  334. rows, err := query(stmt)
  335. if nil != err {
  336. logging.LogErrorf("sql query failed: %s", err)
  337. return
  338. }
  339. defer rows.Close()
  340. for rows.Next() {
  341. ref := scanRefRows(rows)
  342. ret = append(ret, ref)
  343. }
  344. return
  345. }
  346. func QueryRefsByDefID(defBlockID string, containChildren bool) (ret []*Ref) {
  347. sqlBlock := GetBlock(defBlockID)
  348. if nil == sqlBlock {
  349. return
  350. }
  351. var rows *sql.Rows
  352. var err error
  353. if "d" == sqlBlock.Type {
  354. rows, err = query("SELECT * FROM refs WHERE def_block_root_id = ?", defBlockID)
  355. } else {
  356. if containChildren {
  357. blockIDs := queryBlockChildrenIDs(defBlockID)
  358. var params []string
  359. for _, id := range blockIDs {
  360. params = append(params, "\""+id+"\"")
  361. }
  362. rows, err = query("SELECT * FROM refs WHERE def_block_id IN (" + strings.Join(params, ",") + ")")
  363. } else {
  364. rows, err = query("SELECT * FROM refs WHERE def_block_id = ?", defBlockID)
  365. }
  366. }
  367. if nil != err {
  368. logging.LogErrorf("sql query failed: %s", err)
  369. return
  370. }
  371. defer rows.Close()
  372. for rows.Next() {
  373. ref := scanRefRows(rows)
  374. ret = append(ret, ref)
  375. }
  376. return
  377. }
  378. func QueryRefsByDefIDRefID(defBlockID, refBlockID string) (ret []*Ref) {
  379. stmt := "SELECT * FROM refs WHERE def_block_id = ? AND block_id = ?"
  380. rows, err := query(stmt, defBlockID, refBlockID)
  381. if nil != err {
  382. logging.LogErrorf("sql query failed: %s", err)
  383. return
  384. }
  385. defer rows.Close()
  386. for rows.Next() {
  387. ref := scanRefRows(rows)
  388. ret = append(ret, ref)
  389. }
  390. return
  391. }
  392. func DefRefs(condition string) (ret []map[*Block]*Block) {
  393. ret = []map[*Block]*Block{}
  394. stmt := "SELECT ref.*, r.block_id || '@' || r.def_block_id AS rel FROM blocks AS ref, refs AS r WHERE ref.id = r.block_id"
  395. if "" != condition {
  396. stmt += " AND " + condition
  397. }
  398. rows, err := query(stmt)
  399. if nil != err {
  400. logging.LogErrorf("sql query failed: %s", err)
  401. return
  402. }
  403. defer rows.Close()
  404. refs := map[string]*Block{}
  405. for rows.Next() {
  406. var ref Block
  407. var rel string
  408. if err = rows.Scan(&ref.ID, &ref.ParentID, &ref.RootID, &ref.Hash, &ref.Box, &ref.Path, &ref.HPath, &ref.Name, &ref.Alias, &ref.Memo, &ref.Tag, &ref.Content, &ref.FContent, &ref.Markdown, &ref.Length, &ref.Type, &ref.SubType, &ref.IAL, &ref.Sort, &ref.Created, &ref.Updated,
  409. &rel); nil != err {
  410. logging.LogErrorf("query scan field failed: %s", err)
  411. return
  412. }
  413. refs[rel] = &ref
  414. }
  415. rows, err = query("SELECT def.* FROM blocks AS def, refs AS r WHERE def.id = r.def_block_id")
  416. if nil != err {
  417. logging.LogErrorf("sql query failed: %s", err)
  418. return
  419. }
  420. defer rows.Close()
  421. defs := map[string]*Block{}
  422. for rows.Next() {
  423. if def := scanBlockRows(rows); nil != def {
  424. defs[def.ID] = def
  425. }
  426. }
  427. for rel, ref := range refs {
  428. defID := strings.Split(rel, "@")[1]
  429. def := defs[defID]
  430. if nil == def {
  431. continue
  432. }
  433. defRef := map[*Block]*Block{}
  434. defRef[def] = ref
  435. ret = append(ret, defRef)
  436. }
  437. return
  438. }
  439. func scanRefRows(rows *sql.Rows) (ret *Ref) {
  440. var ref Ref
  441. if err := rows.Scan(&ref.ID, &ref.DefBlockID, &ref.DefBlockParentID, &ref.DefBlockRootID, &ref.DefBlockPath, &ref.BlockID, &ref.RootID, &ref.Box, &ref.Path, &ref.Content, &ref.Markdown, &ref.Type); nil != err {
  442. logging.LogErrorf("query scan field failed: %s", err)
  443. return
  444. }
  445. ret = &ref
  446. return
  447. }