github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/store/sqlstore/file_info_store.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package sqlstore 5 6 import ( 7 "database/sql" 8 "fmt" 9 "regexp" 10 "strconv" 11 "strings" 12 13 sq "github.com/Masterminds/squirrel" 14 "github.com/pkg/errors" 15 16 "github.com/masterhung0112/hk_server/v5/einterfaces" 17 "github.com/masterhung0112/hk_server/v5/model" 18 "github.com/masterhung0112/hk_server/v5/shared/mlog" 19 "github.com/masterhung0112/hk_server/v5/store" 20 ) 21 22 type SqlFileInfoStore struct { 23 *SqlStore 24 metrics einterfaces.MetricsInterface 25 queryFields []string 26 } 27 28 func (fs SqlFileInfoStore) ClearCaches() { 29 } 30 31 func newSqlFileInfoStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterface) store.FileInfoStore { 32 s := &SqlFileInfoStore{ 33 SqlStore: sqlStore, 34 metrics: metrics, 35 } 36 37 s.queryFields = []string{ 38 "FileInfo.Id", 39 "FileInfo.CreatorId", 40 "FileInfo.PostId", 41 "FileInfo.CreateAt", 42 "FileInfo.UpdateAt", 43 "FileInfo.DeleteAt", 44 "FileInfo.Path", 45 "FileInfo.ThumbnailPath", 46 "FileInfo.PreviewPath", 47 "FileInfo.Name", 48 "FileInfo.Extension", 49 "FileInfo.Size", 50 "FileInfo.MimeType", 51 "FileInfo.Width", 52 "FileInfo.Height", 53 "FileInfo.HasPreviewImage", 54 "FileInfo.MiniPreview", 55 "Coalesce(FileInfo.Content, '') AS Content", 56 "Coalesce(FileInfo.RemoteId, '') AS RemoteId", 57 } 58 59 for _, db := range sqlStore.GetAllConns() { 60 table := db.AddTableWithName(model.FileInfo{}, "FileInfo").SetKeys(false, "Id") 61 table.ColMap("Id").SetMaxSize(26) 62 table.ColMap("CreatorId").SetMaxSize(26) 63 table.ColMap("PostId").SetMaxSize(26) 64 table.ColMap("Path").SetMaxSize(512) 65 table.ColMap("ThumbnailPath").SetMaxSize(512) 66 table.ColMap("PreviewPath").SetMaxSize(512) 67 table.ColMap("Name").SetMaxSize(256) 68 table.ColMap("Content").SetMaxSize(0) 69 table.ColMap("Extension").SetMaxSize(64) 70 table.ColMap("MimeType").SetMaxSize(256) 71 table.ColMap("RemoteId").SetMaxSize(26) 72 } 73 74 return s 75 } 76 77 func (fs SqlFileInfoStore) createIndexesIfNotExists() { 78 fs.CreateIndexIfNotExists("idx_fileinfo_update_at", "FileInfo", "UpdateAt") 79 fs.CreateIndexIfNotExists("idx_fileinfo_create_at", "FileInfo", "CreateAt") 80 fs.CreateIndexIfNotExists("idx_fileinfo_delete_at", "FileInfo", "DeleteAt") 81 fs.CreateIndexIfNotExists("idx_fileinfo_postid_at", "FileInfo", "PostId") 82 fs.CreateIndexIfNotExists("idx_fileinfo_extension_at", "FileInfo", "Extension") 83 fs.CreateFullTextIndexIfNotExists("idx_fileinfo_name_txt", "FileInfo", "Name") 84 if fs.DriverName() == model.DATABASE_DRIVER_POSTGRES { 85 fs.CreateFullTextFuncIndexIfNotExists("idx_fileinfo_name_splitted", "FileInfo", "Translate(Name, '.,-', ' ')") 86 } 87 fs.CreateFullTextIndexIfNotExists("idx_fileinfo_content_txt", "FileInfo", "Content") 88 } 89 90 func (fs SqlFileInfoStore) Save(info *model.FileInfo) (*model.FileInfo, error) { 91 info.PreSave() 92 if err := info.IsValid(); err != nil { 93 return nil, err 94 } 95 96 if err := fs.GetMaster().Insert(info); err != nil { 97 return nil, errors.Wrap(err, "failed to save FileInfo") 98 } 99 return info, nil 100 } 101 102 func (fs SqlFileInfoStore) GetByIds(ids []string) ([]*model.FileInfo, error) { 103 query := fs.getQueryBuilder(). 104 Select(append(fs.queryFields, "COALESCE(P.ChannelId, '') as ChannelId")...). 105 From("FileInfo"). 106 LeftJoin("Posts as P ON FileInfo.PostId=P.Id"). 107 Where(sq.Eq{"FileInfo.Id": ids}). 108 Where(sq.Eq{"FileInfo.DeleteAt": 0}). 109 OrderBy("FileInfo.CreateAt DESC") 110 111 queryString, args, err := query.ToSql() 112 if err != nil { 113 return nil, errors.Wrap(err, "file_info_tosql") 114 } 115 116 var infos []*model.FileInfo 117 if _, err := fs.GetReplica().Select(&infos, queryString, args...); err != nil { 118 return nil, errors.Wrap(err, "failed to find FileInfos") 119 } 120 return infos, nil 121 } 122 123 func (fs SqlFileInfoStore) Upsert(info *model.FileInfo) (*model.FileInfo, error) { 124 info.PreSave() 125 if err := info.IsValid(); err != nil { 126 return nil, err 127 } 128 129 n, err := fs.GetMaster().Update(info) 130 if err != nil { 131 return nil, errors.Wrap(err, "failed to update FileInfo") 132 } 133 if n == 0 { 134 if err = fs.GetMaster().Insert(info); err != nil { 135 return nil, errors.Wrap(err, "failed to save FileInfo") 136 } 137 } 138 return info, nil 139 } 140 141 func (fs SqlFileInfoStore) get(id string, fromMaster bool) (*model.FileInfo, error) { 142 info := &model.FileInfo{} 143 144 query := fs.getQueryBuilder(). 145 Select(fs.queryFields...). 146 From("FileInfo"). 147 Where(sq.Eq{"Id": id}). 148 Where(sq.Eq{"DeleteAt": 0}) 149 150 queryString, args, err := query.ToSql() 151 if err != nil { 152 return nil, errors.Wrap(err, "file_info_tosql") 153 } 154 155 db := fs.GetReplica() 156 if fromMaster { 157 db = fs.GetMaster() 158 } 159 160 if err := db.SelectOne(info, queryString, args...); err != nil { 161 if err == sql.ErrNoRows { 162 return nil, store.NewErrNotFound("FileInfo", id) 163 } 164 return nil, errors.Wrapf(err, "failed to get FileInfo with id=%s", id) 165 } 166 return info, nil 167 } 168 169 func (fs SqlFileInfoStore) Get(id string) (*model.FileInfo, error) { 170 return fs.get(id, false) 171 } 172 173 func (fs SqlFileInfoStore) GetFromMaster(id string) (*model.FileInfo, error) { 174 return fs.get(id, true) 175 } 176 177 func (fs SqlFileInfoStore) GetWithOptions(page, perPage int, opt *model.GetFileInfosOptions) ([]*model.FileInfo, error) { 178 if perPage < 0 { 179 return nil, store.NewErrLimitExceeded("perPage", perPage, "value used in pagination while getting FileInfos") 180 } else if page < 0 { 181 return nil, store.NewErrLimitExceeded("page", page, "value used in pagination while getting FileInfos") 182 } 183 if perPage == 0 { 184 return nil, nil 185 } 186 187 if opt == nil { 188 opt = &model.GetFileInfosOptions{} 189 } 190 191 query := fs.getQueryBuilder(). 192 Select(fs.queryFields...). 193 From("FileInfo") 194 195 if len(opt.ChannelIds) > 0 { 196 query = query.Join("Posts ON FileInfo.PostId = Posts.Id"). 197 Where(sq.Eq{"Posts.ChannelId": opt.ChannelIds}) 198 } 199 200 if len(opt.UserIds) > 0 { 201 query = query.Where(sq.Eq{"FileInfo.CreatorId": opt.UserIds}) 202 } 203 204 if opt.Since > 0 { 205 query = query.Where(sq.GtOrEq{"FileInfo.CreateAt": opt.Since}) 206 } 207 208 if !opt.IncludeDeleted { 209 query = query.Where("FileInfo.DeleteAt = 0") 210 } 211 212 if opt.SortBy == "" { 213 opt.SortBy = model.FILEINFO_SORT_BY_CREATED 214 } 215 sortDirection := "ASC" 216 if opt.SortDescending { 217 sortDirection = "DESC" 218 } 219 220 switch opt.SortBy { 221 case model.FILEINFO_SORT_BY_CREATED: 222 query = query.OrderBy("FileInfo.CreateAt " + sortDirection) 223 case model.FILEINFO_SORT_BY_SIZE: 224 query = query.OrderBy("FileInfo.Size " + sortDirection) 225 default: 226 return nil, store.NewErrInvalidInput("FileInfo", "<sortOption>", opt.SortBy) 227 } 228 229 query = query.OrderBy("FileInfo.Id ASC") // secondary sort for sort stability 230 231 query = query.Limit(uint64(perPage)).Offset(uint64(perPage * page)) 232 233 queryString, args, err := query.ToSql() 234 if err != nil { 235 return nil, errors.Wrap(err, "file_info_tosql") 236 } 237 var infos []*model.FileInfo 238 if _, err := fs.GetReplica().Select(&infos, queryString, args...); err != nil { 239 return nil, errors.Wrap(err, "failed to find FileInfos") 240 } 241 return infos, nil 242 } 243 244 func (fs SqlFileInfoStore) GetByPath(path string) (*model.FileInfo, error) { 245 info := &model.FileInfo{} 246 247 query := fs.getQueryBuilder(). 248 Select(fs.queryFields...). 249 From("FileInfo"). 250 Where(sq.Eq{"Path": path}). 251 Where(sq.Eq{"DeleteAt": 0}). 252 Limit(1) 253 254 queryString, args, err := query.ToSql() 255 if err != nil { 256 return nil, errors.Wrap(err, "file_info_tosql") 257 } 258 259 if err := fs.GetReplica().SelectOne(info, queryString, args...); err != nil { 260 if err == sql.ErrNoRows { 261 return nil, store.NewErrNotFound("FileInfo", fmt.Sprintf("path=%s", path)) 262 } 263 264 return nil, errors.Wrapf(err, "failed to get FileInfo with path=%s", path) 265 } 266 return info, nil 267 } 268 269 func (fs SqlFileInfoStore) InvalidateFileInfosForPostCache(postId string, deleted bool) { 270 } 271 272 func (fs SqlFileInfoStore) GetForPost(postId string, readFromMaster, includeDeleted, allowFromCache bool) ([]*model.FileInfo, error) { 273 var infos []*model.FileInfo 274 275 dbmap := fs.GetReplica() 276 277 if readFromMaster { 278 dbmap = fs.GetMaster() 279 } 280 281 query := fs.getQueryBuilder(). 282 Select(fs.queryFields...). 283 From("FileInfo"). 284 Where(sq.Eq{"PostId": postId}). 285 OrderBy("CreateAt") 286 287 if !includeDeleted { 288 query = query.Where("DeleteAt = 0") 289 } 290 291 queryString, args, err := query.ToSql() 292 if err != nil { 293 return nil, errors.Wrap(err, "file_info_tosql") 294 } 295 296 if _, err := dbmap.Select(&infos, queryString, args...); err != nil { 297 return nil, errors.Wrapf(err, "failed to find FileInfos with postId=%s", postId) 298 } 299 return infos, nil 300 } 301 302 func (fs SqlFileInfoStore) GetForUser(userId string) ([]*model.FileInfo, error) { 303 var infos []*model.FileInfo 304 305 dbmap := fs.GetReplica() 306 307 query := fs.getQueryBuilder(). 308 Select(fs.queryFields...). 309 From("FileInfo"). 310 Where(sq.Eq{"CreatorId": userId}). 311 Where(sq.Eq{"DeleteAt": 0}). 312 OrderBy("CreateAt") 313 314 queryString, args, err := query.ToSql() 315 if err != nil { 316 return nil, errors.Wrap(err, "file_info_tosql") 317 } 318 319 if _, err := dbmap.Select(&infos, queryString, args...); err != nil { 320 return nil, errors.Wrapf(err, "failed to find FileInfos with creatorId=%s", userId) 321 } 322 return infos, nil 323 } 324 325 func (fs SqlFileInfoStore) AttachToPost(fileId, postId, creatorId string) error { 326 sqlResult, err := fs.GetMaster().Exec(` 327 UPDATE 328 FileInfo 329 SET 330 PostId = :PostId 331 WHERE 332 Id = :Id 333 AND PostId = '' 334 AND (CreatorId = :CreatorId OR CreatorId = 'nouser') 335 `, map[string]interface{}{ 336 "PostId": postId, 337 "Id": fileId, 338 "CreatorId": creatorId, 339 }) 340 if err != nil { 341 return errors.Wrapf(err, "failed to update FileInfo with id=%s and postId=%s", fileId, postId) 342 } 343 344 count, err := sqlResult.RowsAffected() 345 if err != nil { 346 // RowsAffected should never fail with the MySQL or Postgres drivers 347 return errors.Wrap(err, "unable to retrieve rows affected") 348 } else if count == 0 { 349 // Could not attach the file to the post 350 return store.NewErrInvalidInput("FileInfo", "<id, postId, creatorId>", fmt.Sprintf("<%s, %s, %s>", fileId, postId, creatorId)) 351 } 352 return nil 353 } 354 355 func (fs SqlFileInfoStore) SetContent(fileId, content string) error { 356 query := fs.getQueryBuilder(). 357 Update("FileInfo"). 358 Set("Content", content). 359 Where(sq.Eq{"Id": fileId}) 360 361 queryString, args, err := query.ToSql() 362 if err != nil { 363 return errors.Wrap(err, "file_info_tosql") 364 } 365 366 _, err = fs.GetMaster().Exec(queryString, args...) 367 if err != nil { 368 return errors.Wrapf(err, "failed to update FileInfo content with id=%s", fileId) 369 } 370 371 return nil 372 } 373 374 func (fs SqlFileInfoStore) DeleteForPost(postId string) (string, error) { 375 if _, err := fs.GetMaster().Exec( 376 `UPDATE 377 FileInfo 378 SET 379 DeleteAt = :DeleteAt 380 WHERE 381 PostId = :PostId`, map[string]interface{}{"DeleteAt": model.GetMillis(), "PostId": postId}); err != nil { 382 return "", errors.Wrapf(err, "failed to update FileInfo with postId=%s", postId) 383 } 384 return postId, nil 385 } 386 387 func (fs SqlFileInfoStore) PermanentDelete(fileId string) error { 388 if _, err := fs.GetMaster().Exec( 389 `DELETE FROM 390 FileInfo 391 WHERE 392 Id = :FileId`, map[string]interface{}{"FileId": fileId}); err != nil { 393 return errors.Wrapf(err, "failed to delete FileInfo with id=%s", fileId) 394 } 395 return nil 396 } 397 398 func (fs SqlFileInfoStore) PermanentDeleteBatch(endTime int64, limit int64) (int64, error) { 399 var query string 400 if fs.DriverName() == "postgres" { 401 query = "DELETE from FileInfo WHERE Id = any (array (SELECT Id FROM FileInfo WHERE CreateAt < :EndTime LIMIT :Limit))" 402 } else { 403 query = "DELETE from FileInfo WHERE CreateAt < :EndTime LIMIT :Limit" 404 } 405 406 sqlResult, err := fs.GetMaster().Exec(query, map[string]interface{}{"EndTime": endTime, "Limit": limit}) 407 if err != nil { 408 return 0, errors.Wrap(err, "failed to delete FileInfos in batch") 409 } 410 411 rowsAffected, err := sqlResult.RowsAffected() 412 if err != nil { 413 return 0, errors.Wrapf(err, "unable to retrieve rows affected") 414 } 415 416 return rowsAffected, nil 417 } 418 419 func (fs SqlFileInfoStore) PermanentDeleteByUser(userId string) (int64, error) { 420 query := "DELETE from FileInfo WHERE CreatorId = :CreatorId" 421 422 sqlResult, err := fs.GetMaster().Exec(query, map[string]interface{}{"CreatorId": userId}) 423 if err != nil { 424 return 0, errors.Wrapf(err, "failed to delete FileInfo with creatorId=%s", userId) 425 } 426 427 rowsAffected, err := sqlResult.RowsAffected() 428 if err != nil { 429 return 0, errors.Wrapf(err, "unable to retrieve rows affected") 430 } 431 432 return rowsAffected, nil 433 } 434 435 func (fs SqlFileInfoStore) Search(paramsList []*model.SearchParams, userId, teamId string, page, perPage int) (*model.FileInfoList, error) { 436 // Since we don't support paging for DB search, we just return nothing for later pages 437 if page > 0 { 438 return model.NewFileInfoList(), nil 439 } 440 if err := model.IsSearchParamsListValid(paramsList); err != nil { 441 return nil, err 442 } 443 query := fs.getQueryBuilder(). 444 Select(append(fs.queryFields, "Coalesce(P.ChannelId, '') AS ChannelId")...). 445 From("FileInfo"). 446 LeftJoin("Posts as P ON FileInfo.PostId=P.Id"). 447 LeftJoin("Channels as C ON C.Id=P.ChannelId"). 448 LeftJoin("ChannelMembers as CM ON C.Id=CM.ChannelId"). 449 Where(sq.Or{sq.Eq{"C.TeamId": teamId}, sq.Eq{"C.TeamId": ""}}). 450 Where(sq.Eq{"FileInfo.DeleteAt": 0}). 451 OrderBy("FileInfo.CreateAt DESC"). 452 Limit(100) 453 454 for _, params := range paramsList { 455 params.Terms = removeNonAlphaNumericUnquotedTerms(params.Terms, " ") 456 457 if !params.IncludeDeletedChannels { 458 query = query.Where(sq.Eq{"C.DeleteAt": 0}) 459 } 460 461 if !params.SearchWithoutUserId { 462 query = query.Where(sq.Eq{"CM.UserId": userId}) 463 } 464 465 if len(params.InChannels) != 0 { 466 query = query.Where(sq.Eq{"C.Id": params.InChannels}) 467 } 468 469 if len(params.Extensions) != 0 { 470 query = query.Where(sq.Eq{"FileInfo.Extension": params.Extensions}) 471 } 472 473 if len(params.ExcludedExtensions) != 0 { 474 query = query.Where(sq.NotEq{"FileInfo.Extension": params.ExcludedExtensions}) 475 } 476 477 if len(params.ExcludedChannels) != 0 { 478 query = query.Where(sq.NotEq{"C.Id": params.ExcludedChannels}) 479 } 480 481 if len(params.FromUsers) != 0 { 482 query = query.Where(sq.Eq{"FileInfo.CreatorId": params.FromUsers}) 483 } 484 485 if len(params.ExcludedUsers) != 0 { 486 query = query.Where(sq.NotEq{"FileInfo.CreatorId": params.ExcludedUsers}) 487 } 488 489 // handle after: before: on: filters 490 if params.OnDate != "" { 491 onDateStart, onDateEnd := params.GetOnDateMillis() 492 query = query.Where(sq.Expr("FileInfo.CreateAt BETWEEN ? AND ?", strconv.FormatInt(onDateStart, 10), strconv.FormatInt(onDateEnd, 10))) 493 } else { 494 if params.ExcludedDate != "" { 495 excludedDateStart, excludedDateEnd := params.GetExcludedDateMillis() 496 query = query.Where(sq.Expr("FileInfo.CreateAt NOT BETWEEN ? AND ?", strconv.FormatInt(excludedDateStart, 10), strconv.FormatInt(excludedDateEnd, 10))) 497 } 498 499 if params.AfterDate != "" { 500 afterDate := params.GetAfterDateMillis() 501 query = query.Where(sq.GtOrEq{"FileInfo.CreateAt": strconv.FormatInt(afterDate, 10)}) 502 } 503 504 if params.BeforeDate != "" { 505 beforeDate := params.GetBeforeDateMillis() 506 query = query.Where(sq.LtOrEq{"FileInfo.CreateAt": strconv.FormatInt(beforeDate, 10)}) 507 } 508 509 if params.ExcludedAfterDate != "" { 510 afterDate := params.GetExcludedAfterDateMillis() 511 query = query.Where(sq.Lt{"FileInfo.CreateAt": strconv.FormatInt(afterDate, 10)}) 512 } 513 514 if params.ExcludedBeforeDate != "" { 515 beforeDate := params.GetExcludedBeforeDateMillis() 516 query = query.Where(sq.Gt{"FileInfo.CreateAt": strconv.FormatInt(beforeDate, 10)}) 517 } 518 } 519 520 terms := params.Terms 521 excludedTerms := params.ExcludedTerms 522 523 // these chars have special meaning and can be treated as spaces 524 for _, c := range specialSearchChar { 525 terms = strings.Replace(terms, c, " ", -1) 526 excludedTerms = strings.Replace(excludedTerms, c, " ", -1) 527 } 528 529 if terms == "" && excludedTerms == "" { 530 // we've already confirmed that we have a channel or user to search for 531 } else if fs.DriverName() == model.DATABASE_DRIVER_POSTGRES { 532 // Parse text for wildcards 533 if wildcard, err := regexp.Compile(`\*($| )`); err == nil { 534 terms = wildcard.ReplaceAllLiteralString(terms, ":* ") 535 excludedTerms = wildcard.ReplaceAllLiteralString(excludedTerms, ":* ") 536 } 537 538 excludeClause := "" 539 if excludedTerms != "" { 540 excludeClause = " & !(" + strings.Join(strings.Fields(excludedTerms), " | ") + ")" 541 } 542 543 queryTerms := "" 544 if params.OrTerms { 545 queryTerms = "(" + strings.Join(strings.Fields(terms), " | ") + ")" + excludeClause 546 } else { 547 queryTerms = "(" + strings.Join(strings.Fields(terms), " & ") + ")" + excludeClause 548 } 549 550 query = query.Where(sq.Or{ 551 sq.Expr("to_tsvector('english', FileInfo.Name) @@ to_tsquery('english', ?)", queryTerms), 552 sq.Expr("to_tsvector('english', Translate(FileInfo.Name, '.,-', ' ')) @@ to_tsquery('english', ?)", queryTerms), 553 sq.Expr("to_tsvector('english', FileInfo.Content) @@ to_tsquery('english', ?)", queryTerms), 554 }) 555 } else if fs.DriverName() == model.DATABASE_DRIVER_MYSQL { 556 var err error 557 terms, err = removeMysqlStopWordsFromTerms(terms) 558 if err != nil { 559 return nil, errors.Wrap(err, "failed to remove Mysql stop-words from terms") 560 } 561 562 if terms == "" { 563 return model.NewFileInfoList(), nil 564 } 565 566 excludeClause := "" 567 if excludedTerms != "" { 568 excludeClause = " -(" + excludedTerms + ")" 569 } 570 571 queryTerms := "" 572 if params.OrTerms { 573 queryTerms = terms + excludeClause 574 } else { 575 splitTerms := []string{} 576 for _, t := range strings.Fields(terms) { 577 splitTerms = append(splitTerms, "+"+t) 578 } 579 queryTerms = strings.Join(splitTerms, " ") + excludeClause 580 } 581 query = query.Where(sq.Or{ 582 sq.Expr("MATCH (FileInfo.Name) AGAINST (? IN BOOLEAN MODE)", queryTerms), 583 sq.Expr("MATCH (FileInfo.Content) AGAINST (? IN BOOLEAN MODE)", queryTerms), 584 }) 585 } 586 } 587 588 queryString, args, err := query.ToSql() 589 if err != nil { 590 return nil, errors.Wrap(err, "file_info_tosql") 591 } 592 593 list := model.NewFileInfoList() 594 fileInfos := []*model.FileInfo{} 595 _, err = fs.GetSearchReplica().Select(&fileInfos, queryString, args...) 596 if err != nil { 597 mlog.Warn("Query error searching files.", mlog.Err(err)) 598 // Don't return the error to the caller as it is of no use to the user. Instead return an empty set of search results. 599 } else { 600 for _, f := range fileInfos { 601 list.AddFileInfo(f) 602 list.AddOrder(f.Id) 603 } 604 } 605 list.MakeNonNil() 606 return list, nil 607 } 608 609 func (fs SqlFileInfoStore) CountAll() (int64, error) { 610 query := fs.getQueryBuilder(). 611 Select("COUNT(*)"). 612 From("FileInfo"). 613 Where("DeleteAt = 0") 614 615 queryString, args, err := query.ToSql() 616 if err != nil { 617 return int64(0), errors.Wrap(err, "count_tosql") 618 } 619 620 count, err := fs.GetReplica().SelectInt(queryString, args...) 621 if err != nil { 622 return int64(0), errors.Wrap(err, "failed to count Files") 623 } 624 return count, nil 625 } 626 627 func (fs SqlFileInfoStore) GetFilesBatchForIndexing(startTime, endTime int64, limit int) ([]*model.FileForIndexing, error) { 628 var files []*model.FileForIndexing 629 sql, args, _ := fs.getQueryBuilder(). 630 Select(append(fs.queryFields, "Coalesce(p.ChannelId, '') AS ChannelId")...). 631 From("FileInfo"). 632 LeftJoin("Posts AS p ON FileInfo.PostId = p.Id"). 633 Where(sq.GtOrEq{"FileInfo.CreateAt": startTime}). 634 Where(sq.Lt{"FileInfo.CreateAt": endTime}). 635 OrderBy("FileInfo.CreateAt"). 636 Limit(uint64(limit)). 637 ToSql() 638 _, err := fs.GetSearchReplica().Select(&files, sql, args...) 639 if err != nil { 640 return nil, errors.Wrap(err, "failed to find Files") 641 } 642 643 return files, nil 644 }