github.com/haagen/force@v0.19.6-0.20140911230915-22addd930b34/bulk.go (about)

     1  package main
     2  
     3  /*
     4  
     5  bulk command
     6  force bulk insert mydata.csv
     7  
     8  The load process involves these steps
     9  	1. Create a job
    10  	https://instance_name—api.salesforce.com/services/async/APIversion/job
    11  		payload:
    12  			<jobInfo xmlns="http://www.force.com/2009/06/asyncapi/dataload">
    13   				<operation>insert</operation>
    14   				<object>Account</object>
    15   				<contentType>CSV</contentType>
    16  			</jobInfo>
    17  	2. Add batches to the created job
    18  	https://instance_name—api.salesforce.com/services/async/APIversion/job/jobid/batch
    19  		payload:
    20  			<sObjects xmlns="http://www.force.com/2009/06/asyncapi/dataload">
    21    				<sObject>
    22      				<description>Created from Bulk API on Tue Apr 14 11:15:59 PDT 2009</description>
    23      				<name>[Bulk API] Account 0 (batch 0)</name>
    24    				</sObject>
    25    				<sObject>
    26      				<description>Created from Bulk API on Tue Apr 14 11:15:59 PDT 2009</description>
    27      				<name>[Bulk API] Account 1 (batch 0)</name>
    28    				</sObject>
    29  			</sObjects>
    30  	3. Close job (I assume this submits the job???)
    31  	https://instance_name—api.salesforce.com/services/async/APIversion/job/jobId
    32  		payload:
    33  			<jobInfo xmlns="http://www.force.com/2009/06/asyncapi/dataload">
    34   				<state>Closed</state>
    35  			</jobInfo>
    36  
    37  Jobs and batches can be monitored.
    38  
    39  bulk command
    40  force bulk job <jobId>
    41  
    42  bulk command
    43  force bulk batches <jobId>
    44  
    45  bulk command
    46  force bulk batch <batchId>
    47  
    48  
    49  
    50  
    51  
    52  */
    53  
    54  import (
    55  	"encoding/xml"
    56  	"fmt"
    57  	"io/ioutil"
    58  )
    59  
    60  var cmdBulk = &Command{
    61  	Run:   runBulk,
    62  	Usage: "bulk insert Account [csv file]",
    63  	Short: "Load csv file use Bulk API",
    64  	Long: `
    65  Load csv file use Bulk API
    66  
    67  Examples:
    68  
    69    force bulk insert Account [csv file]
    70  
    71    force bulk update Account [csv file]
    72  
    73    force bulk job [job id]
    74  
    75    force bulk batches [job id]
    76  
    77    force bulk batch [job id] [batch id]
    78  
    79    force bulk batch retrieve [job id] [batch id]
    80  
    81    force bulk query Account [SOQL]
    82  
    83    force bulk query retrieve [job id] [batch id]
    84  `,
    85  }
    86  
    87  func runBulk(cmd *Command, args []string) {
    88  
    89  	if len(args) == 1 {
    90  		ErrorAndExit("Invalid command")
    91  	} else if len(args) == 2 {
    92  		if args[0] == "insert" {
    93  			ErrorAndExit("Missing argument for insert")
    94  		} else if args[0] == "job" {
    95  			showJobDetails(args[1])
    96  		} else if args[0] == "batches" {
    97  			listBatches(args[1])
    98  		} else {
    99  			ErrorAndExit("Invalid command")
   100  		}
   101  	} else if len(args) == 3 {
   102  		if args[0] == "insert" {
   103  			createBulkInsertJob(args[2], args[1], "CSV")
   104  		} else if args[0] == "update" {
   105  			createBulkUpdateJob(args[2], args[1], "CSV")
   106  		} else if args[0] == "batch" {
   107  			showBatchDetails(args[1], args[2])
   108  		} else if args[0] == "query" {
   109  			if args[1] == "retrieve" {
   110  				ErrorAndExit("Query retrieve requires a job id and a batch id")
   111  			} else {
   112  				doBulkQuery(args[1], args[2], "CSV")
   113  			}
   114  		}
   115  	} else if len(args) == 4 {
   116  		if args[0] == "insert" {
   117  			createBulkInsertJob(args[2], args[1], args[3])
   118  		} else if args[0] == "update" {
   119  			createBulkUpdateJob(args[2], args[1], args[3])
   120  		} else if args[0] == "batch" {
   121  			getBatchResults(args[2], args[3])
   122  		} else if args[0] == "query" {
   123  			if args[1] == "retrieve" {
   124  				fmt.Println(string(getBulkQueryResults(args[2], args[3])))
   125  			} else if args[1] == "status" {
   126  				DisplayBatchInfo(getBatchDetails(args[2], args[3]))
   127  			} else {
   128  				doBulkQuery(args[1], args[2], args[3])
   129  			}
   130  		}
   131  	}
   132  }
   133  
   134  func doBulkQuery(objectType string, soql string, contenttype string) {
   135  	jobInfo, err := createBulkJob(objectType, "query", contenttype)
   136  	force, _ := ActiveForce()
   137  
   138  	result, err := force.BulkQuery(soql, jobInfo.Id, contenttype)
   139  	if err != nil {
   140  		closeBulkJob(jobInfo.Id)
   141  		ErrorAndExit(err.Error())
   142  	}
   143  	fmt.Println("Query Submitted")
   144  	fmt.Printf("To retrieve query status use\nforce bulk query status %s %s\n\n", jobInfo.Id, result.Id)
   145  	fmt.Printf("To retrieve query data use\nforce bulk query retrieve %s %s\n\n", jobInfo.Id, result.Id)
   146  	closeBulkJob(jobInfo.Id)
   147  }
   148  
   149  func getBulkQueryResults(jobId string, batchId string) (data []byte) {
   150  	resultId := retrieveBulkQuery(jobId, batchId)
   151  	data = retrieveBulkQueryResults(jobId, batchId, resultId)
   152  	return
   153  }
   154  
   155  func retrieveBulkQuery(jobId string, batchId string) (resultId string) {
   156  	force, _ := ActiveForce()
   157  
   158  	jobInfo, err := force.RetrieveBulkQuery(jobId, batchId)
   159  	if err != nil {
   160  		ErrorAndExit(err.Error())
   161  	}
   162  
   163  	var result struct {
   164  		Result string `xml:"result"`
   165  	}
   166  
   167  	xml.Unmarshal(jobInfo, &result)
   168  	resultId = result.Result
   169  	return
   170  }
   171  
   172  func retrieveBulkQueryResults(jobId string, batchId string, resultId string) (data []byte) {
   173  	force, _ := ActiveForce()
   174  
   175  	data, err := force.RetrieveBulkQueryResults(jobId, batchId, resultId)
   176  	if err != nil {
   177  		ErrorAndExit(err.Error())
   178  	}
   179  	return
   180  }
   181  
   182  func showJobDetails(jobId string) {
   183  	jobInfo := getJobDetails(jobId)
   184  	DisplayJobInfo(jobInfo)
   185  }
   186  
   187  func listBatches(jobId string) {
   188  	batchInfos := getBatches(jobId)
   189  	DisplayBatchList(batchInfos)
   190  }
   191  
   192  func showBatchDetails(jobId string, batchId string) {
   193  	batchInfo := getBatchDetails(jobId, batchId)
   194  	DisplayBatchInfo(batchInfo)
   195  }
   196  
   197  func getBatchResults(jobId string, batchId string) {
   198  	force, _ := ActiveForce()
   199  
   200  	data, err := force.RetrieveBulkBatchResults(jobId, batchId)
   201  	fmt.Println(data)
   202  	if err != nil {
   203  		ErrorAndExit(err.Error())
   204  	}
   205  	return
   206  }
   207  
   208  func getJobDetails(jobId string) (jobInfo JobInfo) {
   209  	force, _ := ActiveForce()
   210  
   211  	jobInfo, err := force.GetJobInfo(jobId)
   212  
   213  	if err != nil {
   214  		ErrorAndExit(err.Error())
   215  	}
   216  	return
   217  }
   218  
   219  func getBatches(jobId string) (batchInfos []BatchInfo) {
   220  	force, _ := ActiveForce()
   221  
   222  	batchInfos, err := force.GetBatches(jobId)
   223  
   224  	if err != nil {
   225  		ErrorAndExit(err.Error())
   226  	}
   227  	return
   228  }
   229  
   230  func getBatchDetails(jobId string, batchId string) (batchInfo BatchInfo) {
   231  	force, _ := ActiveForce()
   232  
   233  	batchInfo, err := force.GetBatchInfo(jobId, batchId)
   234  
   235  	if err != nil {
   236  		ErrorAndExit(err.Error())
   237  	}
   238  	return
   239  }
   240  
   241  func createBulkInsertJob(csvFilePath string, objectType string, format string) {
   242  	jobInfo, err := createBulkJob(objectType, "insert", format)
   243  	if err != nil {
   244  		ErrorAndExit(err.Error())
   245  	} else {
   246  		batchInfo, err := addBatchToJob(csvFilePath, jobInfo.Id)
   247  		if err != nil {
   248  			closeBulkJob(jobInfo.Id)
   249  			ErrorAndExit(err.Error())
   250  		} else {
   251  			closeBulkJob(jobInfo.Id)
   252  			fmt.Printf("Job created ( %s ) - for job status use\n force bulk batch %s %s\n", jobInfo.Id, jobInfo.Id, batchInfo.Id)
   253  		}
   254  	}
   255  }
   256  
   257  func createBulkUpdateJob(csvFilePath string, objectType string, format string) {
   258  	jobInfo, err := createBulkJob(objectType, "update", format)
   259  	if err != nil {
   260  		ErrorAndExit(err.Error())
   261  	} else {
   262  		_, err := addBatchToJob(csvFilePath, jobInfo.Id)
   263  		if err != nil {
   264  			closeBulkJob(jobInfo.Id)
   265  			ErrorAndExit(err.Error())
   266  		} else {
   267  			closeBulkJob(jobInfo.Id)
   268  		}
   269  	}
   270  }
   271  
   272  func addBatchToJob(csvFilePath string, jobId string) (result BatchInfo, err error) {
   273  
   274  	force, _ := ActiveForce()
   275  
   276  	filedata, err := ioutil.ReadFile(csvFilePath)
   277  
   278  	result, err = force.AddBatchToJob(string(filedata), jobId)
   279  	return
   280  }
   281  
   282  func getBatchInfo(jobId string, batchId string) (batchInfo BatchInfo, err error) {
   283  	force, _ := ActiveForce()
   284  	batchInfo, err = force.GetBatchInfo(jobId, batchId)
   285  	return
   286  }
   287  
   288  func createBulkJob(objectType string, operation string, fileFormat string) (jobInfo JobInfo, err error) {
   289  	force, _ := ActiveForce()
   290  
   291  	xml := `
   292  	<jobInfo xmlns="http://www.force.com/2009/06/asyncapi/dataload">
   293   		<operation>%s</operation>
   294   		<object>%s</object>
   295   		<contentType>%s</contentType>
   296  	</jobInfo>
   297  	`
   298  	data := fmt.Sprintf(xml, operation, objectType, fileFormat)
   299  	jobInfo, err = force.CreateBulkJob(data)
   300  	return
   301  }
   302  
   303  func closeBulkJob(jobId string) (jobInfo JobInfo, err error) {
   304  	force, _ := ActiveForce()
   305  
   306  	xml := `
   307  	<jobInfo xmlns="http://www.force.com/2009/06/asyncapi/dataload">
   308   		<state>Closed</state>
   309  	</jobInfo>
   310  	`
   311  	jobInfo, err = force.CloseBulkJob(jobId, xml)
   312  	if err != nil {
   313  		ErrorAndExit(err.Error())
   314  	}
   315  	return
   316  }