github.com/scraniel/migrate@v0.0.0-20230320185700-339088f36cee/database/multistmt/parse.go (about)

     1  // Package multistmt provides methods for parsing multi-statement database migrations
     2  package multistmt
     3  
     4  import (
     5  	"bufio"
     6  	"bytes"
     7  	"io"
     8  )
     9  
    10  // StartBufSize is the default starting size of the buffer used to scan and parse multi-statement migrations
    11  var StartBufSize = 4096
    12  
    13  // Handler handles a single migration parsed from a multi-statement migration.
    14  // It's given the single migration to handle and returns whether or not further statements
    15  // from the multi-statement migration should be parsed and handled.
    16  type Handler func(migration []byte) bool
    17  
    18  func splitWithDelimiter(delimiter []byte) func(d []byte, atEOF bool) (int, []byte, error) {
    19  	return func(d []byte, atEOF bool) (int, []byte, error) {
    20  		// SplitFunc inspired by bufio.ScanLines() implementation
    21  		if atEOF {
    22  			if len(d) == 0 {
    23  				return 0, nil, nil
    24  			}
    25  			return len(d), d, nil
    26  		}
    27  		if i := bytes.Index(d, delimiter); i >= 0 {
    28  			return i + len(delimiter), d[:i+len(delimiter)], nil
    29  		}
    30  		return 0, nil, nil
    31  	}
    32  }
    33  
    34  // Parse parses the given multi-statement migration
    35  func Parse(reader io.Reader, delimiter []byte, maxMigrationSize int, h Handler) error {
    36  	scanner := bufio.NewScanner(reader)
    37  	scanner.Buffer(make([]byte, 0, StartBufSize), maxMigrationSize)
    38  	scanner.Split(splitWithDelimiter(delimiter))
    39  	for scanner.Scan() {
    40  		cont := h(scanner.Bytes())
    41  		if !cont {
    42  			break
    43  		}
    44  	}
    45  	return scanner.Err()
    46  }