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