github.com/go-generalize/volcago@v1.7.0/generator/testfiles/not_auto/sub_task_gen.go (about) 1 // Code generated by volcago. DO NOT EDIT. 2 // generated version: devel 3 package model 4 5 import ( 6 "context" 7 8 "cloud.google.com/go/firestore" 9 "golang.org/x/xerrors" 10 "google.golang.org/api/iterator" 11 "google.golang.org/grpc/codes" 12 "google.golang.org/grpc/status" 13 ) 14 15 //go:generate mockgen -source $GOFILE -destination mock/mock_sub_task_gen/mock_sub_task_gen.go 16 17 // SubTaskRepository - Repository of SubTask 18 type SubTaskRepository interface { 19 // Single 20 Get(ctx context.Context, id string, opts ...GetOption) (*SubTask, error) 21 GetWithDoc(ctx context.Context, doc *firestore.DocumentRef, opts ...GetOption) (*SubTask, error) 22 Insert(ctx context.Context, subject *SubTask) (_ string, err error) 23 Update(ctx context.Context, subject *SubTask) (err error) 24 StrictUpdate(ctx context.Context, id string, param *SubTaskUpdateParam, opts ...firestore.Precondition) error 25 Delete(ctx context.Context, subject *SubTask, opts ...DeleteOption) (err error) 26 DeleteByID(ctx context.Context, id string, opts ...DeleteOption) (err error) 27 // Multiple 28 GetMulti(ctx context.Context, ids []string, opts ...GetOption) ([]*SubTask, error) 29 InsertMulti(ctx context.Context, subjects []*SubTask) (_ []string, er error) 30 UpdateMulti(ctx context.Context, subjects []*SubTask) (er error) 31 DeleteMulti(ctx context.Context, subjects []*SubTask, opts ...DeleteOption) (er error) 32 DeleteMultiByIDs(ctx context.Context, ids []string, opts ...DeleteOption) (er error) 33 // Single(Transaction) 34 GetWithTx(tx *firestore.Transaction, id string, opts ...GetOption) (*SubTask, error) 35 GetWithDocWithTx(tx *firestore.Transaction, doc *firestore.DocumentRef, opts ...GetOption) (*SubTask, error) 36 InsertWithTx(ctx context.Context, tx *firestore.Transaction, subject *SubTask) (_ string, err error) 37 UpdateWithTx(ctx context.Context, tx *firestore.Transaction, subject *SubTask) (err error) 38 StrictUpdateWithTx(tx *firestore.Transaction, id string, param *SubTaskUpdateParam, opts ...firestore.Precondition) error 39 DeleteWithTx(ctx context.Context, tx *firestore.Transaction, subject *SubTask, opts ...DeleteOption) (err error) 40 DeleteByIDWithTx(ctx context.Context, tx *firestore.Transaction, id string, opts ...DeleteOption) (err error) 41 // Multiple(Transaction) 42 GetMultiWithTx(tx *firestore.Transaction, ids []string, opts ...GetOption) ([]*SubTask, error) 43 InsertMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*SubTask) (_ []string, er error) 44 UpdateMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*SubTask) (er error) 45 DeleteMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*SubTask, opts ...DeleteOption) (er error) 46 DeleteMultiByIDsWithTx(ctx context.Context, tx *firestore.Transaction, ids []string, opts ...DeleteOption) (er error) 47 // Search 48 Search(ctx context.Context, param *SubTaskSearchParam, q *firestore.Query) ([]*SubTask, error) 49 SearchWithTx(tx *firestore.Transaction, param *SubTaskSearchParam, q *firestore.Query) ([]*SubTask, error) 50 SearchByParam(ctx context.Context, param *SubTaskSearchParam) ([]*SubTask, *PagingResult, error) 51 SearchByParamWithTx(tx *firestore.Transaction, param *SubTaskSearchParam) ([]*SubTask, *PagingResult, error) 52 // misc 53 GetCollection() *firestore.CollectionRef 54 GetCollectionName() string 55 GetDocRef(id string) *firestore.DocumentRef 56 RunInTransaction() func(ctx context.Context, f func(context.Context, *firestore.Transaction) error, opts ...firestore.TransactionOption) (err error) 57 SetParentDoc(doc *firestore.DocumentRef) 58 NewRepositoryByParent(doc *firestore.DocumentRef) SubTaskRepository 59 Free() 60 } 61 62 // SubTaskRepositoryMiddleware - middleware of SubTaskRepository 63 type SubTaskRepositoryMiddleware interface { 64 BeforeInsert(ctx context.Context, subject *SubTask) (bool, error) 65 BeforeUpdate(ctx context.Context, old, subject *SubTask) (bool, error) 66 BeforeDelete(ctx context.Context, subject *SubTask, opts ...DeleteOption) (bool, error) 67 BeforeDeleteByID(ctx context.Context, ids []string, opts ...DeleteOption) (bool, error) 68 } 69 70 type subTaskRepository struct { 71 collectionName string 72 firestoreClient *firestore.Client 73 parentDocument *firestore.DocumentRef 74 collectionGroup *firestore.CollectionGroupRef 75 middleware []SubTaskRepositoryMiddleware 76 uniqueRepository *uniqueRepository 77 } 78 79 // NewSubTaskRepository - constructor 80 func NewSubTaskRepository(firestoreClient *firestore.Client, parentDocument *firestore.DocumentRef, middleware ...SubTaskRepositoryMiddleware) SubTaskRepository { 81 return &subTaskRepository{ 82 collectionName: "SubTask", 83 firestoreClient: firestoreClient, 84 parentDocument: parentDocument, 85 middleware: middleware, 86 uniqueRepository: newUniqueRepository(firestoreClient, "SubTask"), 87 } 88 } 89 90 // NewSubTaskCollectionGroupRepository - constructor 91 func NewSubTaskCollectionGroupRepository(firestoreClient *firestore.Client) SubTaskRepository { 92 return &subTaskRepository{ 93 collectionName: "SubTask", 94 collectionGroup: firestoreClient.CollectionGroup("SubTask"), 95 } 96 } 97 98 func (repo *subTaskRepository) beforeInsert(ctx context.Context, subject *SubTask) error { 99 repo.uniqueRepository.setMiddleware(ctx) 100 err := repo.uniqueRepository.CheckUnique(ctx, nil, subject) 101 if err != nil { 102 return xerrors.Errorf("unique.middleware error: %w", err) 103 } 104 105 for _, m := range repo.middleware { 106 c, err := m.BeforeInsert(ctx, subject) 107 if err != nil { 108 return xerrors.Errorf("beforeInsert.middleware error: %w", err) 109 } 110 if !c { 111 continue 112 } 113 } 114 115 return nil 116 } 117 118 func (repo *subTaskRepository) beforeUpdate(ctx context.Context, old, subject *SubTask) error { 119 if ctx.Value(transactionInProgressKey{}) != nil && old == nil { 120 var err error 121 doc := repo.GetDocRef(subject.ID) 122 old, err = repo.get(context.Background(), doc) 123 if err != nil { 124 if status.Code(err) == codes.NotFound { 125 return ErrNotFound 126 } 127 return xerrors.Errorf("error in Get method: %w", err) 128 } 129 } 130 repo.uniqueRepository.setMiddleware(ctx) 131 err := repo.uniqueRepository.CheckUnique(ctx, old, subject) 132 if err != nil { 133 return xerrors.Errorf("unique.middleware error: %w", err) 134 } 135 136 for _, m := range repo.middleware { 137 c, err := m.BeforeUpdate(ctx, old, subject) 138 if err != nil { 139 return xerrors.Errorf("beforeUpdate.middleware error: %w", err) 140 } 141 if !c { 142 continue 143 } 144 } 145 146 return nil 147 } 148 149 func (repo *subTaskRepository) beforeDelete(ctx context.Context, subject *SubTask, opts ...DeleteOption) error { 150 repo.uniqueRepository.setMiddleware(ctx) 151 err := repo.uniqueRepository.DeleteUnique(ctx, subject) 152 if err != nil { 153 return xerrors.Errorf("unique.middleware error: %w", err) 154 } 155 156 for _, m := range repo.middleware { 157 c, err := m.BeforeDelete(ctx, subject, opts...) 158 if err != nil { 159 return xerrors.Errorf("beforeDelete.middleware error: %w", err) 160 } 161 if !c { 162 continue 163 } 164 } 165 166 return nil 167 } 168 169 // GetCollection - *firestore.CollectionRef getter 170 func (repo *subTaskRepository) GetCollection() *firestore.CollectionRef { 171 if repo.collectionGroup != nil { 172 return nil 173 } 174 return repo.parentDocument.Collection(repo.collectionName) 175 } 176 177 // GetCollectionName - CollectionName getter 178 func (repo *subTaskRepository) GetCollectionName() string { 179 return repo.collectionName 180 } 181 182 // GetDocRef - *firestore.DocumentRef getter 183 func (repo *subTaskRepository) GetDocRef(id string) *firestore.DocumentRef { 184 if repo.collectionGroup != nil { 185 return nil 186 } 187 return repo.GetCollection().Doc(id) 188 } 189 190 // RunInTransaction - (*firestore.Client).RunTransaction getter 191 func (repo *subTaskRepository) RunInTransaction() func(ctx context.Context, f func(context.Context, *firestore.Transaction) error, opts ...firestore.TransactionOption) (err error) { 192 return repo.firestoreClient.RunTransaction 193 } 194 195 // SetParentDoc - parent document setter 196 func (repo *subTaskRepository) SetParentDoc(doc *firestore.DocumentRef) { 197 if doc == nil { 198 return 199 } 200 repo.parentDocument = doc 201 } 202 203 // NewRepositoryByParent - Returns new instance with setting parent document 204 func (repo subTaskRepository) NewRepositoryByParent(doc *firestore.DocumentRef) SubTaskRepository { 205 if doc == nil { 206 return &repo 207 } 208 repo.parentDocument = doc 209 return &repo 210 } 211 212 // Free - parent document releaser 213 func (repo *subTaskRepository) Free() { 214 repo.parentDocument = nil 215 } 216 217 // SubTaskSearchParam - params for search 218 type SubTaskSearchParam struct { 219 ID *QueryChainer 220 IsSubCollection *QueryChainer 221 222 CursorKey string 223 CursorLimit int 224 } 225 226 // SubTaskUpdateParam - params for strict updates 227 type SubTaskUpdateParam struct { 228 IsSubCollection interface{} 229 } 230 231 // Search - search documents 232 // The third argument is firestore.Query, basically you can pass nil 233 func (repo *subTaskRepository) Search(ctx context.Context, param *SubTaskSearchParam, q *firestore.Query) ([]*SubTask, error) { 234 return repo.search(ctx, param, q) 235 } 236 237 // SearchByParam - search documents by search param 238 func (repo *subTaskRepository) SearchByParam(ctx context.Context, param *SubTaskSearchParam) ([]*SubTask, *PagingResult, error) { 239 return repo.searchByParam(ctx, param) 240 } 241 242 // Get - get `SubTask` by `SubTask.ID` 243 func (repo *subTaskRepository) Get(ctx context.Context, id string, opts ...GetOption) (*SubTask, error) { 244 if repo.collectionGroup != nil { 245 return nil, ErrNotAvailableCG 246 } 247 doc := repo.GetDocRef(id) 248 return repo.get(ctx, doc, opts...) 249 } 250 251 // GetWithDoc - get `SubTask` by *firestore.DocumentRef 252 func (repo *subTaskRepository) GetWithDoc(ctx context.Context, doc *firestore.DocumentRef, opts ...GetOption) (*SubTask, error) { 253 if repo.collectionGroup != nil { 254 return nil, ErrNotAvailableCG 255 } 256 return repo.get(ctx, doc, opts...) 257 } 258 259 // Insert - insert of `SubTask` 260 func (repo *subTaskRepository) Insert(ctx context.Context, subject *SubTask) (_ string, err error) { 261 if repo.collectionGroup != nil { 262 return "", ErrNotAvailableCG 263 } 264 if err := repo.beforeInsert(ctx, subject); err != nil { 265 return "", xerrors.Errorf("before insert error: %w", err) 266 } 267 268 return repo.insert(ctx, subject) 269 } 270 271 // Update - update of `SubTask` 272 func (repo *subTaskRepository) Update(ctx context.Context, subject *SubTask) (err error) { 273 if repo.collectionGroup != nil { 274 return ErrNotAvailableCG 275 } 276 doc := repo.GetDocRef(subject.ID) 277 278 old, err := repo.get(ctx, doc) 279 if err != nil { 280 if status.Code(err) == codes.NotFound { 281 return ErrNotFound 282 } 283 return xerrors.Errorf("error in Get method: %w", err) 284 } 285 286 if err := repo.beforeUpdate(ctx, old, subject); err != nil { 287 return xerrors.Errorf("before update error: %w", err) 288 } 289 290 return repo.update(ctx, subject) 291 } 292 293 // StrictUpdate - strict update of `SubTask` 294 func (repo *subTaskRepository) StrictUpdate(ctx context.Context, id string, param *SubTaskUpdateParam, opts ...firestore.Precondition) error { 295 if repo.collectionGroup != nil { 296 return ErrNotAvailableCG 297 } 298 return repo.strictUpdate(ctx, id, param, opts...) 299 } 300 301 // Delete - delete of `SubTask` 302 func (repo *subTaskRepository) Delete(ctx context.Context, subject *SubTask, opts ...DeleteOption) (err error) { 303 if repo.collectionGroup != nil { 304 return ErrNotAvailableCG 305 } 306 if err := repo.beforeDelete(ctx, subject, opts...); err != nil { 307 return xerrors.Errorf("before delete error: %w", err) 308 } 309 310 return repo.deleteByID(ctx, subject.ID) 311 } 312 313 // DeleteByID - delete `SubTask` by `SubTask.ID` 314 func (repo *subTaskRepository) DeleteByID(ctx context.Context, id string, opts ...DeleteOption) (err error) { 315 if repo.collectionGroup != nil { 316 return ErrNotAvailableCG 317 } 318 subject, err := repo.Get(ctx, id) 319 if err != nil { 320 return xerrors.Errorf("error in Get method: %w", err) 321 } 322 323 if err := repo.beforeDelete(ctx, subject, opts...); err != nil { 324 return xerrors.Errorf("before delete error: %w", err) 325 } 326 327 return repo.Delete(ctx, subject, opts...) 328 } 329 330 // GetMulti - get `SubTask` in bulk by array of `SubTask.ID` 331 func (repo *subTaskRepository) GetMulti(ctx context.Context, ids []string, opts ...GetOption) ([]*SubTask, error) { 332 if repo.collectionGroup != nil { 333 return nil, ErrNotAvailableCG 334 } 335 return repo.getMulti(ctx, ids, opts...) 336 } 337 338 // InsertMulti - bulk insert of `SubTask` 339 func (repo *subTaskRepository) InsertMulti(ctx context.Context, subjects []*SubTask) (_ []string, er error) { 340 if repo.collectionGroup != nil { 341 return nil, ErrNotAvailableCG 342 } 343 344 ids := make([]string, 0, len(subjects)) 345 batches := make([]*firestore.WriteBatch, 0) 346 batch := repo.firestoreClient.Batch() 347 collect := repo.GetCollection() 348 349 for i, subject := range subjects { 350 var ref *firestore.DocumentRef 351 if subject.ID == "" { 352 ref = collect.NewDoc() 353 subject.ID = ref.ID 354 } else { 355 ref = collect.Doc(subject.ID) 356 if s, err := ref.Get(ctx); err == nil { 357 return nil, xerrors.Errorf("already exists [%v]: %#v", subject.ID, s) 358 } 359 } 360 361 if err := repo.beforeInsert(ctx, subject); err != nil { 362 return nil, xerrors.Errorf("before insert error(%d) [%v]: %w", i, subject.ID, err) 363 } 364 365 batch.Set(ref, subject) 366 ids = append(ids, ref.ID) 367 i++ 368 if (i%500) == 0 && len(subjects) != i { 369 batches = append(batches, batch) 370 batch = repo.firestoreClient.Batch() 371 } 372 } 373 batches = append(batches, batch) 374 375 for _, b := range batches { 376 if _, err := b.Commit(ctx); err != nil { 377 return nil, xerrors.Errorf("error in Commit method: %w", err) 378 } 379 } 380 381 return ids, nil 382 } 383 384 // UpdateMulti - bulk update of `SubTask` 385 func (repo *subTaskRepository) UpdateMulti(ctx context.Context, subjects []*SubTask) (er error) { 386 if repo.collectionGroup != nil { 387 return ErrNotAvailableCG 388 } 389 390 batches := make([]*firestore.WriteBatch, 0) 391 batch := repo.firestoreClient.Batch() 392 collect := repo.GetCollection() 393 394 for i, subject := range subjects { 395 ref := collect.Doc(subject.ID) 396 snapShot, err := ref.Get(ctx) 397 if err != nil { 398 if status.Code(err) == codes.NotFound { 399 return xerrors.Errorf("not found [%v]: %w", subject.ID, err) 400 } 401 return xerrors.Errorf("error in Get method [%v]: %w", subject.ID, err) 402 } 403 404 old := new(SubTask) 405 if err = snapShot.DataTo(&old); err != nil { 406 return xerrors.Errorf("error in DataTo method: %w", err) 407 } 408 409 if err := repo.beforeUpdate(ctx, old, subject); err != nil { 410 return xerrors.Errorf("before update error(%d) [%v]: %w", i, subject.ID, err) 411 } 412 413 batch.Set(ref, subject) 414 i++ 415 if (i%500) == 0 && len(subjects) != i { 416 batches = append(batches, batch) 417 batch = repo.firestoreClient.Batch() 418 } 419 } 420 batches = append(batches, batch) 421 422 for _, b := range batches { 423 if _, err := b.Commit(ctx); err != nil { 424 return xerrors.Errorf("error in Commit method: %w", err) 425 } 426 } 427 428 return nil 429 } 430 431 // DeleteMulti - bulk delete of `SubTask` 432 func (repo *subTaskRepository) DeleteMulti(ctx context.Context, subjects []*SubTask, opts ...DeleteOption) (er error) { 433 if repo.collectionGroup != nil { 434 return ErrNotAvailableCG 435 } 436 437 batches := make([]*firestore.WriteBatch, 0) 438 batch := repo.firestoreClient.Batch() 439 collect := repo.GetCollection() 440 441 for i, subject := range subjects { 442 ref := collect.Doc(subject.ID) 443 if _, err := ref.Get(ctx); err != nil { 444 if status.Code(err) == codes.NotFound { 445 return xerrors.Errorf("not found [%v]: %w", subject.ID, err) 446 } 447 return xerrors.Errorf("error in Get method [%v]: %w", subject.ID, err) 448 } 449 450 if err := repo.beforeDelete(ctx, subject, opts...); err != nil { 451 return xerrors.Errorf("before delete error(%d) [%v]: %w", i, subject.ID, err) 452 } 453 454 batch.Delete(ref) 455 456 i++ 457 if (i%500) == 0 && len(subjects) != i { 458 batches = append(batches, batch) 459 batch = repo.firestoreClient.Batch() 460 } 461 } 462 batches = append(batches, batch) 463 464 for _, b := range batches { 465 if _, err := b.Commit(ctx); err != nil { 466 return xerrors.Errorf("error in Commit method: %w", err) 467 } 468 } 469 470 return nil 471 } 472 473 // DeleteMultiByIDs - delete `SubTask` in bulk by array of `SubTask.ID` 474 func (repo *subTaskRepository) DeleteMultiByIDs(ctx context.Context, ids []string, opts ...DeleteOption) (er error) { 475 if repo.collectionGroup != nil { 476 return ErrNotAvailableCG 477 } 478 subjects := make([]*SubTask, len(ids)) 479 480 opt := GetOption{} 481 if len(opts) > 0 { 482 opt.IncludeSoftDeleted = opts[0].Mode == DeleteModeHard 483 } 484 for i, id := range ids { 485 subject, err := repo.Get(ctx, id, opt) 486 if err != nil { 487 return xerrors.Errorf("error in Get method: %w", err) 488 } 489 subjects[i] = subject 490 } 491 492 return repo.DeleteMulti(ctx, subjects, opts...) 493 } 494 495 // SearchWithTx - search documents in transaction 496 func (repo *subTaskRepository) SearchWithTx(tx *firestore.Transaction, param *SubTaskSearchParam, q *firestore.Query) ([]*SubTask, error) { 497 return repo.search(tx, param, q) 498 } 499 500 // SearchByParamWithTx - search documents by search param in transaction 501 func (repo *subTaskRepository) SearchByParamWithTx(tx *firestore.Transaction, param *SubTaskSearchParam) ([]*SubTask, *PagingResult, error) { 502 return repo.searchByParam(tx, param) 503 } 504 505 // GetWithTx - get `SubTask` by `SubTask.ID` in transaction 506 func (repo *subTaskRepository) GetWithTx(tx *firestore.Transaction, id string, opts ...GetOption) (*SubTask, error) { 507 if repo.collectionGroup != nil { 508 return nil, ErrNotAvailableCG 509 } 510 doc := repo.GetDocRef(id) 511 return repo.get(tx, doc, opts...) 512 } 513 514 // GetWithDocWithTx - get `SubTask` by *firestore.DocumentRef in transaction 515 func (repo *subTaskRepository) GetWithDocWithTx(tx *firestore.Transaction, doc *firestore.DocumentRef, opts ...GetOption) (*SubTask, error) { 516 if repo.collectionGroup != nil { 517 return nil, ErrNotAvailableCG 518 } 519 return repo.get(tx, doc, opts...) 520 } 521 522 // InsertWithTx - insert of `SubTask` in transaction 523 func (repo *subTaskRepository) InsertWithTx(ctx context.Context, tx *firestore.Transaction, subject *SubTask) (_ string, err error) { 524 if repo.collectionGroup != nil { 525 return "", ErrNotAvailableCG 526 } 527 if err := repo.beforeInsert(context.WithValue(ctx, transactionInProgressKey{}, tx), subject); err != nil { 528 return "", xerrors.Errorf("before insert error: %w", err) 529 } 530 531 return repo.insert(tx, subject) 532 } 533 534 // UpdateWithTx - update of `SubTask` in transaction 535 func (repo *subTaskRepository) UpdateWithTx(ctx context.Context, tx *firestore.Transaction, subject *SubTask) (err error) { 536 if repo.collectionGroup != nil { 537 return ErrNotAvailableCG 538 } 539 if err := repo.beforeUpdate(context.WithValue(ctx, transactionInProgressKey{}, tx), nil, subject); err != nil { 540 return xerrors.Errorf("before update error: %w", err) 541 } 542 543 return repo.update(tx, subject) 544 } 545 546 // StrictUpdateWithTx - strict update of `SubTask` in transaction 547 func (repo *subTaskRepository) StrictUpdateWithTx(tx *firestore.Transaction, id string, param *SubTaskUpdateParam, opts ...firestore.Precondition) error { 548 if repo.collectionGroup != nil { 549 return ErrNotAvailableCG 550 } 551 return repo.strictUpdate(tx, id, param, opts...) 552 } 553 554 // DeleteWithTx - delete of `SubTask` in transaction 555 func (repo *subTaskRepository) DeleteWithTx(ctx context.Context, tx *firestore.Transaction, subject *SubTask, opts ...DeleteOption) (err error) { 556 if repo.collectionGroup != nil { 557 return ErrNotAvailableCG 558 } 559 if err := repo.beforeDelete(context.WithValue(ctx, transactionInProgressKey{}, tx), subject, opts...); err != nil { 560 return xerrors.Errorf("before delete error: %w", err) 561 } 562 563 return repo.deleteByID(tx, subject.ID) 564 } 565 566 // DeleteByIDWithTx - delete `SubTask` by `SubTask.ID` in transaction 567 func (repo *subTaskRepository) DeleteByIDWithTx(ctx context.Context, tx *firestore.Transaction, id string, opts ...DeleteOption) (err error) { 568 if repo.collectionGroup != nil { 569 return ErrNotAvailableCG 570 } 571 subject, err := repo.Get(context.Background(), id) 572 if err != nil { 573 return xerrors.Errorf("error in Get method: %w", err) 574 } 575 576 if err := repo.beforeDelete(context.WithValue(ctx, transactionInProgressKey{}, tx), subject, opts...); err != nil { 577 return xerrors.Errorf("before delete error: %w", err) 578 } 579 580 return repo.deleteByID(tx, id) 581 } 582 583 // GetMultiWithTx - get `SubTask` in bulk by array of `SubTask.ID` in transaction 584 func (repo *subTaskRepository) GetMultiWithTx(tx *firestore.Transaction, ids []string, opts ...GetOption) ([]*SubTask, error) { 585 if repo.collectionGroup != nil { 586 return nil, ErrNotAvailableCG 587 } 588 return repo.getMulti(tx, ids, opts...) 589 } 590 591 // InsertMultiWithTx - bulk insert of `SubTask` in transaction 592 func (repo *subTaskRepository) InsertMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*SubTask) (_ []string, er error) { 593 if repo.collectionGroup != nil { 594 return nil, ErrNotAvailableCG 595 } 596 597 ids := make([]string, len(subjects)) 598 599 for i := range subjects { 600 if err := repo.beforeInsert(ctx, subjects[i]); err != nil { 601 return nil, xerrors.Errorf("before insert error(%d) [%v]: %w", i, subjects[i].ID, err) 602 } 603 604 id, err := repo.insert(tx, subjects[i]) 605 if err != nil { 606 return nil, xerrors.Errorf("error in insert method(%d) [%v]: %w", i, subjects[i].ID, err) 607 } 608 ids[i] = id 609 } 610 611 return ids, nil 612 } 613 614 // UpdateMultiWithTx - bulk update of `SubTask` in transaction 615 func (repo *subTaskRepository) UpdateMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*SubTask) (er error) { 616 if repo.collectionGroup != nil { 617 return ErrNotAvailableCG 618 } 619 ctx = context.WithValue(ctx, transactionInProgressKey{}, tx) 620 621 for i := range subjects { 622 if err := repo.beforeUpdate(ctx, nil, subjects[i]); err != nil { 623 return xerrors.Errorf("before update error(%d) [%v]: %w", i, subjects[i].ID, err) 624 } 625 } 626 627 for i := range subjects { 628 if err := repo.update(tx, subjects[i]); err != nil { 629 return xerrors.Errorf("error in update method(%d) [%v]: %w", i, subjects[i].ID, err) 630 } 631 } 632 633 return nil 634 } 635 636 // DeleteMultiWithTx - bulk delete of `SubTask` in transaction 637 func (repo *subTaskRepository) DeleteMultiWithTx(ctx context.Context, tx *firestore.Transaction, subjects []*SubTask, opts ...DeleteOption) (er error) { 638 if repo.collectionGroup != nil { 639 return ErrNotAvailableCG 640 } 641 642 var isHardDeleteMode bool 643 if len(opts) > 0 { 644 isHardDeleteMode = opts[0].Mode == DeleteModeHard 645 } 646 opt := GetOption{ 647 IncludeSoftDeleted: isHardDeleteMode, 648 } 649 for i := range subjects { 650 dr := repo.GetDocRef(subjects[i].ID) 651 if _, err := repo.get(context.Background(), dr, opt); err != nil { 652 if status.Code(err) == codes.NotFound { 653 return xerrors.Errorf("not found(%d) [%v]", i, subjects[i].ID) 654 } 655 return xerrors.Errorf("error in get method(%d) [%v]: %w", i, subjects[i].ID, err) 656 } 657 658 if err := repo.beforeDelete(context.WithValue(ctx, transactionInProgressKey{}, tx), subjects[i], opts...); err != nil { 659 return xerrors.Errorf("before delete error(%d) [%v]: %w", i, subjects[i].ID, err) 660 } 661 } 662 663 for i := range subjects { 664 if err := repo.deleteByID(tx, subjects[i].ID); err != nil { 665 return xerrors.Errorf("error in delete method(%d) [%v]: %w", i, subjects[i].ID, err) 666 } 667 } 668 669 return nil 670 } 671 672 // DeleteMultiByIDWithTx - delete `SubTask` in bulk by array of `SubTask.ID` in transaction 673 func (repo *subTaskRepository) DeleteMultiByIDsWithTx(ctx context.Context, tx *firestore.Transaction, ids []string, opts ...DeleteOption) (er error) { 674 if repo.collectionGroup != nil { 675 return ErrNotAvailableCG 676 } 677 678 for i := range ids { 679 dr := repo.GetDocRef(ids[i]) 680 subject, err := repo.get(context.Background(), dr) 681 if err != nil { 682 if status.Code(err) == codes.NotFound { 683 return xerrors.Errorf("not found(%d) [%v]", i, ids[i]) 684 } 685 return xerrors.Errorf("error in get method(%d) [%v]: %w", i, ids[i], err) 686 } 687 688 if err := repo.beforeDelete(context.WithValue(ctx, transactionInProgressKey{}, tx), subject, opts...); err != nil { 689 return xerrors.Errorf("before delete error(%d) [%v]: %w", i, subject.ID, err) 690 } 691 } 692 693 for i := range ids { 694 if err := repo.deleteByID(tx, ids[i]); err != nil { 695 return xerrors.Errorf("error in delete method(%d) [%v]: %w", i, ids[i], err) 696 } 697 } 698 699 return nil 700 } 701 702 func (repo *subTaskRepository) get(v interface{}, doc *firestore.DocumentRef, _ ...GetOption) (*SubTask, error) { 703 var ( 704 snapShot *firestore.DocumentSnapshot 705 err error 706 ) 707 708 switch x := v.(type) { 709 case *firestore.Transaction: 710 snapShot, err = x.Get(doc) 711 case context.Context: 712 snapShot, err = doc.Get(x) 713 default: 714 return nil, xerrors.Errorf("invalid type: %v", x) 715 } 716 717 if err != nil { 718 if status.Code(err) == codes.NotFound { 719 return nil, ErrNotFound 720 } 721 return nil, xerrors.Errorf("error in Get method: %w", err) 722 } 723 724 subject := new(SubTask) 725 if err := snapShot.DataTo(&subject); err != nil { 726 return nil, xerrors.Errorf("error in DataTo method: %w", err) 727 } 728 729 subject.ID = snapShot.Ref.ID 730 731 return subject, nil 732 } 733 734 func (repo *subTaskRepository) getMulti(v interface{}, ids []string, _ ...GetOption) ([]*SubTask, error) { 735 var ( 736 snapShots []*firestore.DocumentSnapshot 737 err error 738 collect = repo.GetCollection() 739 drs = make([]*firestore.DocumentRef, len(ids)) 740 ) 741 742 for i, id := range ids { 743 ref := collect.Doc(id) 744 drs[i] = ref 745 } 746 747 switch x := v.(type) { 748 case *firestore.Transaction: 749 snapShots, err = x.GetAll(drs) 750 case context.Context: 751 snapShots, err = repo.firestoreClient.GetAll(x, drs) 752 default: 753 return nil, xerrors.Errorf("invalid type: %v", v) 754 } 755 756 if err != nil { 757 return nil, xerrors.Errorf("error in GetAll method: %w", err) 758 } 759 760 subjects := make([]*SubTask, 0, len(ids)) 761 mErr := NewMultiErrors() 762 for i, snapShot := range snapShots { 763 if !snapShot.Exists() { 764 mErr = append(mErr, NewMultiError(i, ErrNotFound)) 765 continue 766 } 767 768 subject := new(SubTask) 769 if err = snapShot.DataTo(&subject); err != nil { 770 return nil, xerrors.Errorf("error in DataTo method: %w", err) 771 } 772 773 subject.ID = snapShot.Ref.ID 774 subjects = append(subjects, subject) 775 } 776 777 if len(mErr) == 0 { 778 return subjects, nil 779 } 780 781 return subjects, mErr 782 } 783 784 func (repo *subTaskRepository) insert(v interface{}, subject *SubTask) (string, error) { 785 var ( 786 dr = repo.GetCollection().NewDoc() 787 err error 788 ) 789 790 switch x := v.(type) { 791 case *firestore.Transaction: 792 err = x.Create(dr, subject) 793 case context.Context: 794 _, err = dr.Create(x, subject) 795 default: 796 return "", xerrors.Errorf("invalid type: %v", v) 797 } 798 799 if err != nil { 800 if status.Code(err) == codes.AlreadyExists { 801 return "", xerrors.Errorf("error in Create method: err=%+v: %w", err, ErrAlreadyExists) 802 } 803 return "", xerrors.Errorf("error in Create method: %w", err) 804 } 805 806 subject.ID = dr.ID 807 808 return dr.ID, nil 809 } 810 811 func (repo *subTaskRepository) update(v interface{}, subject *SubTask) error { 812 var ( 813 dr = repo.GetDocRef(subject.ID) 814 err error 815 ) 816 817 switch x := v.(type) { 818 case *firestore.Transaction: 819 err = x.Set(dr, subject) 820 case context.Context: 821 _, err = dr.Set(x, subject) 822 default: 823 return xerrors.Errorf("invalid type: %v", v) 824 } 825 826 if err != nil { 827 return xerrors.Errorf("error in Set method: %w", err) 828 } 829 830 return nil 831 } 832 833 func (repo *subTaskRepository) strictUpdate(v interface{}, id string, param *SubTaskUpdateParam, opts ...firestore.Precondition) error { 834 var ( 835 dr = repo.GetDocRef(id) 836 err error 837 ) 838 839 updates := updater(SubTask{}, param) 840 841 switch x := v.(type) { 842 case *firestore.Transaction: 843 err = x.Update(dr, updates, opts...) 844 case context.Context: 845 _, err = dr.Update(x, updates, opts...) 846 default: 847 return xerrors.Errorf("invalid type: %v", v) 848 } 849 850 if err != nil { 851 return xerrors.Errorf("error in Update method: %w", err) 852 } 853 854 return nil 855 } 856 857 func (repo *subTaskRepository) deleteByID(v interface{}, id string) error { 858 dr := repo.GetDocRef(id) 859 var err error 860 861 switch x := v.(type) { 862 case *firestore.Transaction: 863 err = x.Delete(dr, firestore.Exists) 864 case context.Context: 865 _, err = dr.Delete(x, firestore.Exists) 866 default: 867 return xerrors.Errorf("invalid type: %v", v) 868 } 869 870 if err != nil { 871 return xerrors.Errorf("error in Delete method: %w", err) 872 } 873 874 return nil 875 } 876 877 func (repo *subTaskRepository) runQuery(v interface{}, query firestore.Query) ([]*SubTask, error) { 878 var iter *firestore.DocumentIterator 879 880 switch x := v.(type) { 881 case *firestore.Transaction: 882 iter = x.Documents(query) 883 case context.Context: 884 iter = query.Documents(x) 885 default: 886 return nil, xerrors.Errorf("invalid type: %v", v) 887 } 888 889 defer iter.Stop() 890 891 subjects := make([]*SubTask, 0) 892 893 for { 894 doc, err := iter.Next() 895 if err == iterator.Done { 896 break 897 } 898 if err != nil { 899 return nil, xerrors.Errorf("error in Next method: %w", err) 900 } 901 902 subject := new(SubTask) 903 904 if err = doc.DataTo(&subject); err != nil { 905 return nil, xerrors.Errorf("error in DataTo method: %w", err) 906 } 907 908 subject.ID = doc.Ref.ID 909 subjects = append(subjects, subject) 910 } 911 912 return subjects, nil 913 } 914 915 // BUG(54m): there may be potential bugs 916 func (repo *subTaskRepository) searchByParam(v interface{}, param *SubTaskSearchParam) ([]*SubTask, *PagingResult, error) { 917 query := func() firestore.Query { 918 if repo.collectionGroup != nil { 919 return repo.collectionGroup.Query 920 } 921 return repo.GetCollection().Query 922 }() 923 if param.ID != nil { 924 for _, chain := range param.ID.QueryGroup { 925 var value interface{} 926 switch val := chain.Value.(type) { 927 case string: 928 value = repo.GetDocRef(val) 929 case []string: 930 docRefs := make([]*firestore.DocumentRef, len(val)) 931 for i := range val { 932 docRefs[i] = repo.GetDocRef(val[i]) 933 } 934 value = docRefs 935 default: 936 return nil, nil, xerrors.Errorf("document id can only be of type `string` and `[]string`. value: %#v", chain.Value) 937 } 938 query = query.Where(firestore.DocumentID, chain.Operator, value) 939 } 940 if direction := param.ID.OrderByDirection; direction > 0 { 941 query = query.OrderBy(firestore.DocumentID, direction) 942 query = param.ID.BuildCursorQuery(query) 943 } 944 } 945 if param.IsSubCollection != nil { 946 for _, chain := range param.IsSubCollection.QueryGroup { 947 query = query.Where("IsSubCollection", chain.Operator, chain.Value) 948 } 949 if direction := param.IsSubCollection.OrderByDirection; direction > 0 { 950 query = query.OrderBy("IsSubCollection", direction) 951 query = param.IsSubCollection.BuildCursorQuery(query) 952 } 953 } 954 955 limit := param.CursorLimit + 1 956 957 if param.CursorKey != "" { 958 var ( 959 ds *firestore.DocumentSnapshot 960 err error 961 ) 962 switch x := v.(type) { 963 case *firestore.Transaction: 964 ds, err = x.Get(repo.GetDocRef(param.CursorKey)) 965 case context.Context: 966 ds, err = repo.GetDocRef(param.CursorKey).Get(x) 967 default: 968 return nil, nil, xerrors.Errorf("invalid x type: %v", v) 969 } 970 if err != nil { 971 if status.Code(err) == codes.NotFound { 972 return nil, nil, ErrNotFound 973 } 974 return nil, nil, xerrors.Errorf("error in Get method: %w", err) 975 } 976 query = query.StartAt(ds) 977 } 978 979 if limit > 1 { 980 query = query.Limit(limit) 981 } 982 983 subjects, err := repo.runQuery(v, query) 984 if err != nil { 985 return nil, nil, xerrors.Errorf("error in runQuery method: %w", err) 986 } 987 988 pagingResult := &PagingResult{ 989 Length: len(subjects), 990 } 991 if limit > 1 && limit == pagingResult.Length { 992 next := pagingResult.Length - 1 993 pagingResult.NextCursorKey = subjects[next].ID 994 subjects = subjects[:next] 995 pagingResult.Length-- 996 } 997 998 return subjects, pagingResult, nil 999 } 1000 1001 func (repo *subTaskRepository) search(v interface{}, param *SubTaskSearchParam, q *firestore.Query) ([]*SubTask, error) { 1002 if (param == nil && q == nil) || (param != nil && q != nil) { 1003 return nil, xerrors.New("either one should be nil") 1004 } 1005 1006 query := func() firestore.Query { 1007 if q != nil { 1008 return *q 1009 } 1010 if repo.collectionGroup != nil { 1011 return repo.collectionGroup.Query 1012 } 1013 return repo.GetCollection().Query 1014 }() 1015 1016 if q == nil { 1017 subjects, _, err := repo.searchByParam(v, param) 1018 if err != nil { 1019 return nil, xerrors.Errorf("error in searchByParam method: %w", err) 1020 } 1021 1022 return subjects, nil 1023 } 1024 1025 return repo.runQuery(v, query) 1026 }