<commit_before>// Package enigma provides developers with a Go client for the Enigma.io API.
//
// The Enigma API allows users to download datasets, query metadata, or perform server side operations on tables in Enigma.
// All calls to the API are made through a RESTful protocol and require an API key.
// The Enigma API is served over HTTPS.
package enigma

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

const (
	root    = "https://api.enigma.io" //<version>/<endpoint>/<api key>/<datapath>/<parameters>
	version = "v2"
)

type endpoint string

const (
	meta   endpoint = "meta"
	data   endpoint = "data"
	stats  endpoint = "stats"
	export endpoint = "export"
)

// Conjunction represents the logical link between multiple search or where parameters.
type Conjunction string

const (
	Or  Conjunction = "or"
	And Conjunction = "and"
)

// SortDirection represents the direction in which a selected column or calculation result
// should be sorted.
type SortDirection string

const (
	Asc  SortDirection = "+"
	Desc SortDirection = "-"
)

// Operation represents a calculation that a stats request can perform on a selected column.
type Operation string

const (
	Sum       Operation = "sum"
	Avg       Operation = "avg"
	StdDev    Operation = "stddev"
	Variance  Operation = "variance"
	Max       Operation = "max"
	Min       Operation = "min"
	Frequency Operation = "frequency"
)

type query struct {
	baseUri  string
	datapath string
	params   url.Values
}

func doQuery(baseUri, datapath string, params url.Values, response interface{}) (err error) {
	uri := baseUri + "/" + datapath
	if len(params) > 0 {
		uri += "?" + params.Encode()
	}

	resp, err := http.Get(uri)
	if err != nil {
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	// API error handling
	if resp.StatusCode != 200 {
		var e map[string]interface{}
		if json.Unmarshal(body, &e) != nil {
			return errors.New(resp.Status)
		} else {
			return errors.New(e["info"].(map[string]interface{})["additional"].(string))
		}
	}

	// Parsing the response into the provided response struct.
	if err = json.Unmarshal(body, &response); err != nil {
		return
	}
<commit_msg>Added a buildUrl fund to improve testability<commit_after>// Package enigma provides developers with a Go client for the Enigma.io API.
//
// The Enigma API allows users to download datasets, query metadata, or perform server side operations on tables in Enigma.
// All calls to the API are made through a RESTful protocol and require an API key.
// The Enigma API is served over HTTPS.
package enigma

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

const (
	root    = "https://api.enigma.io" //<version>/<endpoint>/<api key>/<datapath>/<parameters>
	version = "v2"
)

type endpoint string

const (
	meta   endpoint = "meta"
	data   endpoint = "data"
	stats  endpoint = "stats"
	export endpoint = "export"
)

// Conjunction represents the logical link between multiple search or where parameters.
type Conjunction string

const (
	Or  Conjunction = "or"
	And Conjunction = "and"
)

// SortDirection represents the direction in which a selected column or calculation result
// should be sorted.
type SortDirection string

const (
	Asc  SortDirection = "+"
	Desc SortDirection = "-"
)

// Operation represents a calculation that a stats request can perform on a selected column.
type Operation string

const (
	Sum       Operation = "sum"
	Avg       Operation = "avg"
	StdDev    Operation = "stddev"
	Variance  Operation = "variance"
	Max       Operation = "max"
	Min       Operation = "min"
	Frequency Operation = "frequency"
)

type query struct {
	baseUri  string
	datapath string
	params   url.Values
}

// Although used in a single location, this function has been isolated to make the code
// easier to test.
func buildUrl(baseUri, datapath string, params url.Values) string {
	uri := baseUri + "/" + datapath
	if len(params) > 0 {
		uri += "?" + params.Encode()
	}
	return uri
}

// doQuery performs the actual HTTP request and parses the returned JSON into a typed response structure.
func doQuery(baseUri, datapath string, params url.Values, response interface{}) (err error) {
	uri := buildUrl(baseUri, datapath, params)

	resp, err := http.Get(uri)
	if err != nil {
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	// API error handling
	if resp.StatusCode != 200 {
		var e map[string]interface{}
		if json.Unmarshal(body, &e) != nil {
			return errors.New(resp.Status)
		} else {
			return errors.New(e["info"].(map[string]interface{})["additional"].(string))
		}
	}

	// Parsing the response into the provided response struct.
	if err = json.Unmarshal(body, &response); err != nil {
		return
	}

{'fraction_non_alphanumeric': 0.10985393951861756, 'fraction_numerical': 0.002057189878625797, 'mean_word_length': 3.485239852398524, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 15, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7403360', 'n_tokens_mistral': 1569, 'n_tokens_neox': 1510, 'n_words': 547}