github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/common/recalc.go (about)

     1  package common
     2  
     3  import (
     4  	"database/sql"
     5  	//"log"
     6  	"strconv"
     7  
     8  	qgen "github.com/Azareal/Gosora/query_gen"
     9  )
    10  
    11  var Recalc RecalcInt
    12  
    13  type RecalcInt interface {
    14  	Replies() (count int, err error)
    15  	Forums() (count int, err error)
    16  	Subscriptions() (count int, err error)
    17  	ActivityStream() (count int, err error)
    18  	Users() error
    19  	Attachments() (count int, err error)
    20  }
    21  
    22  type DefaultRecalc struct {
    23  	getActivitySubscriptions *sql.Stmt
    24  	getActivityStream        *sql.Stmt
    25  	getAttachments           *sql.Stmt
    26  	getTopicCount            *sql.Stmt
    27  	resetTopicCount          *sql.Stmt
    28  }
    29  
    30  func NewDefaultRecalc(acc *qgen.Accumulator) (*DefaultRecalc, error) {
    31  	return &DefaultRecalc{
    32  		getActivitySubscriptions: acc.Select("activity_subscriptions").Columns("targetID,targetType").Prepare(),
    33  		getActivityStream:        acc.Select("activity_stream").Columns("asid,event,elementID,elementType,extra").Prepare(),
    34  		getAttachments:           acc.Select("attachments").Columns("attachID,originID,originTable").Prepare(),
    35  		getTopicCount:            acc.Count("topics").Where("parentID=?").Prepare(),
    36  		//resetTopicCount:          acc.SimpleUpdateSelect("forums", "topicCount = tc", "topics", "count(*) as tc", "parentID=?", "", ""),
    37  		// TODO: Avoid using RawPrepare
    38  		resetTopicCount: acc.RawPrepare("UPDATE forums, (SELECT COUNT(*) as tc FROM topics WHERE parentID=?) AS src SET forums.topicCount=src.tc WHERE forums.fid=?"),
    39  	}, acc.FirstError()
    40  }
    41  
    42  func (s *DefaultRecalc) Replies() (count int, err error) {
    43  	var ltid int
    44  	err = Rstore.Each(func(r *Reply) error {
    45  		if ltid == r.ParentID && r.ParentID > 0 {
    46  			//return nil
    47  		}
    48  		if !Topics.Exists(r.ParentID) {
    49  			// TODO: Delete in chunks not one at a time?
    50  			if err := r.Delete(); err != nil {
    51  				return err
    52  			}
    53  			count++
    54  		}
    55  		return nil
    56  	})
    57  	return count, err
    58  }
    59  
    60  func (s *DefaultRecalc) Forums() (count int, err error) {
    61  	err = Forums.Each(func(f *Forum) error {
    62  		_, err := s.resetTopicCount.Exec(f.ID, f.ID)
    63  		if err != nil {
    64  			return err
    65  		}
    66  		count++
    67  		return nil
    68  	})
    69  	return count, err
    70  }
    71  
    72  func (s *DefaultRecalc) Subscriptions() (count int, err error) {
    73  	err = eachall(s.getActivitySubscriptions, func(r *sql.Rows) error {
    74  		var targetID int
    75  		var targetType string
    76  		err := r.Scan(&targetID, &targetType)
    77  		if err != nil {
    78  			return err
    79  		}
    80  		if targetType == "topic" {
    81  			if !Topics.Exists(targetID) {
    82  				// TODO: Delete in chunks not one at a time?
    83  				err := Subscriptions.DeleteResource(targetID, targetType)
    84  				if err != nil {
    85  					return err
    86  				}
    87  				count++
    88  			}
    89  		}
    90  		return nil
    91  	})
    92  	return count, err
    93  }
    94  
    95  type Existable interface {
    96  	Exists(id int) bool
    97  }
    98  
    99  func (s *DefaultRecalc) ActivityStream() (count int, err error) {
   100  	err = eachall(s.getActivityStream, func(r *sql.Rows) error {
   101  		var asid, elementID int
   102  		var event, elementType, extra string
   103  		err := r.Scan(&asid, &event, &elementID, &elementType, &extra)
   104  		if err != nil {
   105  			return err
   106  		}
   107  		//log.Print("asid:",asid)
   108  		var s Existable
   109  		switch elementType {
   110  		case "user":
   111  			if event == "reply" {
   112  				extraI, _ := strconv.Atoi(extra)
   113  				if extraI > 0 {
   114  					s = Prstore
   115  					elementID = extraI
   116  				} else {
   117  					return nil
   118  				}
   119  			} else {
   120  				return nil
   121  			}
   122  		case "topic":
   123  			s = Topics
   124  			// TODO: Delete reply events with an empty extra field
   125  			if event == "reply" {
   126  				extraI, _ := strconv.Atoi(extra)
   127  				if extraI > 0 {
   128  					s = Rstore
   129  					elementID = extraI
   130  				}
   131  			}
   132  		case "post":
   133  			s = Rstore
   134  			// TODO: Add a TopicExistsByReplyID for efficiency
   135  			/*_, err = TopicByReplyID(elementID)
   136  			if err == sql.ErrNoRows {
   137  				// TODO: Delete in chunks not one at a time?
   138  				err := Activity.Delete(asid)
   139  				if err != nil {
   140  					return err
   141  				}
   142  				count++
   143  			} else if err != nil {
   144  				return err
   145  			}*/
   146  		default:
   147  			return nil
   148  		}
   149  		if !s.Exists(elementID) {
   150  			// TODO: Delete in chunks not one at a time?
   151  			err := Activity.Delete(asid)
   152  			if err != nil {
   153  				return err
   154  			}
   155  			count++
   156  		}
   157  		return nil
   158  	})
   159  	return count, err
   160  }
   161  
   162  func (s *DefaultRecalc) Users() error {
   163  	return Users.Each(func(u *User) error {
   164  		return u.RecalcPostStats()
   165  	})
   166  }
   167  
   168  func (s *DefaultRecalc) Attachments() (count int, err error) {
   169  	err = eachall(s.getAttachments, func(r *sql.Rows) error {
   170  		var aid, originID int
   171  		var originType string
   172  		err := r.Scan(&aid, &originID, &originType)
   173  		if err != nil {
   174  			return err
   175  		}
   176  		var s Existable
   177  		switch originType {
   178  		case "topics":
   179  			s = Topics
   180  		case "replies":
   181  			s = Rstore
   182  		default:
   183  			return nil
   184  		}
   185  		if !s.Exists(originID) {
   186  			// TODO: Delete in chunks not one at a time?
   187  			err := Attachments.Delete(aid)
   188  			if err != nil {
   189  				return err
   190  			}
   191  			count++
   192  		}
   193  		return nil
   194  	})
   195  	return count, err
   196  }