// Copyright 2023 Harness, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package database import ( "context" "database/sql" "time" "github.com/harness/gitness/app/api/request" "github.com/harness/gitness/registry/app/store" "github.com/harness/gitness/registry/app/store/database/util" "github.com/harness/gitness/registry/types" store2 "github.com/harness/gitness/store" databaseg "github.com/harness/gitness/store/database" "github.com/harness/gitness/store/database/dbtx" "github.com/google/uuid" "github.com/jmoiron/sqlx" "github.com/pkg/errors" ) type GenericBlobDao struct { sqlDB *sqlx.DB } func (g GenericBlobDao) FindByID(ctx context.Context, id string) (*types.GenericBlob, error) { q := databaseg.Builder. Select(util.ArrToStringByDelimiter(util.GetDBTagsFromStruct(GenericBlob{}), ",")). From("generic_blobs"). Where("generic_blob_id = ?", id) db := dbtx.GetAccessor(ctx, g.sqlDB) dst := new(GenericBlob) sql, args, err := q.ToSql() if err != nil { return nil, errors.Wrap(err, "Failed to convert query to sql") } if err = db.GetContext(ctx, dst, sql, args...); err != nil { return nil, databaseg.ProcessSQLErrorf(ctx, err, "Failed to find generic blob with id %s", id) } return g.mapToGenericBlob(ctx, dst) } func (g GenericBlobDao) FindBySha256AndRootParentID(ctx context.Context, sha256 string, rootParentID int64) ( *types.GenericBlob, error) { q := databaseg.Builder. Select(util.ArrToStringByDelimiter(util.GetDBTagsFromStruct(GenericBlob{}), ",")). From("generic_blob"). Where("generic_blob_root_parent_id = ? AND generic_blob_sha256 = ?", rootParentID, sha256) db := dbtx.GetAccessor(ctx, g.sqlDB) dst := new(GenericBlob) sql, args, err := q.ToSql() if err != nil { return nil, errors.Wrap(err, "Failed to convert query to sql") } if err = db.GetContext(ctx, dst, sql, args...); err != nil { return nil, databaseg.ProcessSQLErrorf(ctx, err, "Failed to find generic blob with sha256 %s", sha256) } return g.mapToGenericBlob(ctx, dst) } func (g GenericBlobDao) Create(ctx context.Context, gb *types.GenericBlob) error { const sqlQuery = ` INSERT INTO generic_blobs ( generic_blob_id ,generic_blob_root_parent_id ,generic_blob_sha_1 ,generic_blob_sha_256 ,generic_blob_sha_512 ,generic_blob_md5 ,generic_blob_size ,generic_blob_created_at ,generic_blob_created_by ) VALUES ( :generic_blob_id , :generic_blob_root_parent_id ,:generic_blob_sha_1 ,:generic_blob_sha_256 ,:generic_blob_sha_512 ,:generic_blob_md5 ,:generic_blob_size ,:generic_blob_created_at ,:generic_blob_created_by ) ON CONFLICT (generic_blob_root_parent_id, generic_blob_sha_256) DO UPDATE SET generic_blob_id = generic_blobs.generic_blob_id RETURNING generic_blob_id` db := dbtx.GetAccessor(ctx, g.sqlDB) query, arg, err := db.BindNamed(sqlQuery, g.mapToInternalGenericBlob(ctx, gb)) if err != nil { return databaseg.ProcessSQLErrorf(ctx, err, "Failed to bind generic blob object") } if err = db.QueryRowContext(ctx, query, arg...).Scan(&gb.ID); err != nil { if errors.Is(err, sql.ErrNoRows) || errors.Is(err, store2.ErrDuplicate) { return nil } return databaseg.ProcessSQLErrorf(ctx, err, "Insert query failed") } return nil } func (g GenericBlobDao) DeleteByID(_ context.Context, _ string) error { // TODO implement me panic("implement me") } func (g GenericBlobDao) mapToGenericBlob(_ context.Context, dst *GenericBlob) (*types.GenericBlob, error) { return &types.GenericBlob{ ID: dst.ID, RootParentID: dst.RootParentID, Sha256: dst.Sha256, Sha1: dst.Sha1, Sha512: dst.Sha512, MD5: dst.MD5, Size: dst.Size, CreatedAt: time.UnixMilli(dst.CreatedAt), CreatedBy: dst.CreatedBy, }, nil } func (g GenericBlobDao) mapToInternalGenericBlob(ctx context.Context, gb *types.GenericBlob) interface{} { session, _ := request.AuthSessionFrom(ctx) if gb.CreatedAt.IsZero() { gb.CreatedAt = time.Now() } if gb.CreatedBy == 0 { gb.CreatedBy = session.Principal.ID } if gb.ID == "" { gb.ID = uuid.NewString() } return &GenericBlob{ ID: gb.ID, Sha256: gb.Sha256, Sha1: gb.Sha1, Sha512: gb.Sha512, MD5: gb.MD5, Size: gb.Size, RootParentID: gb.RootParentID, CreatedAt: gb.CreatedAt.UnixMilli(), CreatedBy: gb.CreatedBy, } } func NewGenericBlobDao(sqlDB *sqlx.DB) store.GenericBlobRepository { return &GenericBlobDao{ sqlDB: sqlDB, } } type GenericBlob struct { ID string `db:"generic_blob_id"` RootParentID int64 `db:"generic_blob_root_parent_id"` Sha1 string `db:"generic_blob_sha_1"` Sha256 string `db:"generic_blob_sha_256"` Sha512 string `db:"generic_blob_sha_512"` MD5 string `db:"generic_blob_md5"` Size int64 `db:"generic_blob_size"` CreatedAt int64 `db:"generic_blob_created_at"` CreatedBy int64 `db:"generic_blob_created_by"` }