func (jsonli *jsonlFilePartitionIterator) NextPartition() (sif.Partition, func(), error) {
	jsonli.lock.Lock()
	defer jsonli.lock.Unlock()
	colNames := jsonli.schema.ColumnNames()
	colTypes := jsonli.schema.ColumnTypes()
	part := datasource.CreateBuildablePartition(jsonli.parser.PartitionSize(), jsonli.schema)
	tempRow := datasource.CreateTempRow()
	for {
		if part.GetNumRows() == part.GetMaxRows() {
			return part, nil, nil
		}
		hasNext := jsonli.scanner.Scan()
		if !hasNext {
			jsonli.hasNext = false
			for _, l := range jsonli.endListeners {
				l()
			}
			jsonli.endListeners = []func(){}
			return part, nil, nil
		}
		if err := jsonli.scanner.Err(); err != nil {
			return nil, nil, err
		}
		rowString := jsonli.scanner.Text()
		row, err := part.AppendEmptyRowData(tempRow)
		if err != nil {
			return nil, nil, err
		}
		err = ParseJSONRow(colNames, colTypes, gjson.Parse(rowString), row)
		if err != nil {
			log.Printf("Unable to parse line:\n\t%s", rowString)
			return nil, nil, err
		}
	}
}
NextPartition returns the next Partition if one is available, or an error
package jsonl
import (
	"bufio"
	"log"
	"sync"
	"github.com/go-sif/sif"
	"github.com/go-sif/sif/datasource"
	"github.com/tidwall/gjson"
)
type jsonlFilePartitionIterator struct {
	parser       *Parser
	scanner      *bufio.Scanner
	hasNext      bool
	source       sif.DataSource
	schema       sif.Schema
	lock         sync.Mutex
	endListeners []func()
}
func (jsonli *jsonlFilePartitionIterator) OnEnd(onEnd func()) {
	jsonli.lock.Lock()
	defer jsonli.lock.Unlock()
	jsonli.endListeners = append(jsonli.endListeners, onEnd)
}
func (jsonli *jsonlFilePartitionIterator) HasNextPartition() bool {
	jsonli.lock.Lock()
	defer jsonli.lock.Unlock()
	return jsonli.hasNext
}