2020-06-16 15:15:04 +03:00
package commands
import (
"bytes"
2021-04-01 13:38:55 +03:00
"fmt"
"io/ioutil"
2021-01-18 20:11:05 +03:00
"os"
"path/filepath"
2020-06-16 15:15:04 +03:00
2021-06-16 14:44:15 +03:00
"github.com/hasura/graphql-engine/cli/v2/internal/hasura"
2021-04-01 13:38:55 +03:00
2020-06-16 15:15:04 +03:00
"github.com/spf13/afero"
"github.com/spf13/cobra"
2021-06-16 14:44:15 +03:00
"github.com/hasura/graphql-engine/cli/v2"
2022-11-07 16:11:33 +03:00
"github.com/hasura/graphql-engine/cli/v2/internal/errors"
2021-06-16 14:44:15 +03:00
"github.com/hasura/graphql-engine/cli/v2/internal/metadataobject/actions/editor"
"github.com/hasura/graphql-engine/cli/v2/seed"
2020-06-16 15:15:04 +03:00
)
type SeedNewOptions struct {
2021-04-01 13:38:55 +03:00
EC * cli . ExecutionContext
Driver * seed . Driver
2020-06-16 15:15:04 +03:00
// filename for the new seed file
SeedName string
// table name if seed file has to be created from a database table
FromTableNames [ ] string
// seed file that was created
2021-02-17 15:51:43 +03:00
FilePath string
2021-03-08 14:59:35 +03:00
Source cli . Source
2020-06-16 15:15:04 +03:00
}
func newSeedCreateCmd ( ec * cli . ExecutionContext ) * cobra . Command {
opts := SeedNewOptions {
EC : ec ,
}
cmd := & cobra . Command {
Use : "create seed_name" ,
2020-08-18 15:29:58 +03:00
Short : "Create a new seed file" ,
2020-06-16 15:15:04 +03:00
Example : ` # Create a new seed file and use editor to add SQL :
hasura seed create new_table_seed
# Create a new seed by exporting data from tables already present in the database :
hasura seed create table1_seed -- from - table table1
# Export data from multiple tables :
hasura seed create tables_seed -- from - table table1 -- from - table table2 ` ,
Args : cobra . ExactArgs ( 1 ) ,
SilenceUsage : false ,
PreRunE : func ( cmd * cobra . Command , args [ ] string ) error {
2022-11-07 16:11:33 +03:00
op := genOpName ( cmd , "PreRunE" )
2021-12-23 18:58:53 +03:00
if err := validateConfigV3Prechecks ( cmd , ec ) ; err != nil {
2022-11-07 16:11:33 +03:00
return errors . E ( op , err )
2021-12-23 18:58:53 +03:00
}
if ec . Config . Version < cli . V3 {
return nil
}
if err := databaseChooser ( ec ) ; err != nil {
2022-11-07 16:11:33 +03:00
return errors . E ( op , err )
2021-12-23 18:58:53 +03:00
}
if err := validateSourceInfo ( ec ) ; err != nil {
2022-11-07 16:11:33 +03:00
return errors . E ( op , err )
2021-12-23 18:58:53 +03:00
}
// check if seed ops are supported for the database
if ! seed . IsSeedsSupported ( ec . Source . Kind ) {
2022-11-07 16:11:33 +03:00
return errors . E ( op , fmt . Errorf ( "seed operations on database %s of kind %s is not supported" , ec . Source . Name , ec . Source . Kind ) )
2021-12-23 18:58:53 +03:00
}
return nil
2020-06-16 15:15:04 +03:00
} ,
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
2022-11-07 16:11:33 +03:00
op := genOpName ( cmd , "RunE" )
2020-06-16 15:15:04 +03:00
opts . SeedName = args [ 0 ]
2021-03-08 14:59:35 +03:00
opts . Source = ec . Source
2022-12-22 10:55:37 +03:00
opts . Driver = getSeedDriver ( ec , ec . Config . Version )
2020-06-16 15:15:04 +03:00
err := opts . Run ( )
if err != nil {
2022-11-07 16:11:33 +03:00
return errors . E ( op , err )
2020-06-16 15:15:04 +03:00
}
ec . Logger . WithField ( "file" , opts . FilePath ) . Info ( "created seed file successfully" )
return nil
} ,
}
2021-11-08 16:31:08 +03:00
cmd . Flags ( ) . StringArrayVar ( & opts . FromTableNames , "from-table" , [ ] string { } , "name of table from which seed file has to be initialized. e.g. table1, myschema1.table1" )
2020-06-16 15:15:04 +03:00
return cmd
}
func ( o * SeedNewOptions ) Run ( ) error {
2022-11-07 16:11:33 +03:00
var op errors . Op = "commands.SeedNewOptions.Run"
2021-03-08 14:59:35 +03:00
databaseDirectory := filepath . Join ( o . EC . SeedsDirectory , o . Source . Name )
2021-02-17 15:51:43 +03:00
if f , _ := os . Stat ( databaseDirectory ) ; f == nil {
if err := os . MkdirAll ( databaseDirectory , 0755 ) ; err != nil {
2022-11-07 16:11:33 +03:00
return errors . E ( op , err )
2021-01-18 20:11:05 +03:00
}
}
2020-06-16 15:15:04 +03:00
createSeedOpts := seed . CreateSeedOpts {
UserProvidedSeedName : o . SeedName ,
2021-03-08 14:59:35 +03:00
DirectoryPath : filepath . Join ( o . EC . SeedsDirectory , o . Source . Name ) ,
2020-06-16 15:15:04 +03:00
}
// If we are initializing from a database table
// create a hasura client and add table name opts
if createSeedOpts . Data == nil {
2020-08-10 08:58:03 +03:00
var body [ ] byte
2020-06-16 15:15:04 +03:00
if len ( o . FromTableNames ) > 0 {
2021-04-01 13:38:55 +03:00
if o . Source . Kind != hasura . SourceKindPG && o . EC . Config . Version >= cli . V3 {
2022-11-07 16:11:33 +03:00
return errors . E ( op , "--from-table is supported only for postgres databases" )
2020-06-16 15:15:04 +03:00
}
// Send the query
2021-04-01 13:38:55 +03:00
bodyReader , err := o . Driver . ExportDatadump ( o . FromTableNames , o . Source . Name )
2020-06-16 15:15:04 +03:00
if err != nil {
2022-11-07 16:11:33 +03:00
return errors . E ( op , fmt . Errorf ( "exporting seed data: %w" , err ) )
2020-06-16 15:15:04 +03:00
}
2021-04-01 13:38:55 +03:00
body , err = ioutil . ReadAll ( bodyReader )
if err != nil {
2022-11-07 16:11:33 +03:00
return errors . E ( op , err )
2021-04-01 13:38:55 +03:00
}
2020-06-16 15:15:04 +03:00
} else {
const defaultText = ""
2020-08-10 08:58:03 +03:00
var err error
2021-03-08 11:29:21 +03:00
body , err = editor . CaptureInputFromEditor ( editor . GetPreferredEditorFromEnvironment , defaultText , "sql" )
2020-06-16 15:15:04 +03:00
if err != nil {
2022-11-07 16:11:33 +03:00
return errors . E ( op , fmt . Errorf ( "cannot find default editor from env: %w" , err ) )
2020-06-16 15:15:04 +03:00
}
}
2020-08-10 08:58:03 +03:00
createSeedOpts . Data = bytes . NewReader ( body )
2020-06-16 15:15:04 +03:00
}
fs := afero . NewOsFs ( )
filepath , err := seed . CreateSeedFile ( fs , createSeedOpts )
if err != nil || filepath == nil {
2022-11-07 16:11:33 +03:00
return errors . E ( op , fmt . Errorf ( "failed to create seed file: %w" , err ) )
2020-06-16 15:15:04 +03:00
}
o . FilePath = * filepath
return nil
}