github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/remotesrv.go (about)

     1  // Copyright 2022 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package sqle
    16  
    17  import (
    18  	"context"
    19  
    20  	"github.com/dolthub/go-mysql-server/sql"
    21  
    22  	"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
    23  	"github.com/dolthub/dolt/go/libraries/doltcore/remotesrv"
    24  	"github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess"
    25  	"github.com/dolthub/dolt/go/libraries/utils/filesys"
    26  	"github.com/dolthub/dolt/go/store/datas"
    27  )
    28  
    29  type remotesrvStore struct {
    30  	ctxFactory func(context.Context) (*sql.Context, error)
    31  	createDBs  bool
    32  }
    33  
    34  var _ remotesrv.DBCache = remotesrvStore{}
    35  
    36  func (s remotesrvStore) Get(ctx context.Context, path, nbfVerStr string) (remotesrv.RemoteSrvStore, error) {
    37  	sqlCtx, err := s.ctxFactory(ctx)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  	sess := dsess.DSessFromSess(sqlCtx.Session)
    42  	db, err := sess.Provider().Database(sqlCtx, path)
    43  	if err != nil {
    44  		if s.createDBs && sql.ErrDatabaseNotFound.Is(err) {
    45  			err = sess.Provider().CreateDatabase(sqlCtx, path)
    46  			if err != nil {
    47  				return nil, err
    48  			}
    49  			db, err = sess.Provider().Database(sqlCtx, path)
    50  			if err != nil {
    51  				return nil, err
    52  			}
    53  		} else {
    54  			return nil, err
    55  		}
    56  	}
    57  
    58  	sdb, ok := db.(dsess.SqlDatabase)
    59  	if !ok {
    60  		return nil, remotesrv.ErrUnimplemented
    61  	}
    62  	datasdb := doltdb.HackDatasDatabaseFromDoltDB(sdb.DbData().Ddb)
    63  	cs := datas.ChunkStoreFromDatabase(datasdb)
    64  	rss, ok := cs.(remotesrv.RemoteSrvStore)
    65  	if !ok {
    66  		return nil, remotesrv.ErrUnimplemented
    67  	}
    68  	return rss, nil
    69  }
    70  
    71  // In the SQL context, the database provider that we use to expose the
    72  // remotesapi interface can choose to either create a newly accessed database
    73  // on first access or to return NotFound. Currently we allow creation in the
    74  // cluster replication context, where the replicated database should definitely
    75  // be made to exist and the accesses are always writes, but we disallow it in
    76  // the exposed-as-a-remotesapi-endpoint use case, where the requested database
    77  // may just be a typo or a configuration mistake on the part of the user.
    78  
    79  type CreateUnknownDatabasesSetting bool
    80  
    81  const CreateUnknownDatabases CreateUnknownDatabasesSetting = true
    82  const DoNotCreateUnknownDatabases CreateUnknownDatabasesSetting = false
    83  
    84  // Considers |args| and returns a new |remotesrv.ServerArgs| instance which
    85  // will serve databases accessible through |ctxFactory|.
    86  func RemoteSrvFSAndDBCache(ctxFactory func(context.Context) (*sql.Context, error), createSetting CreateUnknownDatabasesSetting) (filesys.Filesys, remotesrv.DBCache, error) {
    87  	sqlCtx, err := ctxFactory(context.Background())
    88  	if err != nil {
    89  		return nil, nil, err
    90  	}
    91  	sess := dsess.DSessFromSess(sqlCtx.Session)
    92  	fs := sess.Provider().FileSystem()
    93  	dbcache := remotesrvStore{ctxFactory, bool(createSetting)}
    94  	return fs, dbcache, nil
    95  }
    96  
    97  func WithUserPasswordAuth(args remotesrv.ServerArgs, authnz remotesrv.AccessControl) remotesrv.ServerArgs {
    98  	si := remotesrv.ServerInterceptor{
    99  		Lgr:              args.Logger,
   100  		AccessController: authnz,
   101  	}
   102  	args.Options = append(args.Options, si.Options()...)
   103  	return args
   104  }