github.com/ydb-platform/ydb-go-sdk/v3@v3.57.0/sugar/path.go (about)

     1  package sugar
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"path"
     7  	"strings"
     8  
     9  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
    10  	"github.com/ydb-platform/ydb-go-sdk/v3/scheme"
    11  	"github.com/ydb-platform/ydb-go-sdk/v3/table"
    12  	"github.com/ydb-platform/ydb-go-sdk/v3/topic"
    13  )
    14  
    15  const (
    16  	sysDirectory = ".sys"
    17  )
    18  
    19  type dbName interface {
    20  	Name() string
    21  }
    22  
    23  type dbScheme interface {
    24  	Scheme() scheme.Client
    25  }
    26  
    27  type dbTable interface {
    28  	Table() table.Client
    29  }
    30  
    31  type dbTopic interface {
    32  	Topic() topic.Client
    33  }
    34  
    35  type dbForMakeRecursive interface {
    36  	dbName
    37  	dbScheme
    38  }
    39  
    40  type dbFoRemoveRecursive interface {
    41  	dbName
    42  	dbScheme
    43  	dbTable
    44  	dbTopic
    45  }
    46  
    47  // MakeRecursive creates path inside database
    48  // pathToCreate is a database root relative path
    49  // MakeRecursive method equal bash command `mkdir -p ~/path/to/create`
    50  // where `~` - is a root of database
    51  func MakeRecursive(ctx context.Context, db dbForMakeRecursive, pathToCreate string) error {
    52  	if strings.HasPrefix(pathToCreate, sysDirectory+"/") {
    53  		return xerrors.WithStackTrace(
    54  			fmt.Errorf("making directory %q inside system path %q not supported", pathToCreate, sysDirectory),
    55  		)
    56  	}
    57  
    58  	absPath := path.Join(db.Name(), pathToCreate)
    59  
    60  	err := db.Scheme().MakeDirectory(ctx, absPath)
    61  	if err != nil {
    62  		return xerrors.WithStackTrace(
    63  			fmt.Errorf("cannot make directory %q: %w", absPath, err),
    64  		)
    65  	}
    66  
    67  	info, err := db.Scheme().DescribePath(ctx, absPath)
    68  	if err != nil {
    69  		return xerrors.WithStackTrace(
    70  			fmt.Errorf("cannot describe path %q: %w", absPath, err),
    71  		)
    72  	}
    73  
    74  	switch info.Type {
    75  	case
    76  		scheme.EntryDatabase,
    77  		scheme.EntryDirectory:
    78  		return nil
    79  	default:
    80  		return xerrors.WithStackTrace(
    81  			fmt.Errorf("entry %q exists but it is not a directory: %s", absPath, info.Type),
    82  		)
    83  	}
    84  }
    85  
    86  // RemoveRecursive remove selected directory or table names in database.
    87  // pathToRemove is a database root relative path
    88  // All database entities in prefix path will remove if names list is empty.
    89  // Empty prefix means than use root of database.
    90  // RemoveRecursive method equal bash command `rm -rf ~/path/to/remove`
    91  // where `~` - is a root of database
    92  func RemoveRecursive(ctx context.Context, db dbFoRemoveRecursive, pathToRemove string) error {
    93  	fullSysTablePath := path.Join(db.Name(), sysDirectory)
    94  	var rmPath func(int, string) error
    95  	rmPath = func(i int, p string) error {
    96  		if exists, err := IsDirectoryExists(ctx, db.Scheme(), p); err != nil {
    97  			return xerrors.WithStackTrace(
    98  				fmt.Errorf("check directory %q exists failed: %w", p, err),
    99  			)
   100  		} else if !exists {
   101  			return nil
   102  		}
   103  
   104  		entry, err := db.Scheme().DescribePath(ctx, p)
   105  		if err != nil {
   106  			return xerrors.WithStackTrace(
   107  				fmt.Errorf("cannot describe path %q: %w", p, err),
   108  			)
   109  		}
   110  
   111  		if entry.Type != scheme.EntryDirectory && entry.Type != scheme.EntryDatabase {
   112  			return nil
   113  		}
   114  
   115  		dir, err := db.Scheme().ListDirectory(ctx, p)
   116  		if err != nil {
   117  			return xerrors.WithStackTrace(
   118  				fmt.Errorf("listing directory %q failed: %w", p, err),
   119  			)
   120  		}
   121  
   122  		for j := range dir.Children {
   123  			pt := path.Join(p, dir.Children[j].Name)
   124  			if pt == fullSysTablePath {
   125  				continue
   126  			}
   127  			switch t := dir.Children[j].Type; t {
   128  			case scheme.EntryDirectory:
   129  				if err = rmPath(i+1, pt); err != nil {
   130  					return xerrors.WithStackTrace(
   131  						fmt.Errorf("recursive removing directory %q failed: %w", pt, err),
   132  					)
   133  				}
   134  
   135  			case scheme.EntryTable, scheme.EntryColumnTable:
   136  				err = db.Table().Do(ctx, func(ctx context.Context, session table.Session) (err error) {
   137  					return session.DropTable(ctx, pt)
   138  				}, table.WithIdempotent())
   139  				if err != nil {
   140  					return xerrors.WithStackTrace(
   141  						fmt.Errorf("removing table %q failed: %w", pt, err),
   142  					)
   143  				}
   144  
   145  			case scheme.EntryTopic:
   146  				err = db.Topic().Drop(ctx, pt)
   147  				if err != nil {
   148  					return xerrors.WithStackTrace(
   149  						fmt.Errorf("removing topic %q failed: %w", pt, err),
   150  					)
   151  				}
   152  
   153  			default:
   154  				return xerrors.WithStackTrace(
   155  					fmt.Errorf("unknown entry type: %s", t.String()),
   156  				)
   157  			}
   158  		}
   159  
   160  		if entry.Type != scheme.EntryDirectory {
   161  			return nil
   162  		}
   163  
   164  		err = db.Scheme().RemoveDirectory(ctx, p)
   165  		if err != nil {
   166  			return xerrors.WithStackTrace(
   167  				fmt.Errorf("removing directory %q failed: %w", p, err),
   168  			)
   169  		}
   170  
   171  		return nil
   172  	}
   173  	if !strings.HasPrefix(pathToRemove, db.Name()) {
   174  		pathToRemove = path.Join(db.Name(), pathToRemove)
   175  	}
   176  
   177  	return rmPath(0, pathToRemove)
   178  }