mirror of
https://github.com/documize/community.git
synced 2025-08-02 03:55:24 +02:00
Implement PostgreSQL Full Text Search++
1. Full text search supports MySQL, MariaDB, Percona and now PostgreSQL. 2. Changed SQL Variant to typed enum. 3. Changed doc.Versioned from INT to BOOL. 4. Search Reindexer now parses all documents and attachments. 5. Site meta API call returns storage provider type. 6. README prep'ed for PostgreSQL support. 7. DELETE SQL statements ignore zero rows affected. Closes #100 !!! Co-Authored-By: Saul S <sauls8t@users.noreply.github.com> Co-Authored-By: McMatts <matt@documize.com>
This commit is contained in:
parent
97beb3f4d3
commit
8a65567169
26 changed files with 274 additions and 113 deletions
|
@ -12,6 +12,7 @@
|
|||
package attachment
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -75,8 +76,13 @@ func (s Store) GetAttachments(ctx domain.RequestContext, docID string) (a []atta
|
|||
ORDER BY c_filename`),
|
||||
ctx.OrgID, docID)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
a = []attachment.Attachment{}
|
||||
}
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "execute select attachments")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -94,6 +100,11 @@ func (s Store) GetAttachmentsWithData(ctx domain.RequestContext, docID string) (
|
|||
ORDER BY c_filename`),
|
||||
ctx.OrgID, docID)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
a = []attachment.Attachment{}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "execute select attachments with data")
|
||||
}
|
||||
|
|
|
@ -202,7 +202,7 @@ func (s Store) RemoveDocumentCategories(ctx domain.RequestContext, documentID st
|
|||
|
||||
// DeleteBySpace removes all category and category associations for given space.
|
||||
func (s Store) DeleteBySpace(ctx domain.RequestContext, spaceID string) (rows int64, err error) {
|
||||
s1 := fmt.Sprintf("DELETE FROM categorymember WHERE c_orgid='%s' AND c_groupid='%s'", ctx.OrgID, spaceID)
|
||||
s1 := fmt.Sprintf("DELETE FROM dmz_category_member WHERE c_orgid='%s' AND c_spaceid='%s'", ctx.OrgID, spaceID)
|
||||
s.DeleteWhere(ctx.Transaction, s1)
|
||||
|
||||
s2 := fmt.Sprintf("DELETE FROM dmz_category WHERE c_orgid='%s' AND c_spaceid='%s'", ctx.OrgID, spaceID)
|
||||
|
|
|
@ -245,28 +245,28 @@ func (s Store) MoveActivity(ctx domain.RequestContext, documentID, oldSpaceID, n
|
|||
// Delete removes the specified document.
|
||||
// Remove document pages, revisions, attachments, updates the search subsystem.
|
||||
func (s Store) Delete(ctx domain.RequestContext, documentID string) (rows int64, err error) {
|
||||
rows, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_section WHERE c_docid=\"%s\" AND c_orgid=\"%s\"", documentID, ctx.OrgID))
|
||||
rows, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_section WHERE c_docid='%s' AND c_orgid='%s'", documentID, ctx.OrgID))
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_section_revision WHERE c_docid=\"%s\" AND c_orgid=\"%s\"", documentID, ctx.OrgID))
|
||||
_, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_section_revision WHERE c_docid='%s' AND c_orgid='%s'", documentID, ctx.OrgID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_doc_attachment WHERE c_docid=\"%s\" AND c_orgid=\"%s\"", documentID, ctx.OrgID))
|
||||
_, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_doc_attachment WHERE c_docid='%s' AND c_orgid='%s'", documentID, ctx.OrgID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_category_member WHERE c_docid=\"%s\" AND c_orgid=\"%s\"", documentID, ctx.OrgID))
|
||||
_, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_category_member WHERE c_docid='%s' AND c_orgid='%s'", documentID, ctx.OrgID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_doc_vote WHERE c_docid=\"%s\" AND c_orgid=\"%s\"", documentID, ctx.OrgID))
|
||||
_, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_doc_vote WHERE c_docid='%s' AND c_orgid='%s'", documentID, ctx.OrgID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -277,23 +277,23 @@ func (s Store) Delete(ctx domain.RequestContext, documentID string) (rows int64,
|
|||
// DeleteBySpace removes all documents for given space.
|
||||
// Remove document pages, revisions, attachments, updates the search subsystem.
|
||||
func (s Store) DeleteBySpace(ctx domain.RequestContext, spaceID string) (rows int64, err error) {
|
||||
rows, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_section WHERE c_docid IN (SELECT c_refid FROM dmz_doc WHERE c_spaceid=\"%s\" AND c_orgid=\"%s\")", spaceID, ctx.OrgID))
|
||||
rows, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_section WHERE c_docid IN (SELECT c_refid FROM dmz_doc WHERE c_spaceid='%s' AND c_orgid='%s')", spaceID, ctx.OrgID))
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_section_revision WHERE c_docid IN (SELECT c_refid FROM dmz_doc WHERE c_spaceid=\"%s\" AND c_orgid=\"%s\")", spaceID, ctx.OrgID))
|
||||
_, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_section_revision WHERE c_docid IN (SELECT c_refid FROM dmz_doc WHERE c_spaceid='%s' AND c_orgid='%s')", spaceID, ctx.OrgID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_doc_attachment WHERE c_docid IN (SELECT c_refid FROM dmz_doc WHERE c_spaceid=\"%s\" AND c_orgid=\"%s\")", spaceID, ctx.OrgID))
|
||||
_, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_doc_attachment WHERE c_docid IN (SELECT c_refid FROM dmz_doc WHERE c_spaceid='%s' AND c_orgid='%s')", spaceID, ctx.OrgID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_doc_vote WHERE c_docid IN (SELECT c_refid FROM dmz_doc WHERE c_spaceid=\"%s\" AND c_orgid=\"%s\")", spaceID, ctx.OrgID))
|
||||
_, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_doc_vote WHERE c_docid IN (SELECT c_refid FROM dmz_doc WHERE c_spaceid='%s' AND c_orgid='%s')", spaceID, ctx.OrgID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -332,7 +332,7 @@ func (s Store) GetVersions(ctx domain.RequestContext, groupID string) (v []doc.V
|
|||
// Any existing vote by the user is replaced.
|
||||
func (s Store) Vote(ctx domain.RequestContext, refID, orgID, documentID, userID string, vote int) (err error) {
|
||||
_, err = s.DeleteWhere(ctx.Transaction,
|
||||
fmt.Sprintf("DELETE FROM dmz_doc_vote WHERE c_orgid=\"%s\" AND c_docid=\"%s\" AND c_voter=\"%s\"",
|
||||
fmt.Sprintf("DELETE FROM dmz_doc_vote WHERE c_orgid='%s' AND c_docid='%s' AND c_voter='%s'",
|
||||
orgID, documentID, userID))
|
||||
if err != nil {
|
||||
s.Runtime.Log.Error("store.Vote", err)
|
||||
|
|
|
@ -104,7 +104,7 @@ func (s Store) Delete(ctx domain.RequestContext, refID string) (rows int64, err
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
return s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_group_member WHERE c_orgid=\"%s\" AND c_groupid=\"%s\"", ctx.OrgID, refID))
|
||||
return s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_group_member WHERE c_orgid='%s' AND c_groupid='%s'", ctx.OrgID, refID))
|
||||
}
|
||||
|
||||
// GetGroupMembers returns all user associated with given group.
|
||||
|
@ -143,8 +143,12 @@ func (s Store) JoinGroup(ctx domain.RequestContext, groupID, userID string) (err
|
|||
|
||||
// LeaveGroup removes user from group.
|
||||
func (s Store) LeaveGroup(ctx domain.RequestContext, groupID, userID string) (err error) {
|
||||
_, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_group_member WHERE c_orgid=\"%s\" AND c_groupid=\"%s\" AND c_userid=\"%s\"",
|
||||
_, err = s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_group_member WHERE c_orgid='%s' AND c_groupid='%s' AND c_userid='%s'",
|
||||
ctx.OrgID, groupID, userID))
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "clear group member")
|
||||
}
|
||||
|
|
|
@ -137,12 +137,12 @@ func (s Store) MarkOrphanAttachmentLink(ctx domain.RequestContext, attachmentID
|
|||
|
||||
// DeleteSourcePageLinks removes saved links for given source.
|
||||
func (s Store) DeleteSourcePageLinks(ctx domain.RequestContext, pageID string) (rows int64, err error) {
|
||||
return s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_doc_link WHERE c_orgid=\"%s\" AND c_sourcesectionid=\"%s\"", ctx.OrgID, pageID))
|
||||
return s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_doc_link WHERE c_orgid='%s' AND c_sourcesectionid='%s'", ctx.OrgID, pageID))
|
||||
}
|
||||
|
||||
// DeleteSourceDocumentLinks removes saved links for given document.
|
||||
func (s Store) DeleteSourceDocumentLinks(ctx domain.RequestContext, documentID string) (rows int64, err error) {
|
||||
return s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_doc_link WHERE c_orgid=\"%s\" AND c_sourcedocid=\"%s\"", ctx.OrgID, documentID))
|
||||
return s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_doc_link WHERE c_orgid='%s' AND c_sourcedocid='%s'", ctx.OrgID, documentID))
|
||||
}
|
||||
|
||||
// DeleteLink removes saved link from the store.
|
||||
|
|
|
@ -62,6 +62,7 @@ func (h *Handler) Meta(w http.ResponseWriter, r *http.Request) {
|
|||
data.Valid = h.Runtime.Product.License.Valid
|
||||
data.ConversionEndpoint = org.ConversionEndpoint
|
||||
data.License = h.Runtime.Product.License
|
||||
data.Storage = h.Runtime.StoreProvider.Type()
|
||||
|
||||
// Strip secrets
|
||||
data.AuthConfig = auth.StripAuthSecrets(h.Runtime, org.AuthProvider, org.AuthConfig)
|
||||
|
@ -213,6 +214,19 @@ func (h *Handler) rebuildSearchIndex(ctx domain.RequestContext) {
|
|||
for i := range docs {
|
||||
d := docs[i]
|
||||
|
||||
doc, err := h.Store.Document.Get(ctx, d)
|
||||
if err != nil {
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
at, err := h.Store.Attachment.GetAttachments(ctx, d)
|
||||
if err != nil {
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
h.Indexer.IndexDocument(ctx, doc, at)
|
||||
|
||||
pages, err := h.Store.Meta.GetDocumentPages(ctx, d)
|
||||
if err != nil {
|
||||
h.Runtime.Log.Error(method, err)
|
||||
|
|
|
@ -54,6 +54,10 @@ func (s Store) GetDocumentPages(ctx domain.RequestContext, documentID string) (p
|
|||
WHERE c_docid=? AND (c_status=0 OR ((c_status=4 OR c_status=2) AND c_relativeid=''))`),
|
||||
documentID)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
p = []page.Page{}
|
||||
}
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "failed to get instance document pages")
|
||||
}
|
||||
|
|
|
@ -33,7 +33,8 @@ type Store struct {
|
|||
func (s Store) AddPermission(ctx domain.RequestContext, r permission.Permission) (err error) {
|
||||
r.Created = time.Now().UTC()
|
||||
|
||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_permission (c_orgid, c_who, c_whoid, c_action, c_scope, c_location, c_refid, c_created) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"),
|
||||
_, err = ctx.Transaction.Exec(s.Bind(`INSERT INTO dmz_permission
|
||||
(c_orgid, c_who, c_whoid, c_action, c_scope, c_location, c_refid, c_created) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`),
|
||||
r.OrgID, string(r.Who), r.WhoID, string(r.Action), string(r.Scope), string(r.Location), r.RefID, r.Created)
|
||||
|
||||
if err != nil {
|
||||
|
@ -278,7 +279,7 @@ func (s Store) DeleteSpacePermissions(ctx domain.RequestContext, spaceID string)
|
|||
|
||||
// DeleteUserSpacePermissions removes all roles for the specified user, for the specified space.
|
||||
func (s Store) DeleteUserSpacePermissions(ctx domain.RequestContext, spaceID, userID string) (rows int64, err error) {
|
||||
sql := fmt.Sprintf("DELETE FROM dmz_permission WHERE c_orgid='%s' AND c_location='space' AND c_refid='%s' c_who='user' AND c_whoid='%s'",
|
||||
sql := fmt.Sprintf("DELETE FROM dmz_permission WHERE c_orgid='%s' AND c_location='space' AND c_refid='%s' AND c_who='user' AND c_whoid='%s'",
|
||||
ctx.OrgID, spaceID, userID)
|
||||
|
||||
return s.DeleteWhere(ctx.Transaction, sql)
|
||||
|
|
|
@ -120,10 +120,10 @@ func (s Store) DeletePin(ctx domain.RequestContext, id string) (rows int64, err
|
|||
|
||||
// DeletePinnedSpace removes any pins for specified space.
|
||||
func (s Store) DeletePinnedSpace(ctx domain.RequestContext, spaceID string) (rows int64, err error) {
|
||||
return s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_pin WHERE c_orgid=\"%s\" AND c_spaceid=\"%s\"", ctx.OrgID, spaceID))
|
||||
return s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_pin WHERE c_orgid='%s' AND c_spaceid='%s'", ctx.OrgID, spaceID))
|
||||
}
|
||||
|
||||
// DeletePinnedDocument removes any pins for specified document.
|
||||
func (s Store) DeletePinnedDocument(ctx domain.RequestContext, documentID string) (rows int64, err error) {
|
||||
return s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_pin WHERE c_orgid=\"%s\" AND c_docid=\"%s\"", ctx.OrgID, documentID))
|
||||
return s.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM dmz_pin WHERE c_orgid='%s' AND c_docid='%s'", ctx.OrgID, documentID))
|
||||
}
|
||||
|
|
|
@ -82,7 +82,12 @@ func (m *Indexer) IndexContent(ctx domain.RequestContext, p page.Page) {
|
|||
return
|
||||
}
|
||||
|
||||
ctx.Transaction.Commit()
|
||||
err = ctx.Transaction.Commit()
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
m.runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteContent removes all search entries for specific document content.
|
||||
|
|
|
@ -39,43 +39,68 @@ type Store struct {
|
|||
// IndexDocument adds search index entries for document inserting title, tags and attachments as
|
||||
// searchable items. Any existing document entries are removed.
|
||||
func (s Store) IndexDocument(ctx domain.RequestContext, doc doc.Document, a []attachment.Attachment) (err error) {
|
||||
method := "search.IndexDocument"
|
||||
|
||||
// remove previous search entries
|
||||
_, err = ctx.Transaction.Exec(s.Bind("DELETE FROM dmz_search WHERE c_orgid=? AND c_docid=? AND (c_itemtype='doc' OR c_itemtype='file' OR c_itemtype='tag')"),
|
||||
ctx.OrgID, doc.RefID)
|
||||
|
||||
if err != nil {
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
err = errors.Wrap(err, "execute delete document index entries")
|
||||
s.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
// insert doc title
|
||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_search (c_orgid, c_docid, c_itemid, c_itemtype, c_content) VALUES (?, ?, ?, ?, ?)"),
|
||||
ctx.OrgID, doc.RefID, "", "doc", doc.Name)
|
||||
if err != nil {
|
||||
if s.Runtime.StoreProvider.Type() == env.StoreTypePostgreSQL {
|
||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_search (c_orgid, c_docid, c_itemid, c_itemtype, c_content, c_token) VALUES (?, ?, ?, ?, ?, to_tsvector(?))"),
|
||||
ctx.OrgID, doc.RefID, "", "doc", doc.Name, doc.Name)
|
||||
|
||||
} else {
|
||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_search (c_orgid, c_docid, c_itemid, c_itemtype, c_content) VALUES (?, ?, ?, ?, ?)"),
|
||||
ctx.OrgID, doc.RefID, "", "doc", doc.Name)
|
||||
}
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
err = errors.Wrap(err, "execute insert document title entry")
|
||||
s.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
// insert doc tags
|
||||
tags := strings.Split(doc.Tags, "#")
|
||||
for _, t := range tags {
|
||||
t = strings.TrimSpace(t)
|
||||
if len(t) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_search (c_orgid, c_docid, c_itemid, c_itemtype, c_content) VALUES (?, ?, ?, ?, ?)"),
|
||||
ctx.OrgID, doc.RefID, "", "tag", t)
|
||||
if s.Runtime.StoreProvider.Type() == env.StoreTypePostgreSQL {
|
||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_search (c_orgid, c_docid, c_itemid, c_itemtype, c_content, c_token) VALUES (?, ?, ?, ?, ?, to_tsvector(?))"),
|
||||
ctx.OrgID, doc.RefID, "", "tag", t, t)
|
||||
|
||||
if err != nil {
|
||||
} else {
|
||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_search (c_orgid, c_docid, c_itemid, c_itemtype, c_content) VALUES (?, ?, ?, ?, ?)"),
|
||||
ctx.OrgID, doc.RefID, "", "tag", t)
|
||||
}
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
err = errors.Wrap(err, "execute insert document tag entry")
|
||||
s.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, file := range a {
|
||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_search (c_orgid, c_docid, c_itemid, c_itemtype, c_content) VALUES (?, ?, ?, ?, ?)"),
|
||||
ctx.OrgID, doc.RefID, file.RefID, "file", file.Filename)
|
||||
if s.Runtime.StoreProvider.Type() == env.StoreTypePostgreSQL {
|
||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_search (c_orgid, c_docid, c_itemid, c_itemtype, c_content, c_token) VALUES (?, ?, ?, ?, ?, to_tsvector(?))"),
|
||||
ctx.OrgID, doc.RefID, file.RefID, "file", file.Filename, file.Filename)
|
||||
|
||||
if err != nil {
|
||||
} else {
|
||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_search (c_orgid, c_docid, c_itemid, c_itemtype, c_content) VALUES (?, ?, ?, ?, ?)"),
|
||||
ctx.OrgID, doc.RefID, file.RefID, "file", file.Filename)
|
||||
}
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
err = errors.Wrap(err, "execute insert document file entry")
|
||||
s.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,11 +109,14 @@ func (s Store) IndexDocument(ctx domain.RequestContext, doc doc.Document, a []at
|
|||
|
||||
// DeleteDocument removes all search entries for document.
|
||||
func (s Store) DeleteDocument(ctx domain.RequestContext, ID string) (err error) {
|
||||
method := "search.DeleteDocument"
|
||||
|
||||
_, err = ctx.Transaction.Exec(s.Bind("DELETE FROM dmz_search WHERE c_orgid=? AND c_docid=?"),
|
||||
ctx.OrgID, ID)
|
||||
|
||||
if err != nil {
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
err = errors.Wrap(err, "execute delete document entries")
|
||||
s.Runtime.Log.Error(method, err)
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -97,6 +125,8 @@ func (s Store) DeleteDocument(ctx domain.RequestContext, ID string) (err error)
|
|||
// IndexContent adds search index entry for document context.
|
||||
// Any existing document entries are removed.
|
||||
func (s Store) IndexContent(ctx domain.RequestContext, p page.Page) (err error) {
|
||||
method := "search.IndexContent"
|
||||
|
||||
// we do not index pending pages
|
||||
if p.Status == workflow.ChangePending || p.Status == workflow.ChangePendingNew {
|
||||
return
|
||||
|
@ -106,28 +136,49 @@ func (s Store) IndexContent(ctx domain.RequestContext, p page.Page) (err error)
|
|||
_, err = ctx.Transaction.Exec(s.Bind("DELETE FROM dmz_search WHERE c_orgid=? AND c_docid=? AND c_itemid=? AND c_itemtype='page'"),
|
||||
ctx.OrgID, p.DocumentID, p.RefID)
|
||||
|
||||
if err != nil {
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
err = errors.Wrap(err, "execute delete document content entry")
|
||||
s.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
err = nil
|
||||
|
||||
// prepare content
|
||||
content, err := stringutil.HTML(p.Body).Text(false)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "search strip HTML failed")
|
||||
s.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
content = strings.TrimSpace(content)
|
||||
|
||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_search (c_orgid, c_docid, c_itemid, c_itemtype, c_content) VALUES (?, ?, ?, ?, ?)"),
|
||||
ctx.OrgID, p.DocumentID, p.RefID, "page", content)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "execute insert document content entry")
|
||||
}
|
||||
if s.Runtime.StoreProvider.Type() == env.StoreTypePostgreSQL {
|
||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_search (c_orgid, c_docid, c_itemid, c_itemtype, c_content, c_token) VALUES (?, ?, ?, ?, ?, to_tsvector(?))"),
|
||||
ctx.OrgID, p.DocumentID, p.RefID, "page", content, content)
|
||||
|
||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_search (c_orgid, c_docid, c_itemid, c_itemtype, c_content) VALUES (?, ?, ?, ?, ?)"),
|
||||
ctx.OrgID, p.DocumentID, p.RefID, "page", p.Name)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "execute insert document page title entry")
|
||||
} else {
|
||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_search (c_orgid, c_docid, c_itemid, c_itemtype, c_content) VALUES (?, ?, ?, ?, ?)"),
|
||||
ctx.OrgID, p.DocumentID, p.RefID, "page", content)
|
||||
}
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
err = errors.Wrap(err, "execute insert section content entry")
|
||||
s.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
err = nil
|
||||
|
||||
if s.Runtime.StoreProvider.Type() == env.StoreTypePostgreSQL {
|
||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_search (c_orgid, c_docid, c_itemid, c_itemtype, c_content, c_token) VALUES (?, ?, ?, ?, ?, to_tsvector(?))"),
|
||||
ctx.OrgID, p.DocumentID, p.RefID, "page", p.Name, p.Name)
|
||||
|
||||
} else {
|
||||
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_search (c_orgid, c_docid, c_itemid, c_itemtype, c_content) VALUES (?, ?, ?, ?, ?)"),
|
||||
ctx.OrgID, p.DocumentID, p.RefID, "page", p.Name)
|
||||
}
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
err = errors.Wrap(err, "execute insert section title entry")
|
||||
s.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -135,18 +186,23 @@ func (s Store) IndexContent(ctx domain.RequestContext, p page.Page) (err error)
|
|||
|
||||
// DeleteContent removes all search entries for specific document content.
|
||||
func (s Store) DeleteContent(ctx domain.RequestContext, pageID string) (err error) {
|
||||
method := "search.DeleteContent"
|
||||
|
||||
// remove all search entries
|
||||
var stmt1 *sqlx.Stmt
|
||||
stmt1, err = ctx.Transaction.Preparex(s.Bind("DELETE FROM dmz_search WHERE c_orgid=? AND c_itemid=? AND c_itemtype=?"))
|
||||
defer streamutil.Close(stmt1)
|
||||
if err != nil {
|
||||
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
err = errors.Wrap(err, "prepare delete document content entry")
|
||||
s.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = stmt1.Exec(ctx.OrgID, pageID, "page")
|
||||
if err != nil {
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
err = errors.Wrap(err, "execute delete document content entry")
|
||||
s.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -220,9 +276,17 @@ func (s Store) matchFullText(ctx domain.RequestContext, keywords, itemType strin
|
|||
|
||||
switch s.Runtime.StoreProvider.Type() {
|
||||
case env.StoreTypeMySQL:
|
||||
fts = " AND MATCH(s.c_content) AGAINST(? IN BOOLEAN MODE)"
|
||||
fts = " AND MATCH(s.c_content) AGAINST(? IN BOOLEAN MODE) "
|
||||
case env.StoreTypePostgreSQL:
|
||||
fts = ""
|
||||
// By default, we expect no Postgres full text search operators.
|
||||
parser := "plainto_tsquery"
|
||||
// If we find operators then we have to use correct query processor.
|
||||
operator := strings.ContainsAny(keywords, "!()&|*'`\":<->")
|
||||
if operator {
|
||||
parser = "to_tsquery"
|
||||
}
|
||||
|
||||
fts = fmt.Sprintf(" AND s.c_token @@ %s(?) ", parser)
|
||||
}
|
||||
|
||||
sql1 := s.Bind(`
|
||||
|
@ -279,7 +343,7 @@ func (s Store) matchLike(ctx domain.RequestContext, keywords, itemType string) (
|
|||
keywords = strings.Replace(keywords, "'", "", -1)
|
||||
keywords = strings.Replace(keywords, "\"", "", -1)
|
||||
keywords = strings.Replace(keywords, "%", "", -1)
|
||||
keywords = fmt.Sprintf("%%%s%%", keywords)
|
||||
keywords = fmt.Sprintf("%%%s%%", strings.ToLower(keywords))
|
||||
|
||||
sql1 := s.Bind(`SELECT
|
||||
s.id, s.c_orgid AS orgid, s.c_docid AS documentid, s.c_itemid AS itemid, s.c_itemtype AS itemtype,
|
||||
|
@ -304,7 +368,7 @@ func (s Store) matchLike(ctx domain.RequestContext, keywords, itemType string) (
|
|||
AND p.c_location='space' AND (r.c_userid=? OR r.c_userid='0')
|
||||
)
|
||||
)
|
||||
AND s.c_content LIKE ?`)
|
||||
AND LOWER(s.c_content) LIKE ?`)
|
||||
|
||||
err = s.Runtime.Db.Select(&r,
|
||||
sql1,
|
||||
|
|
|
@ -470,7 +470,13 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// If newly marked Everyone space, ensure everyone has permission
|
||||
if prev.Type != space.ScopePublic && sp.Type == space.ScopePublic {
|
||||
h.Store.Permission.DeleteUserSpacePermissions(ctx, sp.RefID, user.EveryoneUserID)
|
||||
_, err = h.Store.Permission.DeleteUserSpacePermissions(ctx, sp.RefID, user.EveryoneUserID)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
perm := permission.Permission{}
|
||||
perm.OrgID = sp.OrgID
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
@ -44,12 +45,13 @@ func (c *Context) Bind(sql string) string {
|
|||
func (c *Context) Delete(tx *sqlx.Tx, table string, id string) (rows int64, err error) {
|
||||
result, err := tx.Exec(c.Bind("DELETE FROM "+table+" WHERE c_refid=?"), id)
|
||||
|
||||
if err != nil {
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to delete row in table %s", table))
|
||||
return
|
||||
}
|
||||
|
||||
rows, err = result.RowsAffected()
|
||||
err = nil
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -58,12 +60,13 @@ func (c *Context) Delete(tx *sqlx.Tx, table string, id string) (rows int64, err
|
|||
func (c *Context) DeleteConstrained(tx *sqlx.Tx, table string, orgID, id string) (rows int64, err error) {
|
||||
result, err := tx.Exec(c.Bind("DELETE FROM "+table+" WHERE c_orgid=? AND c_refid=?"), orgID, id)
|
||||
|
||||
if err != nil {
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to delete row in table %s", table))
|
||||
return
|
||||
}
|
||||
|
||||
rows, err = result.RowsAffected()
|
||||
err = nil
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -72,12 +75,13 @@ func (c *Context) DeleteConstrained(tx *sqlx.Tx, table string, orgID, id string)
|
|||
func (c *Context) DeleteConstrainedWithID(tx *sqlx.Tx, table string, orgID, id string) (rows int64, err error) {
|
||||
result, err := tx.Exec(c.Bind("DELETE FROM "+table+" WHERE c_orgid=? AND id=?"), orgID, id)
|
||||
|
||||
if err != nil {
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to delete row in table %s", table))
|
||||
return
|
||||
}
|
||||
|
||||
rows, err = result.RowsAffected()
|
||||
err = nil
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -86,12 +90,13 @@ func (c *Context) DeleteConstrainedWithID(tx *sqlx.Tx, table string, orgID, id s
|
|||
func (c *Context) DeleteWhere(tx *sqlx.Tx, statement string) (rows int64, err error) {
|
||||
result, err := tx.Exec(statement)
|
||||
|
||||
if err != nil {
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to delete rows: %s", statement))
|
||||
return
|
||||
}
|
||||
|
||||
rows, err = result.RowsAffected()
|
||||
err = nil
|
||||
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue