diff --git a/cmd/exptester/main.go b/cmd/exptester/main.go index 2659d3128..cabb20d93 100644 --- a/cmd/exptester/main.go +++ b/cmd/exptester/main.go @@ -14,7 +14,7 @@ func main() { vars := types.NewXMap(map[string]types.XValue{ "int1": types.NewXNumberFromInt(1), "int2": types.NewXNumberFromInt(2), - "string1": types.NewXString("string1"), + "string1": types.NewXText("string1"), }) if len(os.Args) != 2 { diff --git a/cmd/flowrunner/testdata/flows/dynamic_groups.json b/cmd/flowrunner/testdata/flows/dynamic_groups.json index ddb9f2255..eb0bcf489 100644 --- a/cmd/flowrunner/testdata/flows/dynamic_groups.json +++ b/cmd/flowrunner/testdata/flows/dynamic_groups.json @@ -80,7 +80,7 @@ { "key": "age", "label": "Age", - "value_type": "decimal" + "value_type": "number" }, { "key": "state", diff --git a/cmd/flowrunner/testdata/flows/dynamic_groups_test.json b/cmd/flowrunner/testdata/flows/dynamic_groups_test.json index 9b516e436..63ec3ab98 100644 --- a/cmd/flowrunner/testdata/flows/dynamic_groups_test.json +++ b/cmd/flowrunner/testdata/flows/dynamic_groups_test.json @@ -81,7 +81,7 @@ "contact": { "fields": { "age": { - "decimal": 17, + "number": 17, "text": "17" }, "first_name": { diff --git a/cmd/flowrunner/testdata/flows/subflow.json b/cmd/flowrunner/testdata/flows/subflow.json index efe959fd4..2ed1ace55 100644 --- a/cmd/flowrunner/testdata/flows/subflow.json +++ b/cmd/flowrunner/testdata/flows/subflow.json @@ -30,7 +30,7 @@ "cases": [ { "uuid": "19a95efc-ac69-4b6a-a90b-f84a60b49e4f", - "type": "is_string_eq", + "type": "is_text_eq", "arguments": [ "completed" ], diff --git a/cmd/flowrunner/testdata/flows/subflow_other.json b/cmd/flowrunner/testdata/flows/subflow_other.json index 6f6020f73..c8795d06f 100644 --- a/cmd/flowrunner/testdata/flows/subflow_other.json +++ b/cmd/flowrunner/testdata/flows/subflow_other.json @@ -35,7 +35,7 @@ "type": "switch", "cases": [ { - "type": "is_string_eq", + "type": "is_text_eq", "uuid": "57eda3da-817b-4942-a5fc-e1ea5d12c82d", "arguments": [ "completed" diff --git a/cmd/flowrunner/testdata/flows/webhook_persists.json b/cmd/flowrunner/testdata/flows/webhook_persists.json index 10bc7cf3b..96deaa50f 100644 --- a/cmd/flowrunner/testdata/flows/webhook_persists.json +++ b/cmd/flowrunner/testdata/flows/webhook_persists.json @@ -56,7 +56,7 @@ ], "uuid": "789b45bc-005a-46db-8331-6a966c0141c2", "exit_uuid": "bb09f6b6-89f4-45bd-8cc9-1d4655914590", - "type": "is_string_eq" + "type": "is_text_eq" } ], "default_exit_uuid": "3699df6c-15f0-4a86-b7f8-9fe1497e7854", diff --git a/contactql/parser_test.go b/contactql/parser_test.go index 05b718f34..b082ed06a 100644 --- a/contactql/parser_test.go +++ b/contactql/parser_test.go @@ -91,7 +91,7 @@ func TestEvaluateQuery(t *testing.T) { {`Gender is MALE`, true}, {`gender = "female"`, false}, - // decimal field condition + // number field condition {`age = 36`, true}, {`age is 35`, false}, {`age > 36`, false}, @@ -101,7 +101,7 @@ func TestEvaluateQuery(t *testing.T) { {`age < 37`, true}, {`age <= 36`, true}, - // date field condition + // datetime field condition {`dob = 1981/05/28`, true}, {`dob > 1981/05/28`, false}, {`dob > 1981/05/27`, true}, diff --git a/docs/docs.md b/docs/docs.md index 777cd6079..57d10b156 100644 --- a/docs/docs.md +++ b/docs/docs.md @@ -482,17 +482,17 @@ Takes a list of `values` and returns them as an array @(length(array("a", "b"))) → 2 ``` - + -## bool(value) +## boolean(value) Tries to convert `value` to a boolean. An error is returned if the value can't be converted. ```objectivec -@(bool(array(1, 2))) → true -@(bool("FALSE")) → false -@(bool(1 / 0)) → ERROR +@(boolean(array(1, 2))) → true +@(boolean("FALSE")) → false +@(boolean(1 / 0)) → ERROR ``` @@ -510,9 +510,9 @@ Returns the rune for the passed in codepoint, `num`, which may be unicode, this -## clean(string) +## clean(text) -Strips any leading or trailing whitespace from `string`` +Strips any leading or trailing whitespace from `text` ```objectivec @@ -523,9 +523,9 @@ Strips any leading or trailing whitespace from `string`` -## code(string) +## code(text) -Returns the numeric code for the first character in `string`, it is the inverse of char +Returns the numeric code for the first character in `text`, it is the inverse of char ```objectivec @@ -539,10 +539,10 @@ Returns the numeric code for the first character in `string`, it is the inverse -## date(string) +## date(text) -Turns `string` into a date according to the environment's settings. It will return an error -if it is unable to convert the string to a date. +Turns `text` into a date according to the environment's settings. It will return an error +if it is unable to convert the text to a date. ```objectivec @@ -552,9 +552,9 @@ if it is unable to convert the string to a date. @(date("NOT DATE")) → ERROR ``` - + -## date_add(date, offset, unit) +## datetime_add(date, offset, unit) Calculates the date value arrived at by adding `offset` number of `unit` to the `date` @@ -563,13 +563,13 @@ Valid durations are "Y" for years, "M" for months, "W" for weeks, "D" for days, ```objectivec -@(date_add("2017-01-15", 5, "D")) → 2017-01-20T00:00:00.000000-05:00 -@(date_add("2017-01-15 10:45", 30, "m")) → 2017-01-15T11:15:00.000000-05:00 +@(datetime_add("2017-01-15", 5, "D")) → 2017-01-20T00:00:00.000000-05:00 +@(datetime_add("2017-01-15 10:45", 30, "m")) → 2017-01-15T11:15:00.000000-05:00 ``` - + -## date_diff(date1, date2, unit) +## datetime_diff(date1, date2, unit) Returns the integer duration between `date1` and `date2` in the `unit` specified. @@ -578,22 +578,22 @@ Valid durations are "Y" for years, "M" for months, "W" for weeks, "D" for days, ```objectivec -@(date_diff("2017-01-17", "2017-01-15", "D")) → 2 -@(date_diff("2017-01-17 10:50", "2017-01-17 12:30", "h")) → -1 -@(date_diff("2017-01-17", "2015-12-17", "Y")) → 2 +@(datetime_diff("2017-01-17", "2017-01-15", "D")) → 2 +@(datetime_diff("2017-01-17 10:50", "2017-01-17 12:30", "h")) → -1 +@(datetime_diff("2017-01-17", "2015-12-17", "Y")) → 2 ``` - + -## date_from_parts(year, month, day) +## datetime_from_parts(year, month, day) Converts the passed in `year`, `month` and `day` ```objectivec -@(date_from_parts(2017, 1, 15)) → 2017-01-15T00:00:00.000000-05:00 -@(date_from_parts(2017, 2, 31)) → 2017-03-03T00:00:00.000000-05:00 -@(date_from_parts(2017, 13, 15)) → ERROR +@(datetime_from_parts(2017, 1, 15)) → 2017-01-15T00:00:00.000000-05:00 +@(datetime_from_parts(2017, 2, 31)) → 2017-03-03T00:00:00.000000-05:00 +@(datetime_from_parts(2017, 13, 15)) → ERROR ``` @@ -611,9 +611,9 @@ Takes two arguments, returning `test` if not an error or nil, otherwise returnin -## field(string, offset, delimeter) +## field(text, offset, delimeter) -Splits `string` based on the passed in `delimiter` and returns the field at `offset`. When splitting +Splits `text` based on the passed in `delimiter` and returns the field at `offset`. When splitting with a space, the delimiter is considered to be all whitespace. (first field is 0) @@ -630,7 +630,7 @@ with a space, the delimiter is considered to be all whitespace. (first field is ## format_date(date, format [,timezone]) -Turns `date` into a string according to the `format` specified and in +Turns `date` into text according to the `format` specified and in the optional `timezone`. The format string can consist of the following characters. The characters @@ -672,26 +672,26 @@ environment will be used. An error will be returned if the timezone is not recog @(format_date("NOT DATE", "YYYY-MM-DD")) → ERROR ``` - + -## format_num(num, places, commas) +## format_number(num, places, commas) Returns `num` formatted with the passed in number of decimal `places` and optional `commas` dividing thousands separators ```objectivec -@(format_num(31337)) → 31,337.00 -@(format_num(31337, 2)) → 31,337.00 -@(format_num(31337, 2, true)) → 31,337.00 -@(format_num(31337, 0, false)) → 31337 -@(format_num("foo", 2, false)) → ERROR +@(format_number(31337)) → 31,337.00 +@(format_number(31337, 2)) → 31,337.00 +@(format_number(31337, 2, true)) → 31,337.00 +@(format_number(31337, 0, false)) → 31337 +@(format_number("foo", 2, false)) → ERROR ``` ## format_urn(urn) -Turns `urn` into a human friendly string +Turns `urn` into human friendly text ```objectivec @@ -758,9 +758,9 @@ no JSON representation of that object. -## left(string, count) +## left(text, count) -Returns the `count` most left characters of the passed in `string` +Returns the `count` most left characters of the passed in `text` ```objectivec @@ -774,7 +774,7 @@ Returns the `count` most left characters of the passed in `string` ## length(value) -Returns the length of the passed in string or array. +Returns the length of the passed in text or array. length will return an error if it is passed an item which doesn't have length. @@ -789,9 +789,9 @@ length will return an error if it is passed an item which doesn't have length. -## lower(string) +## lower(text) -Lowercases the passed in `string` +Lowercases the passed in `text` ```objectivec @@ -889,11 +889,11 @@ Returns whether if any of the passed in arguments are truthy @(or(true, false, true)) → true ``` - + -## parse_date(string, format [,timezone]) +## parse_datetime(text, format [,timezone]) -Turns `string` into a date according to the `format` and optional `timezone` specified +Turns `text` into a date according to the `format` and optional `timezone` specified The format string can consist of the following characters. The characters ' ', ':', ',', 'T', '-' and '_' are ignored. Any other character is an error. @@ -927,21 +927,21 @@ Note that fractional seconds will be parsed even without an explicit format iden You should only specify fractional seconds when you want to assert the number of places in the input format. -parse_date will return an error if it is unable to convert the string to a date. +parse_datetime will return an error if it is unable to convert the text to a datetime. ```objectivec -@(parse_date("1979-07-18", "YYYY-MM-DD")) → 1979-07-18T00:00:00.000000-05:00 -@(parse_date("2010 5 10", "YYYY M DD")) → 2010-05-10T00:00:00.000000-05:00 -@(parse_date("2010 5 10 12:50", "YYYY M DD tt:mm", "America/Los_Angeles")) → 2010-05-10T12:50:00.000000-07:00 -@(parse_date("NOT DATE", "YYYY-MM-DD")) → ERROR +@(parse_datetime("1979-07-18", "YYYY-MM-DD")) → 1979-07-18T00:00:00.000000-05:00 +@(parse_datetime("2010 5 10", "YYYY M DD")) → 2010-05-10T00:00:00.000000-05:00 +@(parse_datetime("2010 5 10 12:50", "YYYY M DD tt:mm", "America/Los_Angeles")) → 2010-05-10T12:50:00.000000-07:00 +@(parse_datetime("NOT DATE", "YYYY-MM-DD")) → ERROR ``` -## parse_json(string) +## parse_json(text) -Tries to parse `string` as JSON, returning a fragment you can index into +Tries to parse `text` as JSON, returning a fragment you can index into If the passed in value is not JSON, then an error is returned @@ -955,7 +955,7 @@ If the passed in value is not JSON, then an error is returned ## percent(num) -Converts `num` to a string represented as a percentage +Converts `num` to text represented as a percentage ```objectivec @@ -1006,9 +1006,9 @@ splitting in 3s or 4s if appropriate. -## remove_first_word(string) +## remove_first_word(text) -Removes the 1st word of `string` +Removes the 1st word of `text` ```objectivec @@ -1017,9 +1017,9 @@ Removes the 1st word of `string` -## repeat(string, count) +## repeat(text, count) -Return `string` repeated `count` number of times +Return `text` repeated `count` number of times ```objectivec @@ -1029,9 +1029,9 @@ Return `string` repeated `count` number of times -## replace(string, needle, replacement) +## replace(text, needle, replacement) -Replaces all occurrences of `needle` with `replacement` in `string` +Replaces all occurrences of `needle` with `replacement` in `text` ```objectivec @@ -1041,9 +1041,9 @@ Replaces all occurrences of `needle` with `replacement` in `string` -## right(string, count) +## right(text, count) -Returns the `count` most right characters of the passed in `string` +Returns the `count` most right characters of the passed in `text` ```objectivec @@ -1106,9 +1106,9 @@ Rounds `num` up to the nearest integer value. You can optionally pass in the num -## split(string, delimiter) +## split(text, delimiter) -Splits `string` based on the passed in `delimeter` +Splits `text` based on the passed in `delimeter` Empty values are removed from the returned list @@ -1121,39 +1121,39 @@ Empty values are removed from the returned list @(split("a && b && c", " && ")) → ["a","b","c"] ``` - + -## string(value) +## text(value) -Tries to convert `value` to a string. An error is returned if the value can't be converted. +Tries to convert `value` to text. An error is returned if the value can't be converted. ```objectivec -@(string(3 = 3)) → true -@(json(string(123.45))) → "123.45" -@(string(1 / 0)) → ERROR +@(text(3 = 3)) → true +@(json(text(123.45))) → "123.45" +@(text(1 / 0)) → ERROR ``` - + -## string_cmp(str1, str2) +## text_compare(text1, text2) -Returns the comparison between the strings `str1` and `str2`. +Returns the comparison between the strings `text1` and `text2`. The return value will be -1 if str1 is smaller than str2, 0 if they are equal and 1 if str1 is greater than str2 ```objectivec -@(string_cmp("abc", "abc")) → 0 -@(string_cmp("abc", "def")) → -1 -@(string_cmp("zzz", "aaa")) → 1 +@(text_compare("abc", "abc")) → 0 +@(text_compare("abc", "def")) → -1 +@(text_compare("zzz", "aaa")) → 1 ``` -## title(string) +## title(text) -Titlecases the passed in `string`, capitalizing each word +Titlecases the passed in `text`, capitalizing each word ```objectivec @@ -1205,7 +1205,7 @@ timezone will be returned ## tz_offset(date) -Returns the offset for the timezone as a string +/- HHMM for `date` +Returns the offset for the timezone as text +/- HHMM for `date` If no timezone information is present in the date, then the environment's timezone offset will be returned @@ -1220,9 +1220,9 @@ timezone offset will be returned -## upper(string) +## upper(text) -Uppercases all characters in the passed `string` +Uppercases all characters in the passed `text` ```objectivec @@ -1232,9 +1232,9 @@ Uppercases all characters in the passed `string` -## url_encode(string) +## url_encode(text) -URL encodes `string` for use in a URL parameter +URL encodes `text` for use in a URL parameter ```objectivec @@ -1256,9 +1256,9 @@ Returns the day of the week for `date`, 0 is sunday, 1 is monday.. -## word(string, index) +## word(text, index) -Returns the word at the passed in `index` for the passed in `string` +Returns the word at the passed in `index` for the passed in `text` ```objectivec @@ -1272,9 +1272,9 @@ Returns the word at the passed in `index` for the passed in `string` -## word_count(string) +## word_count(text) -Returns the number of words in `string` +Returns the number of words in `text` ```objectivec @@ -1286,9 +1286,9 @@ Returns the number of words in `string` -## word_slice(string, start, end) +## word_slice(text, start, end) -Extracts a substring from `string` spanning from `start` up to but not-including `end`. (first word is 0). A negative +Extracts a substring from `text` spanning from `start` up to but not-including `end`. (first word is 0). A negative end value means that all words after the start should be returned. @@ -1314,9 +1314,9 @@ function is used.
Tries to convert value
to a boolean. An error is returned if the value can’t be converted.
Returns the rune for the passed in codepoint, num
, which may be unicode, this is the reverse of code
Strips any leading or trailing whitespace from `string``
+Strips any leading or trailing whitespace from text
Returns the numeric code for the first character in string
, it is the inverse of char
Returns the numeric code for the first character in text
, it is the inverse of char
@(code("a")) → 97
@(code("abc")) → 97
@(code("😀")) → 128512
@@ -528,31 +528,31 @@ code(string)
@(code(15)) → 49
@(code("")) → ERROR
Turns string
into a date according to the environment’s settings. It will return an error if it is unable to convert the string to a date.
Turns text
into a date according to the environment’s settings. It will return an error if it is unable to convert the text to a date.
@(date("1979-07-18")) → 1979-07-18T00:00:00.000000-05:00
@(date("1979-07-18T10:30:45.123456Z")) → 1979-07-18T10:30:45.123456Z
@(date("2010 05 10")) → 2010-05-10T00:00:00.000000-05:00
@(date("NOT DATE")) → ERROR
Calculates the date value arrived at by adding offset
number of unit
to the date
Valid durations are “Y” for years, “M” for months, “W” for weeks, “D” for days, “h” for hour, “m” for minutes, “s” for seconds
-@(date_add("2017-01-15", 5, "D")) → 2017-01-20T00:00:00.000000-05:00
-@(date_add("2017-01-15 10:45", 30, "m")) → 2017-01-15T11:15:00.000000-05:00
@(datetime_add("2017-01-15", 5, "D")) → 2017-01-20T00:00:00.000000-05:00
+@(datetime_add("2017-01-15 10:45", 30, "m")) → 2017-01-15T11:15:00.000000-05:00
Returns the integer duration between date1
and date2
in the unit
specified.
Valid durations are “Y” for years, “M” for months, “W” for weeks, “D” for days, “h” for hour, “m” for minutes, “s” for seconds
-@(date_diff("2017-01-17", "2017-01-15", "D")) → 2
-@(date_diff("2017-01-17 10:50", "2017-01-17 12:30", "h")) → -1
-@(date_diff("2017-01-17", "2015-12-17", "Y")) → 2
@(datetime_diff("2017-01-17", "2017-01-15", "D")) → 2
+@(datetime_diff("2017-01-17 10:50", "2017-01-17 12:30", "h")) → -1
+@(datetime_diff("2017-01-17", "2015-12-17", "Y")) → 2
Converts the passed in year
, month
and day
@(date_from_parts(2017, 1, 15)) → 2017-01-15T00:00:00.000000-05:00
-@(date_from_parts(2017, 2, 31)) → 2017-03-03T00:00:00.000000-05:00
-@(date_from_parts(2017, 13, 15)) → ERROR
@(datetime_from_parts(2017, 1, 15)) → 2017-01-15T00:00:00.000000-05:00
+@(datetime_from_parts(2017, 2, 31)) → 2017-03-03T00:00:00.000000-05:00
+@(datetime_from_parts(2017, 13, 15)) → ERROR
Takes two arguments, returning test
if not an error or nil, otherwise returning default
Splits string
based on the passed in delimiter
and returns the field at offset
. When splitting with a space, the delimiter is considered to be all whitespace. (first field is 0)
Splits text
based on the passed in delimiter
and returns the field at offset
. When splitting with a space, the delimiter is considered to be all whitespace. (first field is 0)
@(field("a,b,c", 1, ",")) → b
@(field("a,,b,c", 1, ",")) →
@(field("a b c", 1, " ")) → b
@@ -570,7 +570,7 @@ field(string, offset, delimeter)
@(field("a,b,c", "foo", ",")) → ERROR
Turns date
into a string according to the format
specified and in the optional timezone
.
Turns date
into text according to the format
specified and in the optional timezone
.
The format string can consist of the following characters. The characters ‘’, ‘:’, ‘,’, ‘T’, ‘-’ and ’_’ are ignored. Any other character is an error.
YY
- last two digits of year 0-99Returns num
formatted with the passed in number of decimal places
and optional commas
dividing thousands separators
@(format_num(31337)) → 31,337.00
-@(format_num(31337, 2)) → 31,337.00
-@(format_num(31337, 2, true)) → 31,337.00
-@(format_num(31337, 0, false)) → 31337
-@(format_num("foo", 2, false)) → ERROR
@(format_number(31337)) → 31,337.00
+@(format_number(31337, 2)) → 31,337.00
+@(format_number(31337, 2, true)) → 31,337.00
+@(format_number(31337, 0, false)) → 31337
+@(format_number("foo", 2, false)) → ERROR
Turns urn
into a human friendly string
Turns urn
into human friendly text
@(format_urn("tel:+250781234567")) → 0781 234 567
@(format_urn("twitter:134252511151#billy_bob")) → billy_bob
@(format_urn(contact.urns)) → (206) 555-1212
@@ -643,15 +643,15 @@ json(value)
@(json(10)) → 10
@(json(contact.uuid)) → "5d76d86b-3bb9-4d5a-b822-c9d86f5d8e4f"
Returns the count
most left characters of the passed in string
Returns the count
most left characters of the passed in text
@(left("hello", 2)) → he
@(left("hello", 7)) → hello
@(left("😀😃😄😁", 2)) → 😀😃
@(left("hello", -1)) → ERROR
Returns the length of the passed in string or array.
+Returns the length of the passed in text or array.
length will return an error if it is passed an item which doesn’t have length.
@(length("Hello")) → 5
@(length("😀😃😄😁")) → 4
@@ -659,8 +659,8 @@ length(value)
@(length(array("a", "b", "c"))) → 3
@(length(1234)) → ERROR
Lowercases the passed in string
Lowercases the passed in text
@(lower("HellO")) → hello
@(lower("hello")) → hello
@(lower("123")) → 123
@@ -704,9 +704,9 @@ or(tests…)
Returns whether if any of the passed in arguments are truthy
-
-parse_date(string, format [,timezone])
-Turns string
into a date according to the format
and optional timezone
specified
+
+parse_datetime(text, format [,timezone])
+Turns text
into a date according to the format
and optional timezone
specified
The format string can consist of the following characters. The characters ‘’, ‘:’, ‘,’, ‘T’, ‘-’ and ’_’ are ignored. Any other character is an error.
YY
- last two digits of year 0-99
@@ -732,20 +732,20 @@ parse_date(string, format [,timezone])
Timezone should be a location name as specified in the IANA Time Zone database, such as “America/Guayaquil” or “America/Los_Angeles”. If not specified the timezone of your environment will be used. An error will be returned if the timezone is not recognized.
Note that fractional seconds will be parsed even without an explicit format identifier. You should only specify fractional seconds when you want to assert the number of places in the input format.
-parse_date will return an error if it is unable to convert the string to a date.
-@(parse_date("1979-07-18", "YYYY-MM-DD")) → 1979-07-18T00:00:00.000000-05:00
-@(parse_date("2010 5 10", "YYYY M DD")) → 2010-05-10T00:00:00.000000-05:00
-@(parse_date("2010 5 10 12:50", "YYYY M DD tt:mm", "America/Los_Angeles")) → 2010-05-10T12:50:00.000000-07:00
-@(parse_date("NOT DATE", "YYYY-MM-DD")) → ERROR
+parse_datetime will return an error if it is unable to convert the text to a datetime.
+@(parse_datetime("1979-07-18", "YYYY-MM-DD")) → 1979-07-18T00:00:00.000000-05:00
+@(parse_datetime("2010 5 10", "YYYY M DD")) → 2010-05-10T00:00:00.000000-05:00
+@(parse_datetime("2010 5 10 12:50", "YYYY M DD tt:mm", "America/Los_Angeles")) → 2010-05-10T12:50:00.000000-07:00
+@(parse_datetime("NOT DATE", "YYYY-MM-DD")) → ERROR
-parse_json(string)
-Tries to parse string
as JSON, returning a fragment you can index into
+parse_json(text)
+Tries to parse text
as JSON, returning a fragment you can index into
If the passed in value is not JSON, then an error is returned
percent(num)
-Converts num
to a string represented as a percentage
+Converts num
to text represented as a percentage
@@ -767,22 +767,22 @@ read_code(code)
@(read_code("abc")) → a b c
@(read_code("abcdef")) → a b c , d e f
Removes the 1st word of string
Removes the 1st word of text
Return string
repeated count
number of times
Return text
repeated count
number of times
Replaces all occurrences of needle
with replacement
in string
Replaces all occurrences of needle
with replacement
in text
Returns the count
most right characters of the passed in string
Returns the count
most right characters of the passed in text
@(right("hello", 2)) → lo
@(right("hello", 7)) → hello
@(right("😀😃😄😁", 2)) → 😄😁
@@ -817,29 +817,29 @@ round_up(num [,places])
@(round_up(12.146, 2)) → 12.15
@(round_up("foo")) → ERROR
Splits string
based on the passed in delimeter
Splits text
based on the passed in delimeter
Empty values are removed from the returned list
@(split("a b c", " ")) → ["a","b","c"]
@(split("a", " ")) → ["a"]
@(split("abc..d", ".")) → ["abc","d"]
@(split("a.b.c.", ".")) → ["a","b","c"]
@(split("a && b && c", " && ")) → ["a","b","c"]
Tries to convert value
to a string. An error is returned if the value can’t be converted.
Returns the comparison between the strings str1
and str2
. The return value will be -1 if str1 is smaller than str2, 0 if they are equal and 1 if str1 is greater than str2
Tries to convert value
to text. An error is returned if the value can’t be converted.
Returns the comparison between the strings text1
and text2
. The return value will be -1 if str1 is smaller than str2, 0 if they are equal and 1 if str1 is greater than str2
@(text_compare("abc", "abc")) → 0
+@(text_compare("abc", "def")) → -1
+@(text_compare("zzz", "aaa")) → 1
Titlecases the passed in string
, capitalizing each word
Titlecases the passed in text
, capitalizing each word
Returns the offset for the timezone as a string +/- HHMM for date
Returns the offset for the timezone as text +/- HHMM for date
If no timezone information is present in the date, then the environment’s timezone offset will be returned
@(tz_offset("2017-01-15T02:15:18.123456Z")) → +0000
@(tz_offset("2017-01-15 02:15:18PM")) → -0500
@(tz_offset("2017-01-15")) → -0500
@(tz_offset("foo")) → ERROR
Uppercases all characters in the passed string
Uppercases all characters in the passed text
URL encodes string
for use in a URL parameter
URL encodes text
for use in a URL parameter
Returns the word at the passed in index
for the passed in string
Returns the word at the passed in index
for the passed in text
@(word("bee cat dog", 0)) → bee
@(word("bee.cat,dog", 0)) → bee
@(word("bee.cat,dog", 1)) → cat
@@ -892,15 +892,15 @@ word(string, index)
@(word("bee.cat,dog", -1)) → dog
@(word("bee.cat,dog", -2)) → cat
Returns the number of words in string
Returns the number of words in text
Extracts a substring from string
spanning from start
up to but not-including end
. (first word is 0). A negative end value means that all words after the start should be returned.
Extracts a substring from text
spanning from start
up to but not-including end
. (first word is 0). A negative end value means that all words after the start should be returned.
@(word_slice("bee cat dog", 0, 1)) → bee
@(word_slice("bee cat dog", 0, 2)) → bee cat
@(word_slice("bee cat dog", 1, -1)) → cat dog
@@ -912,66 +912,66 @@ Router Tests
Router tests are a special class of functions which are used within the switch router. They are called in the same way as normal functions, but all return a test result object which by default evalutes to true or false, but can also be used to find the matching portion of the test by using the match
component of the result. The flow editor builds these expressions using UI widgets, but they can be used anywhere a normal template function is used.
-has_all_words(string, words)
-Tests whether all the words
are contained in string
+has_all_words(text, words)
+Tests whether all the words
are contained in text
The words can be in any order and may appear more than once.
@(has_all_words("the quick brown FOX", "the fox")) → true
@(has_all_words("the quick brown FOX", "the fox").match) → the FOX
@(has_all_words("the quick brown fox", "red fox")) → false
-has_any_word(string, words)
-Tests whether any of the words
are contained in the string
+has_any_word(text, words)
+Tests whether any of the words
are contained in the text
Only one of the words needs to match and it may appear more than once.
@(has_any_word("The Quick Brown Fox", "fox quick")) → true
@(has_any_word("The Quick Brown Fox", "red fox")) → true
@(has_any_word("The Quick Brown Fox", "red fox").match) → Fox
-has_beginning(string, beginning)
-Tests whether string
starts with beginning
-Both strings are trimmed of surrounding whitespace, but otherwise matching is strict without any tokenization.
+has_beginning(text, beginning)
+Tests whether text
starts with beginning
+Both text values are trimmed of surrounding whitespace, but otherwise matching is strict without any tokenization.
@(has_beginning("The Quick Brown", "the quick")) → true
@(has_beginning("The Quick Brown", "the quick").match) → The Quick
@(has_beginning("The Quick Brown", "the quick")) → false
@(has_beginning("The Quick Brown", "quick brown")) → false
-has_date(string)
-Tests whether string
contains a date formatted according to our environment
+has_date(text)
+Tests whether text
contains a date formatted according to our environment
@(has_date("the date is 2017-01-15")) → true
@(has_date("the date is 2017-01-15").match) → 2017-01-15T00:00:00.000000-05:00
@(has_date("there is no date here, just a year 2017")) → false
-has_date_eq(string, date)
-Tests whether string
a date equal to date
+has_date_eq(text, date)
+Tests whether text
a date equal to date
@(has_date_eq("the date is 2017-01-15", "2017-01-15")) → true
@(has_date_eq("the date is 2017-01-15", "2017-01-15").match) → 2017-01-15T00:00:00.000000-05:00
@(has_date_eq("the date is 2017-01-15 15:00", "2017-01-15")) → false
@(has_date_eq("there is no date here, just a year 2017", "2017-06-01")) → false
@(has_date_eq("there is no date here, just a year 2017", "not date")) → ERROR
-has_date_gt(string, min)
-Tests whether string
a date after the date min
+has_date_gt(text, min)
+Tests whether text
a date after the date min
@(has_date_gt("the date is 2017-01-15", "2017-01-01")) → true
@(has_date_gt("the date is 2017-01-15", "2017-01-01").match) → 2017-01-15T00:00:00.000000-05:00
@(has_date_gt("the date is 2017-01-15", "2017-03-15")) → false
@(has_date_gt("there is no date here, just a year 2017", "2017-06-01")) → false
@(has_date_gt("there is no date here, just a year 2017", "not date")) → ERROR
-has_date_lt(string, max)
-Tests whether value
contains a date before the date max
+has_date_lt(text, max)
+Tests whether text
contains a date before the date max
@(has_date_lt("the date is 2017-01-15", "2017-06-01")) → true
@(has_date_lt("the date is 2017-01-15", "2017-06-01").match) → 2017-01-15T00:00:00.000000-05:00
@(has_date_lt("there is no date here, just a year 2017", "2017-06-01")) → false
@(has_date_lt("there is no date here, just a year 2017", "not date")) → ERROR
-has_district(string, state)
-Tests whether a district name is contained in the string
. If state
is also provided then the returned district must be within that state.
+has_district(text, state)
+Tests whether a district name is contained in the text
. If state
is also provided then the returned district must be within that state.
@(has_district("Gasabo", "Kigali")) → true
@(has_district("I live in Gasabo", "Kigali")) → true
@(has_district("Gasabo", "Boston")) → false
@(has_district("Gasabo")) → true
-has_email(string)
-Tests whether an email is contained in string
+has_email(text)
+Tests whether an email is contained in text
@(has_email("my email is foo1@bar.com, please respond")) → true
@(has_email("my email is foo1@bar.com, please respond").match) → foo1@bar.com
@(has_email("my email is <foo@bar2.com>")) → true
@@ -982,63 +982,63 @@ has_group(contact, group_uuid)
@(has_group(contact, "b7cf0d83-f1c9-411c-96fd-c511a4cfa86d")) → true
@(has_group(contact, "97fe7029-3a15-4005-b0c7-277b884fc1d5")) → false
-has_number(string)
-Tests whether string
contains a number
+has_number(text)
+Tests whether text
contains a number
@(has_number("the number is 42")) → true
@(has_number("the number is 42").match) → 42
@(has_number("the number is forty two")) → false
-has_number_between(string, min, max)
-Tests whether string
contains a number between min
and max
inclusive
+has_number_between(text, min, max)
+Tests whether text
contains a number between min
and max
inclusive
@(has_number_between("the number is 42", 40, 44)) → true
@(has_number_between("the number is 42", 40, 44).match) → 42
@(has_number_between("the number is 42", 50, 60)) → false
@(has_number_between("the number is not there", 50, 60)) → false
@(has_number_between("the number is not there", "foo", 60)) → ERROR
-has_number_eq(string, value)
-Tests whether strung
contains a number equal to the value
+has_number_eq(text, value)
+Tests whether text
contains a number equal to the value
@(has_number_eq("the number is 42", 42)) → true
@(has_number_eq("the number is 42", 42).match) → 42
@(has_number_eq("the number is 42", 40)) → false
@(has_number_eq("the number is not there", 40)) → false
@(has_number_eq("the number is not there", "foo")) → ERROR
-has_number_gt(string, min)
-Tests whether string
contains a number greater than min
+has_number_gt(text, min)
+Tests whether text
contains a number greater than min
@(has_number_gt("the number is 42", 40)) → true
@(has_number_gt("the number is 42", 40).match) → 42
@(has_number_gt("the number is 42", 42)) → false
@(has_number_gt("the number is not there", 40)) → false
@(has_number_gt("the number is not there", "foo")) → ERROR
-has_number_gte(string, min)
-Tests whether string
contains a number greater than or equal to min
+has_number_gte(text, min)
+Tests whether text
contains a number greater than or equal to min
@(has_number_gte("the number is 42", 42)) → true
@(has_number_gte("the number is 42", 42).match) → 42
@(has_number_gte("the number is 42", 45)) → false
@(has_number_gte("the number is not there", 40)) → false
@(has_number_gte("the number is not there", "foo")) → ERROR
-has_number_lt(string, max)
-Tests whether string
contains a number less than max
+has_number_lt(text, max)
+Tests whether text
contains a number less than max
@(has_number_lt("the number is 42", 44)) → true
@(has_number_lt("the number is 42", 44).match) → 42
@(has_number_lt("the number is 42", 40)) → false
@(has_number_lt("the number is not there", 40)) → false
@(has_number_lt("the number is not there", "foo")) → ERROR
-has_number_lte(string, max)
-Tests whether value
contains a number less than or equal to max
+has_number_lte(text, max)
+Tests whether text
contains a number less than or equal to max
@(has_number_lte("the number is 42", 42)) → true
@(has_number_lte("the number is 42", 44).match) → 42
@(has_number_lte("the number is 42", 40)) → false
@(has_number_lte("the number is not there", 40)) → false
@(has_number_lte("the number is not there", "foo")) → ERROR
-has_only_phrase(string, phrase)
-Tests whether the string
contains only phrase
-The phrase must be the only text in the string to match
+has_only_phrase(text, phrase)
+Tests whether the text
contains only phrase
+The phrase must be the only text in the text to match
@(has_only_phrase("The Quick Brown Fox", "quick brown")) → false
@(has_only_phrase("Quick Brown", "quick brown")) → true
@(has_only_phrase("the Quick Brown fox", "")) → false
@@ -1046,38 +1046,38 @@ has_only_phrase(string, phrase)
@(has_only_phrase("Quick Brown", "quick brown").match) → Quick Brown
@(has_only_phrase("The Quick Brown Fox", "red fox")) → false
-has_pattern(string, pattern)
-Tests whether string
matches the regex pattern
-Both strings are trimmed of surrounding whitespace and matching is case-insensitive.
+has_pattern(text, pattern)
+Tests whether text
matches the regex pattern
+Both text values are trimmed of surrounding whitespace and matching is case-insensitive.
@(has_pattern("Sell cheese please", "buy (\w+)")) → false
@(has_pattern("Buy cheese please", "buy (\w+)")) → true
@(has_pattern("Buy cheese please", "buy (\w+)").match) → Buy cheese
@(has_pattern("Buy cheese please", "buy (\w+)").match.groups[0]) → Buy cheese
@(has_pattern("Buy cheese please", "buy (\w+)").match.groups[1]) → cheese
-has_phone(string, country_code)
-Tests whether a phone number (in the passed in country_code
) is contained in the string
+has_phone(text, country_code)
+Tests whether a phone number (in the passed in country_code
) is contained in the text
@(has_phone("my number is 2067799294", "US")) → true
@(has_phone("my number is 206 779 9294", "US").match) → +12067799294
@(has_phone("my number is none of your business", "US")) → false
-has_phrase(string, phrase)
-Tests whether phrase
is contained in string
+has_phrase(text, phrase)
+Tests whether phrase
is contained in text
The words in the test phrase must appear in the same order with no other words in between.
@(has_phrase("the quick brown fox", "brown fox")) → true
@(has_phrase("the Quick Brown fox", "quick fox")) → false
@(has_phrase("the Quick Brown fox", "")) → true
@(has_phrase("the.quick.brown.fox", "the quick").match) → the quick
-has_state(string)
-Tests whether a state name is contained in the string
+has_state(text)
+Tests whether a state name is contained in the text
@(has_state("Kigali")) → true
@(has_state("Boston")) → false
@(has_state("¡Kigali!")) → true
@(has_state("I live in Kigali")) → true
-has_text(string)
-Tests whether there the string has any characters in it
+has_text(text)
+Tests whether there the text has any characters in it
@(has_text("quick brown")) → true
@(has_text("quick brown").match) → quick brown
@(has_text("")) → false
@@ -1096,8 +1096,8 @@ has_wait_timed_out(run)
Returns whether the last wait timed out.
-has_ward(string, district, state)
-Tests whether a ward name is contained in the string
+has_ward(text, district, state)
+Tests whether a ward name is contained in the text
@(has_ward("Gisozi", "Gasabo", "Kigali")) → true
@(has_ward("I live in Gisozi", "Gasabo", "Kigali")) → true
@(has_ward("Gisozi", "Gasabo", "Brooklyn")) → false
@@ -1113,16 +1113,16 @@ is_error(value)
@(is_error(run.not.existing)) → true
@(is_error(contact.fields.unset)) → true
@(is_error("hello")) → false
-
-is_string_eq(string, string)
-Returns whether two strings are equal (case sensitive). In the case that they are, it will return the string as the match.
-@(is_string_eq("foo", "foo")) → true
-@(is_string_eq("foo", "FOO")) → false
-@(is_string_eq("foo", "bar")) → false
-@(is_string_eq("foo", " foo ")) → false
-@(is_string_eq(run.status, "completed")) → true
-@(is_string_eq(run.webhook.status, "success")) → true
-@(is_string_eq(run.webhook.status, "connection_error")) → false
+
+is_text_eq(text1, text2)
+Returns whether two text values are equal (case sensitive). In the case that they are, it will return the text as the match.
+@(is_text_eq("foo", "foo")) → true
+@(is_text_eq("foo", "FOO")) → false
+@(is_text_eq("foo", "bar")) → false
+@(is_text_eq("foo", " foo ")) → false
+@(is_text_eq(run.status, "completed")) → true
+@(is_text_eq(run.webhook.status, "success")) → true
+@(is_text_eq(run.webhook.status, "connection_error")) → false
Action Definitions
Actions on a node generate events which can then be ingested by the engine container. In some cases the actions cause an immediate action, such as calling a webhook, in others the engine container is responsible for taking the action based on the event that is output, such as sending messages or updating contact fields. In either case the internal state of the engine is always updated to represent the new state so that flow execution is consistent. For example, while the engine itself does not have access to a contact store, it updates its internal representation of a contact’s state based on action performed on a flow so that later references in the flow are correct.
@@ -1615,7 +1615,7 @@
},
"age": {
"text": "23",
- "decimal": 23
+ "number": 23
},
"gender": {
"text": "Male"
diff --git a/excellent/evaluator.go b/excellent/evaluator.go
index a216528a7..dd23ad3ae 100644
--- a/excellent/evaluator.go
+++ b/excellent/evaluator.go
@@ -62,7 +62,7 @@ func EvaluateTemplate(env utils.Environment, context types.XValue, template stri
// if we had one, then just return our string evaluation strategy
if nextTT != EOF {
asStr, err := EvaluateTemplateAsString(env, context, template, false, allowedTopLevels)
- return types.NewXString(asStr), err
+ return types.NewXText(asStr), err
}
switch tokenType {
@@ -71,7 +71,7 @@ func EvaluateTemplate(env utils.Environment, context types.XValue, template stri
// didn't find it, our value is empty string
if value == nil {
- value = types.XStringEmpty
+ value = types.XTextEmpty
}
err, isErr := value.(error)
@@ -80,7 +80,7 @@ func EvaluateTemplate(env utils.Environment, context types.XValue, template stri
if isErr {
buf.WriteString("@")
buf.WriteString(token)
- return types.NewXString(buf.String()), err
+ return types.NewXText(buf.String()), err
}
// found it, return that value
@@ -89,7 +89,7 @@ func EvaluateTemplate(env utils.Environment, context types.XValue, template stri
case EXPRESSION:
value, err := EvaluateExpression(env, context, token)
if err != nil {
- return types.NewXString(buf.String()), err
+ return types.NewXText(buf.String()), err
}
return value, nil
@@ -97,7 +97,7 @@ func EvaluateTemplate(env utils.Environment, context types.XValue, template stri
// different type of token, return the string representation
asStr, err := EvaluateTemplateAsString(env, context, template, false, allowedTopLevels)
- return types.NewXString(asStr), err
+ return types.NewXText(asStr), err
}
// EvaluateTemplateAsString evaluates the passed in template returning the string value of its execution
@@ -115,16 +115,16 @@ func EvaluateTemplateAsString(env utils.Environment, context types.XValue, templ
// didn't find it, our value is empty string
if value == nil {
- value = types.XStringEmpty
+ value = types.XTextEmpty
}
// we got an error, return our raw variable
if types.IsXError(value) {
errors = append(errors, value.(types.XError))
} else {
- strValue, _ := types.ToXString(value)
+ strValue, _ := types.ToXText(value)
if urlEncode {
- strValue = types.NewXString(url.QueryEscape(strValue.Native()))
+ strValue = types.NewXText(url.QueryEscape(strValue.Native()))
}
buf.WriteString(strValue.Native())
@@ -135,9 +135,9 @@ func EvaluateTemplateAsString(env utils.Environment, context types.XValue, templ
if err != nil {
errors = append(errors, err)
} else {
- strValue, _ := types.ToXString(value)
+ strValue, _ := types.ToXText(value)
if urlEncode {
- strValue = types.NewXString(url.QueryEscape(strValue.Native()))
+ strValue = types.NewXText(url.QueryEscape(strValue.Native()))
}
buf.WriteString(strValue.Native())
diff --git a/excellent/evaluator_test.go b/excellent/evaluator_test.go
index 0c8c48316..3bc33e44f 100644
--- a/excellent/evaluator_test.go
+++ b/excellent/evaluator_test.go
@@ -11,10 +11,10 @@ import (
"github.com/stretchr/testify/assert"
)
-var xs = types.NewXString
+var xs = types.NewXText
var xn = types.RequireXNumberFromString
var xi = types.NewXNumberFromInt
-var xd = types.NewXDate
+var xd = types.NewXDateTime
type testXObject struct {
foo string
@@ -25,12 +25,12 @@ func NewTestXObject(foo string, bar int) *testXObject {
return &testXObject{foo: foo, bar: bar}
}
-func (v *testXObject) Reduce() types.XPrimitive { return types.NewXString(v.foo) }
+func (v *testXObject) Reduce() types.XPrimitive { return types.NewXText(v.foo) }
func (v *testXObject) Resolve(key string) types.XValue {
switch key {
case "foo":
- return types.NewXString("bar")
+ return types.NewXText("bar")
case "zed":
return types.NewXNumberFromInt(123)
case "missing":
@@ -41,7 +41,7 @@ func (v *testXObject) Resolve(key string) types.XValue {
}
// ToXJSON is called when this type is passed to @(json(...))
-func (v *testXObject) ToXJSON() types.XString {
+func (v *testXObject) ToXJSON() types.XText {
return types.ResolveKeys(v, "foo", "bar").ToXJSON()
}
@@ -51,15 +51,15 @@ var _ types.XResolvable = &testXObject{}
func TestEvaluateTemplateAsString(t *testing.T) {
vars := types.NewXMap(map[string]types.XValue{
- "string1": types.NewXString("foo"),
- "string2": types.NewXString("bar"),
- "汉字": types.NewXString("simplified chinese"),
+ "string1": types.NewXText("foo"),
+ "string2": types.NewXText("bar"),
+ "汉字": types.NewXText("simplified chinese"),
"int1": types.NewXNumberFromInt(1),
"int2": types.NewXNumberFromInt(2),
"dec1": types.RequireXNumberFromString("1.5"),
"dec2": types.RequireXNumberFromString("2.5"),
- "words": types.NewXString("one two three"),
- "array": types.NewXArray(types.NewXString("one"), types.NewXString("two"), types.NewXString("three")),
+ "words": types.NewXText("one two three"),
+ "array": types.NewXArray(types.NewXText("one"), types.NewXText("two"), types.NewXText("three")),
"thing": NewTestXObject("hello", 123),
"err": types.NewXError(fmt.Errorf("an error")),
})
@@ -153,18 +153,18 @@ func TestEvaluateTemplateAsString(t *testing.T) {
}
func TestEvaluateTemplate(t *testing.T) {
- array1d := types.NewXArray(types.NewXString("a"), types.NewXString("b"), types.NewXString("c"))
- array2d := types.NewXArray(array1d, types.NewXArray(types.NewXString("one"), types.NewXString("two"), types.NewXString("three")))
+ array1d := types.NewXArray(types.NewXText("a"), types.NewXText("b"), types.NewXText("c"))
+ array2d := types.NewXArray(array1d, types.NewXArray(types.NewXText("one"), types.NewXText("two"), types.NewXText("three")))
vars := types.NewXMap(map[string]types.XValue{
- "string1": types.NewXString("foo"),
- "string2": types.NewXString("bar"),
- "key": types.NewXString("four"),
+ "string1": types.NewXText("foo"),
+ "string2": types.NewXText("bar"),
+ "key": types.NewXText("four"),
"int1": types.NewXNumberFromInt(1),
"int2": types.NewXNumberFromInt(2),
"dec1": types.RequireXNumberFromString("1.5"),
"dec2": types.RequireXNumberFromString("2.5"),
- "words": types.NewXString("one two three"),
+ "words": types.NewXText("one two three"),
"array1d": array1d,
"array2d": array2d,
})
@@ -212,8 +212,8 @@ func TestEvaluateTemplate(t *testing.T) {
{"@(1*asdf)", xs(""), true},
{"@(asdf/1)", xs(""), true},
- {"@(false)", types.XBoolFalse, false},
- {"@(TRUE)", types.XBoolTrue, false},
+ {"@(false)", types.XBooleanFalse, false},
+ {"@(TRUE)", types.XBooleanTrue, false},
{"@(1+1+1)", xi(3), false},
{"@(5-2+1)", xi(4), false},
@@ -222,50 +222,50 @@ func TestEvaluateTemplate(t *testing.T) {
{"@(4/2*4)", xi(8), false},
{"@(2^2^2)", xi(16), false},
{"@(\"a\" & \"b\" & \"c\")", xs("abc"), false},
- {"@(1+3 <= 1+4)", types.XBoolTrue, false},
+ {"@(1+3 <= 1+4)", types.XBooleanTrue, false},
// string equality
- {`@("asdf" = "asdf")`, types.XBoolTrue, false},
- {`@("asdf" = "basf")`, types.XBoolFalse, false},
- {`@("asdf" = "ASDF")`, types.XBoolFalse, false}, // case-sensitive
- {`@("asdf" != "asdf")`, types.XBoolFalse, false},
- {`@("asdf" != "basf")`, types.XBoolTrue, false},
+ {`@("asdf" = "asdf")`, types.XBooleanTrue, false},
+ {`@("asdf" = "basf")`, types.XBooleanFalse, false},
+ {`@("asdf" = "ASDF")`, types.XBooleanFalse, false}, // case-sensitive
+ {`@("asdf" != "asdf")`, types.XBooleanFalse, false},
+ {`@("asdf" != "basf")`, types.XBooleanTrue, false},
// bool equality
- {"@(true = true)", types.XBoolTrue, false},
- {"@(true = false)", types.XBoolFalse, false},
- {"@(true = TRUE)", types.XBoolTrue, false},
+ {"@(true = true)", types.XBooleanTrue, false},
+ {"@(true = false)", types.XBooleanFalse, false},
+ {"@(true = TRUE)", types.XBooleanTrue, false},
// numerical equality
- {"@((1 = 1))", types.XBoolTrue, false},
- {"@((1 != 2))", types.XBoolTrue, false},
- {"@(1 = 1)", types.XBoolTrue, false},
- {"@(1 = 2)", types.XBoolFalse, false},
- {"@(1 != 2)", types.XBoolTrue, false},
- {"@(1 != 1)", types.XBoolFalse, false},
- {"@(-1 = 1)", types.XBoolFalse, false},
- {"@(1.0 = 1)", types.XBoolTrue, false},
- {"@(1.1 = 1.10)", types.XBoolTrue, false},
- {"@(1.1234 = 1.10)", types.XBoolFalse, false},
- {`@(1 = number("1.0"))`, types.XBoolTrue, false},
- {"@(11=11=11)", types.XBoolFalse, false}, // 11=11 -> TRUE, then TRUE != 11
+ {"@((1 = 1))", types.XBooleanTrue, false},
+ {"@((1 != 2))", types.XBooleanTrue, false},
+ {"@(1 = 1)", types.XBooleanTrue, false},
+ {"@(1 = 2)", types.XBooleanFalse, false},
+ {"@(1 != 2)", types.XBooleanTrue, false},
+ {"@(1 != 1)", types.XBooleanFalse, false},
+ {"@(-1 = 1)", types.XBooleanFalse, false},
+ {"@(1.0 = 1)", types.XBooleanTrue, false},
+ {"@(1.1 = 1.10)", types.XBooleanTrue, false},
+ {"@(1.1234 = 1.10)", types.XBooleanFalse, false},
+ {`@(1 = number("1.0"))`, types.XBooleanTrue, false},
+ {"@(11=11=11)", types.XBooleanFalse, false}, // 11=11 -> TRUE, then TRUE != 11
// date equality
- {`@(date("2018-04-16") = date("2018-04-16"))`, types.XBoolTrue, false},
- {`@(date("2018-04-16") != date("2018-04-16"))`, types.XBoolFalse, false},
- {`@(date("2018-04-16") = date("2017-03-20"))`, types.XBoolFalse, false},
- {`@(date("2018-04-16") != date("2017-03-20"))`, types.XBoolTrue, false},
+ {`@(date("2018-04-16") = date("2018-04-16"))`, types.XBooleanTrue, false},
+ {`@(date("2018-04-16") != date("2018-04-16"))`, types.XBooleanFalse, false},
+ {`@(date("2018-04-16") = date("2017-03-20"))`, types.XBooleanFalse, false},
+ {`@(date("2018-04-16") != date("2017-03-20"))`, types.XBooleanTrue, false},
{`@(date("xxx") == date("2017-03-20"))`, nil, true},
// other comparsions must be numerical
- {"@(2 > 1)", types.XBoolTrue, false},
- {"@(1 > 2)", types.XBoolFalse, false},
- {"@(2 >= 1)", types.XBoolTrue, false},
- {"@(1 >= 2)", types.XBoolFalse, false},
- {"@(1 <= 2)", types.XBoolTrue, false},
- {"@(2 <= 1)", types.XBoolFalse, false},
- {"@(1 < 2)", types.XBoolTrue, false},
- {"@(2 < 1)", types.XBoolFalse, false},
+ {"@(2 > 1)", types.XBooleanTrue, false},
+ {"@(1 > 2)", types.XBooleanFalse, false},
+ {"@(2 >= 1)", types.XBooleanTrue, false},
+ {"@(1 >= 2)", types.XBooleanFalse, false},
+ {"@(1 <= 2)", types.XBooleanTrue, false},
+ {"@(2 <= 1)", types.XBooleanFalse, false},
+ {"@(1 < 2)", types.XBooleanTrue, false},
+ {"@(2 < 1)", types.XBooleanFalse, false},
{`@(1 < "asdf")`, nil, true}, // can't use with strings
{`@("asdf" < "basf")`, nil, true},
{"@(1<2<3)", xs(""), true}, // can't chain
diff --git a/excellent/functions/functions.go b/excellent/functions/functions.go
index 72dfbc935..15ce5f95f 100644
--- a/excellent/functions/functions.go
+++ b/excellent/functions/functions.go
@@ -28,33 +28,33 @@ func RegisterXFunction(name string, function XFunction) {
// XFUNCTIONS is our map of functions available in Excellent which aren't tests
var XFUNCTIONS = map[string]XFunction{
// type conversion
- "string": OneArgFunction(String),
- "bool": OneArgFunction(Bool),
- "number": OneArgFunction(Number),
- "date": OneStringFunction(Date),
- "array": Array,
+ "text": OneArgFunction(Text),
+ "boolean": OneArgFunction(Boolean),
+ "number": OneArgFunction(Number),
+ "date": OneTextFunction(Date),
+ "array": Array,
- // string functions
+ // text functions
"char": OneNumberFunction(Char),
- "code": OneStringFunction(Code),
- "split": TwoStringFunction(Split),
+ "code": OneTextFunction(Code),
+ "split": TwoTextFunction(Split),
"join": TwoArgFunction(Join),
- "title": OneStringFunction(Title),
- "word": StringAndIntegerFunction(Word),
- "remove_first_word": OneStringFunction(RemoveFirstWord),
- "word_count": OneStringFunction(WordCount),
+ "title": OneTextFunction(Title),
+ "word": TextAndIntegerFunction(Word),
+ "remove_first_word": OneTextFunction(RemoveFirstWord),
+ "word_count": OneTextFunction(WordCount),
"word_slice": ArgCountCheck(2, 3, WordSlice),
"field": Field,
- "clean": OneStringFunction(Clean),
- "left": StringAndIntegerFunction(Left),
- "lower": OneStringFunction(Lower),
- "right": StringAndIntegerFunction(Right),
- "string_cmp": TwoStringFunction(StringCmp),
- "repeat": StringAndIntegerFunction(Repeat),
- "replace": ThreeStringFunction(Replace),
- "upper": OneStringFunction(Upper),
+ "clean": OneTextFunction(Clean),
+ "left": TextAndIntegerFunction(Left),
+ "lower": OneTextFunction(Lower),
+ "right": TextAndIntegerFunction(Right),
+ "text_compare": TwoTextFunction(TextCompare),
+ "repeat": TextAndIntegerFunction(Repeat),
+ "replace": ThreeTextFunction(Replace),
+ "upper": OneTextFunction(Upper),
"percent": OneNumberFunction(Percent),
- "url_encode": OneStringFunction(URLEncode),
+ "url_encode": OneTextFunction(URLEncode),
// bool functions
"and": And,
@@ -73,62 +73,62 @@ var XFUNCTIONS = map[string]XFunction{
"rand_between": TwoNumberFunction(RandBetween),
"abs": OneNumberFunction(Abs),
- // date functions
- "parse_date": ArgCountCheck(2, 3, ParseDate),
- "date_from_parts": DateFromParts,
- "date_diff": DateDiff,
- "date_add": DateAdd,
- "weekday": OneDateFunction(Weekday),
- "tz": OneDateFunction(TZ),
- "tz_offset": OneDateFunction(TZOffset),
- "today": NoArgFunction(Today),
- "now": NoArgFunction(Now),
- "from_epoch": OneNumberFunction(FromEpoch),
- "to_epoch": OneDateFunction(ToEpoch),
+ // datetime functions
+ "parse_datetime": ArgCountCheck(2, 3, ParseDateTime),
+ "datetime_from_parts": DateTimeFromParts,
+ "datetime_diff": DateTimeDiff,
+ "datetime_add": DateTimeAdd,
+ "weekday": OneDateTimeFunction(Weekday),
+ "tz": OneDateTimeFunction(TZ),
+ "tz_offset": OneDateTimeFunction(TZOffset),
+ "today": NoArgFunction(Today),
+ "now": NoArgFunction(Now),
+ "from_epoch": OneNumberFunction(FromEpoch),
+ "to_epoch": OneDateTimeFunction(ToEpoch),
// json functions
"json": OneArgFunction(JSON),
- "parse_json": OneStringFunction(ParseJSON),
+ "parse_json": OneTextFunction(ParseJSON),
// formatting functions
- "format_date": FormatDate,
- "format_num": FormatNum,
- "format_urn": FormatURN,
+ "format_date": FormatDate,
+ "format_number": FormatNumber,
+ "format_urn": FormatURN,
// utility functions
"length": OneArgFunction(Length),
"default": TwoArgFunction(Default),
"legacy_add": TwoArgFunction(LegacyAdd),
- "read_code": OneStringFunction(ReadCode),
+ "read_code": OneTextFunction(ReadCode),
}
//------------------------------------------------------------------------------------------
// Type Conversion Functions
//------------------------------------------------------------------------------------------
-// String tries to convert `value` to a string. An error is returned if the value can't be converted.
+// Text tries to convert `value` to text. An error is returned if the value can't be converted.
//
-// @(string(3 = 3)) -> true
-// @(json(string(123.45))) -> "123.45"
-// @(string(1 / 0)) -> ERROR
+// @(text(3 = 3)) -> true
+// @(json(text(123.45))) -> "123.45"
+// @(text(1 / 0)) -> ERROR
//
-// @function string(value)
-func String(env utils.Environment, value types.XValue) types.XValue {
- str, xerr := types.ToXString(value)
+// @function text(value)
+func Text(env utils.Environment, value types.XValue) types.XValue {
+ str, xerr := types.ToXText(value)
if xerr != nil {
return xerr
}
return str
}
-// Bool tries to convert `value` to a boolean. An error is returned if the value can't be converted.
+// Boolean tries to convert `value` to a boolean. An error is returned if the value can't be converted.
//
-// @(bool(array(1, 2))) -> true
-// @(bool("FALSE")) -> false
-// @(bool(1 / 0)) -> ERROR
+// @(boolean(array(1, 2))) -> true
+// @(boolean("FALSE")) -> false
+// @(boolean(1 / 0)) -> ERROR
//
-// @function bool(value)
-func Bool(env utils.Environment, value types.XValue) types.XValue {
+// @function boolean(value)
+func Boolean(env utils.Environment, value types.XValue) types.XValue {
str, xerr := types.ToXBool(value)
if xerr != nil {
return xerr
@@ -151,22 +151,22 @@ func Number(env utils.Environment, value types.XValue) types.XValue {
return num
}
-// Date turns `string` into a date according to the environment's settings. It will return an error
-// if it is unable to convert the string to a date.
+// Date turns `text` into a date according to the environment's settings. It will return an error
+// if it is unable to convert the text to a date.
//
// @(date("1979-07-18")) -> 1979-07-18T00:00:00.000000-05:00
// @(date("1979-07-18T10:30:45.123456Z")) -> 1979-07-18T10:30:45.123456Z
// @(date("2010 05 10")) -> 2010-05-10T00:00:00.000000-05:00
// @(date("NOT DATE")) -> ERROR
//
-// @function date(string)
-func Date(env utils.Environment, str types.XString) types.XValue {
+// @function date(text)
+func Date(env utils.Environment, str types.XText) types.XValue {
date, err := utils.DateFromString(env, str.Native())
if err != nil {
return types.NewXError(err)
}
- return types.NewXDate(date)
+ return types.NewXDateTime(date)
}
// Array takes a list of `values` and returns them as an array
@@ -202,10 +202,10 @@ func And(env utils.Environment, args ...types.XValue) types.XValue {
return err
}
if !asBool.Native() {
- return types.XBoolFalse
+ return types.XBooleanFalse
}
}
- return types.XBoolTrue
+ return types.XBooleanTrue
}
// Or returns whether if any of the passed in arguments are truthy
@@ -225,10 +225,10 @@ func Or(env utils.Environment, args ...types.XValue) types.XValue {
return err
}
if asBool.Native() {
- return types.XBoolTrue
+ return types.XBooleanTrue
}
}
- return types.XBoolFalse
+ return types.XBooleanFalse
}
// If evaluates the `test` argument, and if truthy returns `true_value`, if not returning `false_value`
@@ -252,10 +252,10 @@ func If(env utils.Environment, test types.XValue, arg1 types.XValue, arg2 types.
}
//------------------------------------------------------------------------------------------
-// String Functions
+// Text Functions
//------------------------------------------------------------------------------------------
-// Code returns the numeric code for the first character in `string`, it is the inverse of char
+// Code returns the numeric code for the first character in `text`, it is the inverse of char
//
// @(code("a")) -> 97
// @(code("abc")) -> 97
@@ -264,17 +264,17 @@ func If(env utils.Environment, test types.XValue, arg1 types.XValue, arg2 types.
// @(code(15)) -> 49
// @(code("")) -> ERROR
//
-// @function code(string)
-func Code(env utils.Environment, str types.XString) types.XValue {
- if str.Length() == 0 {
+// @function code(text)
+func Code(env utils.Environment, text types.XText) types.XValue {
+ if text.Length() == 0 {
return types.NewXErrorf("requires a string of at least one character")
}
- r, _ := utf8.DecodeRuneInString(str.Native())
+ r, _ := utf8.DecodeRuneInString(text.Native())
return types.NewXNumberFromInt(int(r))
}
-// Split splits `string` based on the passed in `delimeter`
+// Split splits `text` based on the passed in `delimeter`
//
// Empty values are removed from the returned list
//
@@ -284,13 +284,13 @@ func Code(env utils.Environment, str types.XString) types.XValue {
// @(split("a.b.c.", ".")) -> ["a","b","c"]
// @(split("a && b && c", " && ")) -> ["a","b","c"]
//
-// @function split(string, delimiter)
-func Split(env utils.Environment, s types.XString, sep types.XString) types.XValue {
+// @function split(text, delimiter)
+func Split(env utils.Environment, text types.XText, sep types.XText) types.XValue {
splits := types.NewXArray()
- allSplits := strings.Split(s.Native(), sep.Native())
+ allSplits := strings.Split(text.Native(), sep.Native())
for i := range allSplits {
if allSplits[i] != "" {
- splits.Append(types.NewXString(allSplits[i]))
+ splits.Append(types.NewXText(allSplits[i]))
}
}
return splits
@@ -308,7 +308,7 @@ func Join(env utils.Environment, array types.XValue, delimiter types.XValue) typ
return types.NewXErrorf("requires an indexable as its first argument")
}
- sep, err := types.ToXString(delimiter)
+ sep, err := types.ToXText(delimiter)
if err != nil {
return err
}
@@ -318,7 +318,7 @@ func Join(env utils.Environment, array types.XValue, delimiter types.XValue) typ
if i > 0 {
output.WriteString(sep.Native())
}
- itemAsStr, err := types.ToXString(indexable.Index(i))
+ itemAsStr, err := types.ToXText(indexable.Index(i))
if err != nil {
return err
}
@@ -326,7 +326,7 @@ func Join(env utils.Environment, array types.XValue, delimiter types.XValue) typ
output.WriteString(itemAsStr.Native())
}
- return types.NewXString(output.String())
+ return types.NewXText(output.String())
}
// Char returns the rune for the passed in codepoint, `num`, which may be unicode, this is the reverse of code
@@ -342,21 +342,21 @@ func Char(env utils.Environment, num types.XNumber) types.XValue {
return xerr
}
- return types.NewXString(string(rune(code)))
+ return types.NewXText(string(rune(code)))
}
-// Title titlecases the passed in `string`, capitalizing each word
+// Title titlecases the passed in `text`, capitalizing each word
//
// @(title("foo")) -> Foo
// @(title("ryan lewis")) -> Ryan Lewis
// @(title(123)) -> 123
//
-// @function title(string)
-func Title(env utils.Environment, str types.XString) types.XValue {
- return types.NewXString(strings.Title(str.Native()))
+// @function title(text)
+func Title(env utils.Environment, text types.XText) types.XValue {
+ return types.NewXText(strings.Title(text.Native()))
}
-// Word returns the word at the passed in `index` for the passed in `string`
+// Word returns the word at the passed in `index` for the passed in `text`
//
// @(word("bee cat dog", 0)) -> bee
// @(word("bee.cat,dog", 0)) -> bee
@@ -365,9 +365,9 @@ func Title(env utils.Environment, str types.XString) types.XValue {
// @(word("bee.cat,dog", -1)) -> dog
// @(word("bee.cat,dog", -2)) -> cat
//
-// @function word(string, index)
-func Word(env utils.Environment, str types.XString, index int) types.XValue {
- words := utils.TokenizeString(str.Native())
+// @function word(text, index)
+func Word(env utils.Environment, text types.XText, index int) types.XValue {
+ words := utils.TokenizeString(text.Native())
offset := index
if offset < 0 {
@@ -378,24 +378,24 @@ func Word(env utils.Environment, str types.XString, index int) types.XValue {
return types.NewXErrorf("index %d is out of range for the number of words %d", index, len(words))
}
- return types.NewXString(words[offset])
+ return types.NewXText(words[offset])
}
-// RemoveFirstWord removes the 1st word of `string`
+// RemoveFirstWord removes the 1st word of `text`
//
// @(remove_first_word("foo bar")) -> bar
//
-// @function remove_first_word(string)
-func RemoveFirstWord(env utils.Environment, str types.XString) types.XValue {
- words := utils.TokenizeString(str.Native())
+// @function remove_first_word(text)
+func RemoveFirstWord(env utils.Environment, text types.XText) types.XValue {
+ words := utils.TokenizeString(text.Native())
if len(words) > 1 {
- return types.NewXString(strings.Join(words[1:], " "))
+ return types.NewXText(strings.Join(words[1:], " "))
}
- return types.XStringEmpty
+ return types.XTextEmpty
}
-// WordSlice extracts a substring from `string` spanning from `start` up to but not-including `end`. (first word is 0). A negative
+// WordSlice extracts a substring from `text` spanning from `start` up to but not-including `end`. (first word is 0). A negative
// end value means that all words after the start should be returned.
//
// @(word_slice("bee cat dog", 0, 1)) -> bee
@@ -405,9 +405,9 @@ func RemoveFirstWord(env utils.Environment, str types.XString) types.XValue {
// @(word_slice("bee cat dog", 2, 3)) -> dog
// @(word_slice("bee cat dog", 3, 10)) ->
//
-// @function word_slice(string, start, end)
+// @function word_slice(text, start, end)
func WordSlice(env utils.Environment, args ...types.XValue) types.XValue {
- str, xerr := types.ToXString(args[0])
+ str, xerr := types.ToXText(args[0])
if xerr != nil {
return xerr
}
@@ -433,32 +433,32 @@ func WordSlice(env utils.Environment, args ...types.XValue) types.XValue {
words := utils.TokenizeString(str.Native())
if start >= len(words) {
- return types.XStringEmpty
+ return types.XTextEmpty
}
if end >= len(words) {
end = len(words)
}
if end > 0 {
- return types.NewXString(strings.Join(words[start:end], " "))
+ return types.NewXText(strings.Join(words[start:end], " "))
}
- return types.NewXString(strings.Join(words[start:], " "))
+ return types.NewXText(strings.Join(words[start:], " "))
}
-// WordCount returns the number of words in `string`
+// WordCount returns the number of words in `text`
//
// @(word_count("foo bar")) -> 2
// @(word_count(10)) -> 1
// @(word_count("")) -> 0
// @(word_count("😀😃😄😁")) -> 4
//
-// @function word_count(string)
-func WordCount(env utils.Environment, str types.XString) types.XValue {
- words := utils.TokenizeString(str.Native())
+// @function word_count(text)
+func WordCount(env utils.Environment, text types.XText) types.XValue {
+ words := utils.TokenizeString(text.Native())
return types.NewXNumberFromInt(len(words))
}
-// Field splits `string` based on the passed in `delimiter` and returns the field at `offset`. When splitting
+// Field splits `text` based on the passed in `delimiter` and returns the field at `offset`. When splitting
// with a space, the delimiter is considered to be all whitespace. (first field is 0)
//
// @(field("a,b,c", 1, ",")) -> b
@@ -468,9 +468,9 @@ func WordCount(env utils.Environment, str types.XString) types.XValue {
// @(field("a\t\tb\tc\td", 1, " ")) ->
// @(field("a,b,c", "foo", ",")) -> ERROR
//
-// @function field(string, offset, delimeter)
+// @function field(text, offset, delimeter)
func Field(env utils.Environment, args ...types.XValue) types.XValue {
- source, xerr := types.ToXString(args[0])
+ source, xerr := types.ToXText(args[0])
if xerr != nil {
return xerr
}
@@ -484,14 +484,14 @@ func Field(env utils.Environment, args ...types.XValue) types.XValue {
return types.NewXErrorf("cannot use a negative index to FIELD")
}
- sep, xerr := types.ToXString(args[2])
+ sep, xerr := types.ToXText(args[2])
if xerr != nil {
return xerr
}
fields := strings.Split(source.Native(), sep.Native())
if field >= len(fields) {
- return types.XStringEmpty
+ return types.XTextEmpty
}
// when using a space as a delimiter, we consider it splitting on whitespace, so remove empty values
@@ -505,29 +505,29 @@ func Field(env utils.Environment, args ...types.XValue) types.XValue {
fields = newFields
}
- return types.NewXString(strings.TrimSpace(fields[field]))
+ return types.NewXText(strings.TrimSpace(fields[field]))
}
-// Clean strips any leading or trailing whitespace from `string``
+// Clean strips any leading or trailing whitespace from `text`
//
// @(clean("\nfoo\t")) -> foo
// @(clean(" bar")) -> bar
// @(clean(123)) -> 123
//
-// @function clean(string)
-func Clean(env utils.Environment, str types.XString) types.XValue {
- return types.NewXString(strings.TrimSpace(str.Native()))
+// @function clean(text)
+func Clean(env utils.Environment, text types.XText) types.XValue {
+ return types.NewXText(strings.TrimSpace(text.Native()))
}
-// Left returns the `count` most left characters of the passed in `string`
+// Left returns the `count` most left characters of the passed in `text`
//
// @(left("hello", 2)) -> he
// @(left("hello", 7)) -> hello
// @(left("😀😃😄😁", 2)) -> 😀😃
// @(left("hello", -1)) -> ERROR
//
-// @function left(string, count)
-func Left(env utils.Environment, str types.XString, count int) types.XValue {
+// @function left(text, count)
+func Left(env utils.Environment, text types.XText, count int) types.XValue {
if count < 0 {
return types.NewXErrorf("can't take a negative count")
}
@@ -535,7 +535,7 @@ func Left(env utils.Environment, str types.XString, count int) types.XValue {
// this weird construct does the right thing for multi-byte unicode
var output bytes.Buffer
i := 0
- for _, r := range str.Native() {
+ for _, r := range text.Native() {
if i >= count {
break
}
@@ -543,102 +543,102 @@ func Left(env utils.Environment, str types.XString, count int) types.XValue {
i++
}
- return types.NewXString(output.String())
+ return types.NewXText(output.String())
}
-// Lower lowercases the passed in `string`
+// Lower lowercases the passed in `text`
//
// @(lower("HellO")) -> hello
// @(lower("hello")) -> hello
// @(lower("123")) -> 123
// @(lower("😀")) -> 😀
//
-// @function lower(string)
-func Lower(env utils.Environment, str types.XString) types.XValue {
- return types.NewXString(strings.ToLower(str.Native()))
+// @function lower(text)
+func Lower(env utils.Environment, text types.XText) types.XValue {
+ return types.NewXText(strings.ToLower(text.Native()))
}
-// Right returns the `count` most right characters of the passed in `string`
+// Right returns the `count` most right characters of the passed in `text`
//
// @(right("hello", 2)) -> lo
// @(right("hello", 7)) -> hello
// @(right("😀😃😄😁", 2)) -> 😄😁
// @(right("hello", -1)) -> ERROR
//
-// @function right(string, count)
-func Right(env utils.Environment, str types.XString, count int) types.XValue {
+// @function right(text, count)
+func Right(env utils.Environment, text types.XText, count int) types.XValue {
if count < 0 {
return types.NewXErrorf("can't take a negative count")
}
- start := utf8.RuneCountInString(str.Native()) - count
+ start := utf8.RuneCountInString(text.Native()) - count
// this weird construct does the right thing for multi-byte unicode
var output bytes.Buffer
i := 0
- for _, r := range str.Native() {
+ for _, r := range text.Native() {
if i >= start {
output.WriteRune(r)
}
i++
}
- return types.NewXString(output.String())
+ return types.NewXText(output.String())
}
-// StringCmp returns the comparison between the strings `str1` and `str2`.
+// TextCompare returns the comparison between the strings `text1` and `text2`.
// The return value will be -1 if str1 is smaller than str2, 0 if they
// are equal and 1 if str1 is greater than str2
//
-// @(string_cmp("abc", "abc")) -> 0
-// @(string_cmp("abc", "def")) -> -1
-// @(string_cmp("zzz", "aaa")) -> 1
+// @(text_compare("abc", "abc")) -> 0
+// @(text_compare("abc", "def")) -> -1
+// @(text_compare("zzz", "aaa")) -> 1
//
-// @function string_cmp(str1, str2)
-func StringCmp(env utils.Environment, str1 types.XString, str2 types.XString) types.XValue {
- return types.NewXNumberFromInt(str1.Compare(str2))
+// @function text_compare(text1, text2)
+func TextCompare(env utils.Environment, text1 types.XText, text2 types.XText) types.XValue {
+ return types.NewXNumberFromInt(text1.Compare(text2))
}
-// Repeat return `string` repeated `count` number of times
+// Repeat return `text` repeated `count` number of times
//
// @(repeat("*", 8)) -> ********
// @(repeat("*", "foo")) -> ERROR
//
-// @function repeat(string, count)
-func Repeat(env utils.Environment, str types.XString, count int) types.XValue {
+// @function repeat(text, count)
+func Repeat(env utils.Environment, text types.XText, count int) types.XValue {
if count < 0 {
return types.NewXErrorf("must be called with a positive integer, got %d", count)
}
var output bytes.Buffer
for j := 0; j < count; j++ {
- output.WriteString(str.Native())
+ output.WriteString(text.Native())
}
- return types.NewXString(output.String())
+ return types.NewXText(output.String())
}
-// Replace replaces all occurrences of `needle` with `replacement` in `string`
+// Replace replaces all occurrences of `needle` with `replacement` in `text`
//
// @(replace("foo bar", "foo", "zap")) -> zap bar
// @(replace("foo bar", "baz", "zap")) -> foo bar
//
-// @function replace(string, needle, replacement)
-func Replace(env utils.Environment, str types.XString, needle types.XString, replacement types.XString) types.XValue {
- return types.NewXString(strings.Replace(str.Native(), needle.Native(), replacement.Native(), -1))
+// @function replace(text, needle, replacement)
+func Replace(env utils.Environment, text types.XText, needle types.XText, replacement types.XText) types.XValue {
+ return types.NewXText(strings.Replace(text.Native(), needle.Native(), replacement.Native(), -1))
}
-// Upper uppercases all characters in the passed `string`
+// Upper uppercases all characters in the passed `text`
//
// @(upper("Asdf")) -> ASDF
// @(upper(123)) -> 123
//
-// @function upper(string)
-func Upper(env utils.Environment, str types.XString) types.XValue {
- return types.NewXString(strings.ToUpper(str.Native()))
+// @function upper(text)
+func Upper(env utils.Environment, text types.XText) types.XValue {
+ return types.NewXText(strings.ToUpper(text.Native()))
}
-// Percent converts `num` to a string represented as a percentage
+// Percent converts `num` to text represented as a percentage
//
// @(percent(0.54234)) -> 54%
// @(percent(1.2)) -> 120%
@@ -650,17 +650,17 @@ func Percent(env utils.Environment, num types.XNumber) types.XValue {
percent := num.Native().Mul(decimal.NewFromFloat(100)).Round(0)
// add on a %
- return types.NewXString(fmt.Sprintf("%d%%", percent.IntPart()))
+ return types.NewXText(fmt.Sprintf("%d%%", percent.IntPart()))
}
-// URLEncode URL encodes `string` for use in a URL parameter
+// URLEncode URL encodes `text` for use in a URL parameter
//
// @(url_encode("two words")) -> two+words
// @(url_encode(10)) -> 10
//
-// @function url_encode(string)
-func URLEncode(env utils.Environment, str types.XString) types.XValue {
- return types.NewXString(url.QueryEscape(str.Native()))
+// @function url_encode(text)
+func URLEncode(env utils.Environment, text types.XText) types.XValue {
+ return types.NewXText(url.QueryEscape(text.Native()))
}
//------------------------------------------------------------------------------------------
@@ -860,10 +860,10 @@ func RandBetween(env utils.Environment, min types.XNumber, max types.XNumber) ty
}
//------------------------------------------------------------------------------------------
-// Date Functions
+// Date & Time Functions
//------------------------------------------------------------------------------------------
-// ParseDate turns `string` into a date according to the `format` and optional `timezone` specified
+// ParseDateTime turns `text` into a date according to the `format` and optional `timezone` specified
//
// The format string can consist of the following characters. The characters
// ' ', ':', ',', 'T', '-' and '_' are ignored. Any other character is an error.
@@ -897,21 +897,21 @@ func RandBetween(env utils.Environment, min types.XNumber, max types.XNumber) ty
// You should only specify fractional seconds when you want to assert the number of places
// in the input format.
//
-// parse_date will return an error if it is unable to convert the string to a date.
+// parse_datetime will return an error if it is unable to convert the text to a datetime.
//
-// @(parse_date("1979-07-18", "YYYY-MM-DD")) -> 1979-07-18T00:00:00.000000-05:00
-// @(parse_date("2010 5 10", "YYYY M DD")) -> 2010-05-10T00:00:00.000000-05:00
-// @(parse_date("2010 5 10 12:50", "YYYY M DD tt:mm", "America/Los_Angeles")) -> 2010-05-10T12:50:00.000000-07:00
-// @(parse_date("NOT DATE", "YYYY-MM-DD")) -> ERROR
+// @(parse_datetime("1979-07-18", "YYYY-MM-DD")) -> 1979-07-18T00:00:00.000000-05:00
+// @(parse_datetime("2010 5 10", "YYYY M DD")) -> 2010-05-10T00:00:00.000000-05:00
+// @(parse_datetime("2010 5 10 12:50", "YYYY M DD tt:mm", "America/Los_Angeles")) -> 2010-05-10T12:50:00.000000-07:00
+// @(parse_datetime("NOT DATE", "YYYY-MM-DD")) -> ERROR
//
-// @function parse_date(string, format [,timezone])
-func ParseDate(env utils.Environment, args ...types.XValue) types.XValue {
- str, xerr := types.ToXString(args[0])
+// @function parse_datetime(text, format [,timezone])
+func ParseDateTime(env utils.Environment, args ...types.XValue) types.XValue {
+ str, xerr := types.ToXText(args[0])
if xerr != nil {
return xerr
}
- format, xerr := types.ToXString(args[1])
+ format, xerr := types.ToXText(args[1])
if xerr != nil {
return xerr
}
@@ -925,7 +925,7 @@ func ParseDate(env utils.Environment, args ...types.XValue) types.XValue {
// grab our location
location := env.Timezone()
if len(args) == 3 {
- tzStr, xerr := types.ToXString(args[2])
+ tzStr, xerr := types.ToXText(args[2])
if xerr != nil {
return xerr
}
@@ -942,17 +942,17 @@ func ParseDate(env utils.Environment, args ...types.XValue) types.XValue {
return types.NewXError(err)
}
- return types.NewXDate(parsed.In(location))
+ return types.NewXDateTime(parsed.In(location))
}
-// DateFromParts converts the passed in `year`, `month` and `day`
+// DateTimeFromParts converts the passed in `year`, `month` and `day`
//
-// @(date_from_parts(2017, 1, 15)) -> 2017-01-15T00:00:00.000000-05:00
-// @(date_from_parts(2017, 2, 31)) -> 2017-03-03T00:00:00.000000-05:00
-// @(date_from_parts(2017, 13, 15)) -> ERROR
+// @(datetime_from_parts(2017, 1, 15)) -> 2017-01-15T00:00:00.000000-05:00
+// @(datetime_from_parts(2017, 2, 31)) -> 2017-03-03T00:00:00.000000-05:00
+// @(datetime_from_parts(2017, 13, 15)) -> ERROR
//
-// @function date_from_parts(year, month, day)
-func DateFromParts(env utils.Environment, args ...types.XValue) types.XValue {
+// @function datetime_from_parts(year, month, day)
+func DateTimeFromParts(env utils.Environment, args ...types.XValue) types.XValue {
if len(args) != 3 {
return types.NewXErrorf("requires three arguments, got %d", len(args))
}
@@ -973,20 +973,20 @@ func DateFromParts(env utils.Environment, args ...types.XValue) types.XValue {
return xerr
}
- return types.NewXDate(time.Date(year, time.Month(month), day, 0, 0, 0, 0, env.Timezone()))
+ return types.NewXDateTime(time.Date(year, time.Month(month), day, 0, 0, 0, 0, env.Timezone()))
}
-// DateDiff returns the integer duration between `date1` and `date2` in the `unit` specified.
+// DateTimeDiff returns the integer duration between `date1` and `date2` in the `unit` specified.
//
// Valid durations are "Y" for years, "M" for months, "W" for weeks, "D" for days, "h" for hour,
// "m" for minutes, "s" for seconds
//
-// @(date_diff("2017-01-17", "2017-01-15", "D")) -> 2
-// @(date_diff("2017-01-17 10:50", "2017-01-17 12:30", "h")) -> -1
-// @(date_diff("2017-01-17", "2015-12-17", "Y")) -> 2
+// @(datetime_diff("2017-01-17", "2017-01-15", "D")) -> 2
+// @(datetime_diff("2017-01-17 10:50", "2017-01-17 12:30", "h")) -> -1
+// @(datetime_diff("2017-01-17", "2015-12-17", "Y")) -> 2
//
-// @function date_diff(date1, date2, unit)
-func DateDiff(env utils.Environment, args ...types.XValue) types.XValue {
+// @function datetime_diff(date1, date2, unit)
+func DateTimeDiff(env utils.Environment, args ...types.XValue) types.XValue {
if len(args) != 3 {
return types.NewXErrorf("takes exactly three arguments, received %d", len(args))
}
@@ -1001,7 +1001,7 @@ func DateDiff(env utils.Environment, args ...types.XValue) types.XValue {
return xerr
}
- unit, xerr := types.ToXString(args[2])
+ unit, xerr := types.ToXText(args[2])
if xerr != nil {
return xerr
}
@@ -1030,16 +1030,16 @@ func DateDiff(env utils.Environment, args ...types.XValue) types.XValue {
return types.NewXErrorf("unknown unit: %s, must be one of s, m, h, D, W, M, Y", unit)
}
-// DateAdd calculates the date value arrived at by adding `offset` number of `unit` to the `date`
+// DateTimeAdd calculates the date value arrived at by adding `offset` number of `unit` to the `date`
//
// Valid durations are "Y" for years, "M" for months, "W" for weeks, "D" for days, "h" for hour,
// "m" for minutes, "s" for seconds
//
-// @(date_add("2017-01-15", 5, "D")) -> 2017-01-20T00:00:00.000000-05:00
-// @(date_add("2017-01-15 10:45", 30, "m")) -> 2017-01-15T11:15:00.000000-05:00
+// @(datetime_add("2017-01-15", 5, "D")) -> 2017-01-20T00:00:00.000000-05:00
+// @(datetime_add("2017-01-15 10:45", 30, "m")) -> 2017-01-15T11:15:00.000000-05:00
//
-// @function date_add(date, offset, unit)
-func DateAdd(env utils.Environment, args ...types.XValue) types.XValue {
+// @function datetime_add(date, offset, unit)
+func DateTimeAdd(env utils.Environment, args ...types.XValue) types.XValue {
if len(args) != 3 {
return types.NewXErrorf("takes exactly three arguments, received %d", len(args))
}
@@ -1054,26 +1054,26 @@ func DateAdd(env utils.Environment, args ...types.XValue) types.XValue {
return xerr
}
- unit, xerr := types.ToXString(args[2])
+ unit, xerr := types.ToXText(args[2])
if xerr != nil {
return xerr
}
switch unit.Native() {
case "s":
- return types.NewXDate(date.Native().Add(time.Duration(duration) * time.Second))
+ return types.NewXDateTime(date.Native().Add(time.Duration(duration) * time.Second))
case "m":
- return types.NewXDate(date.Native().Add(time.Duration(duration) * time.Minute))
+ return types.NewXDateTime(date.Native().Add(time.Duration(duration) * time.Minute))
case "h":
- return types.NewXDate(date.Native().Add(time.Duration(duration) * time.Hour))
+ return types.NewXDateTime(date.Native().Add(time.Duration(duration) * time.Hour))
case "D":
- return types.NewXDate(date.Native().AddDate(0, 0, duration))
+ return types.NewXDateTime(date.Native().AddDate(0, 0, duration))
case "W":
- return types.NewXDate(date.Native().AddDate(0, 0, duration*7))
+ return types.NewXDateTime(date.Native().AddDate(0, 0, duration*7))
case "M":
- return types.NewXDate(date.Native().AddDate(0, duration, 0))
+ return types.NewXDateTime(date.Native().AddDate(0, duration, 0))
case "Y":
- return types.NewXDate(date.Native().AddDate(duration, 0, 0))
+ return types.NewXDateTime(date.Native().AddDate(duration, 0, 0))
}
return types.NewXErrorf("unknown unit: %s, must be one of s, m, h, D, W, M, Y", unit)
@@ -1085,7 +1085,7 @@ func DateAdd(env utils.Environment, args ...types.XValue) types.XValue {
// @(weekday("foo")) -> ERROR
//
// @function weekday(date)
-func Weekday(env utils.Environment, date types.XDate) types.XValue {
+func Weekday(env utils.Environment, date types.XDateTime) types.XValue {
return types.NewXNumberFromInt(int(date.Native().Weekday()))
}
@@ -1100,11 +1100,11 @@ func Weekday(env utils.Environment, date types.XDate) types.XValue {
// @(tz("foo")) -> ERROR
//
// @function tz(date)
-func TZ(env utils.Environment, date types.XDate) types.XValue {
- return types.NewXString(date.Native().Location().String())
+func TZ(env utils.Environment, date types.XDateTime) types.XValue {
+ return types.NewXText(date.Native().Location().String())
}
-// TZOffset returns the offset for the timezone as a string +/- HHMM for `date`
+// TZOffset returns the offset for the timezone as text +/- HHMM for `date`
//
// If no timezone information is present in the date, then the environment's
// timezone offset will be returned
@@ -1115,9 +1115,9 @@ func TZ(env utils.Environment, date types.XDate) types.XValue {
// @(tz_offset("foo")) -> ERROR
//
// @function tz_offset(date)
-func TZOffset(env utils.Environment, date types.XDate) types.XValue {
+func TZOffset(env utils.Environment, date types.XDateTime) types.XValue {
// this looks like we are returning a set offset, but this is how go describes formats
- return types.NewXString(date.Native().Format("-0700"))
+ return types.NewXText(date.Native().Format("-0700"))
}
@@ -1128,7 +1128,7 @@ func TZOffset(env utils.Environment, date types.XDate) types.XValue {
// @function today()
func Today(env utils.Environment) types.XValue {
nowTZ := env.Now()
- return types.NewXDate(time.Date(nowTZ.Year(), nowTZ.Month(), nowTZ.Day(), 0, 0, 0, 0, env.Timezone()))
+ return types.NewXDateTime(time.Date(nowTZ.Year(), nowTZ.Month(), nowTZ.Day(), 0, 0, 0, 0, env.Timezone()))
}
// FromEpoch returns a new date created from `num` which represents number of nanoseconds since January 1st, 1970 GMT
@@ -1137,7 +1137,7 @@ func Today(env utils.Environment) types.XValue {
//
// @function from_epoch(num)
func FromEpoch(env utils.Environment, num types.XNumber) types.XValue {
- return types.NewXDate(time.Unix(0, num.Native().IntPart()).In(env.Timezone()))
+ return types.NewXDateTime(time.Unix(0, num.Native().IntPart()).In(env.Timezone()))
}
// ToEpoch converts `date` to the number of nanoseconds since January 1st, 1970 GMT
@@ -1145,7 +1145,7 @@ func FromEpoch(env utils.Environment, num types.XNumber) types.XValue {
// @(to_epoch("2017-06-12T16:56:59.000000Z")) -> 1497286619000000000
//
// @function to_epoch(date)
-func ToEpoch(env utils.Environment, date types.XDate) types.XValue {
+func ToEpoch(env utils.Environment, date types.XDateTime) types.XValue {
return types.NewXNumberFromInt64(date.Native().UnixNano())
}
@@ -1155,23 +1155,23 @@ func ToEpoch(env utils.Environment, date types.XDate) types.XValue {
//
// @function now()
func Now(env utils.Environment) types.XValue {
- return types.NewXDate(env.Now())
+ return types.NewXDateTime(env.Now())
}
//------------------------------------------------------------------------------------------
// JSON Functions
//------------------------------------------------------------------------------------------
-// ParseJSON tries to parse `string` as JSON, returning a fragment you can index into
+// ParseJSON tries to parse `text` as JSON, returning a fragment you can index into
//
// If the passed in value is not JSON, then an error is returned
//
// @(parse_json("[1,2,3,4]").2) -> 3
// @(parse_json("invalid json")) -> ERROR
//
-// @function parse_json(string)
-func ParseJSON(env utils.Environment, str types.XString) types.XValue {
- return types.JSONToXValue([]byte(str.Native()))
+// @function parse_json(text)
+func ParseJSON(env utils.Environment, text types.XText) types.XValue {
+ return types.JSONToXValue([]byte(text.Native()))
}
// JSON tries to return a JSON representation of `value`. An error is returned if there is
@@ -1194,7 +1194,7 @@ func JSON(env utils.Environment, value types.XValue) types.XValue {
// Formatting Functions
//----------------------------------------------------------------------------------------
-// FormatDate turns `date` into a string according to the `format` specified and in
+// FormatDate turns `date` into text according to the `format` specified and in
// the optional `timezone`.
//
// The format string can consist of the following characters. The characters
@@ -1243,9 +1243,9 @@ func FormatDate(env utils.Environment, args ...types.XValue) types.XValue {
return xerr
}
- format := types.NewXString(fmt.Sprintf("%s %s", env.DateFormat().String(), env.TimeFormat().String()))
+ format := types.NewXText(fmt.Sprintf("%s %s", env.DateFormat().String(), env.TimeFormat().String()))
if len(args) >= 2 {
- format, xerr = types.ToXString(args[1])
+ format, xerr = types.ToXText(args[1])
if xerr != nil {
return xerr
}
@@ -1260,7 +1260,7 @@ func FormatDate(env utils.Environment, args ...types.XValue) types.XValue {
// grab our location
location := env.Timezone()
if len(args) == 3 {
- arg3, xerr := types.ToXString(args[2])
+ arg3, xerr := types.ToXText(args[2])
if xerr != nil {
return xerr
}
@@ -1273,23 +1273,23 @@ func FormatDate(env utils.Environment, args ...types.XValue) types.XValue {
// convert to our timezone if we have one (otherwise we remain in the date's default)
if location != nil {
- date = types.NewXDate(date.Native().In(location))
+ date = types.NewXDateTime(date.Native().In(location))
}
// return the formatted date
- return types.NewXString(date.Native().Format(goFormat))
+ return types.NewXText(date.Native().Format(goFormat))
}
-// FormatNum returns `num` formatted with the passed in number of decimal `places` and optional `commas` dividing thousands separators
+// FormatNumber returns `num` formatted with the passed in number of decimal `places` and optional `commas` dividing thousands separators
//
-// @(format_num(31337)) -> 31,337.00
-// @(format_num(31337, 2)) -> 31,337.00
-// @(format_num(31337, 2, true)) -> 31,337.00
-// @(format_num(31337, 0, false)) -> 31337
-// @(format_num("foo", 2, false)) -> ERROR
+// @(format_number(31337)) -> 31,337.00
+// @(format_number(31337, 2)) -> 31,337.00
+// @(format_number(31337, 2, true)) -> 31,337.00
+// @(format_number(31337, 0, false)) -> 31337
+// @(format_number("foo", 2, false)) -> ERROR
//
-// @function format_num(num, places, commas)
-func FormatNum(env utils.Environment, args ...types.XValue) types.XValue {
+// @function format_number(num, places, commas)
+func FormatNumber(env utils.Environment, args ...types.XValue) types.XValue {
if len(args) < 1 || len(args) > 3 {
return types.NewXErrorf("takes 1 to 3 arguments, got %d", len(args))
}
@@ -1309,7 +1309,7 @@ func FormatNum(env utils.Environment, args ...types.XValue) types.XValue {
}
}
- commas := types.XBoolTrue
+ commas := types.XBooleanTrue
if len(args) > 2 {
if commas, err = types.ToXBool(args[2]); err != nil {
return err
@@ -1329,10 +1329,10 @@ func FormatNum(env utils.Environment, args ...types.XValue) types.XValue {
}
}
f64, _ := num.Native().Float64()
- return types.NewXString(humanize.FormatFloat(formatStr.String(), f64))
+ return types.NewXText(humanize.FormatFloat(formatStr.String(), f64))
}
-// FormatURN turns `urn` into a human friendly string
+// FormatURN turns `urn` into human friendly text
//
// @(format_urn("tel:+250781234567")) -> 0781 234 567
// @(format_urn("twitter:134252511151#billy_bob")) -> billy_bob
@@ -1357,11 +1357,11 @@ func FormatURN(env utils.Environment, args ...types.XValue) types.XValue {
if indexable.Length() >= 1 {
urnArg = indexable.Index(0)
} else {
- return types.XStringEmpty
+ return types.XTextEmpty
}
}
- urnString, xerr := types.ToXString(urnArg)
+ urnString, xerr := types.ToXText(urnArg)
if xerr != nil {
return xerr
}
@@ -1372,14 +1372,14 @@ func FormatURN(env utils.Environment, args ...types.XValue) types.XValue {
return types.NewXErrorf("%s is not a valid URN: %s", urnString, err)
}
- return types.NewXString(urn.Format())
+ return types.NewXText(urn.Format())
}
//------------------------------------------------------------------------------------------
// Utility Functions
//------------------------------------------------------------------------------------------
-// Length returns the length of the passed in string or array.
+// Length returns the length of the passed in text or array.
//
// length will return an error if it is passed an item which doesn't have length.
//
@@ -1445,7 +1445,7 @@ func LegacyAdd(env utils.Environment, arg1 types.XValue, arg2 types.XValue) type
if dec2.Native().IntPart() < math.MinInt32 || dec2.Native().IntPart() > math.MaxInt32 {
return types.NewXErrorf("cannot operate on integers greater than 32 bit")
}
- return types.NewXDate(date1.Native().AddDate(0, 0, int(dec2.Native().IntPart())))
+ return types.NewXDateTime(date1.Native().AddDate(0, 0, int(dec2.Native().IntPart())))
}
// int and date, do a day addition
@@ -1453,7 +1453,7 @@ func LegacyAdd(env utils.Environment, arg1 types.XValue, arg2 types.XValue) type
if dec1.Native().IntPart() < math.MinInt32 || dec1.Native().IntPart() > math.MaxInt32 {
return types.NewXErrorf("cannot operate on integers greater than 32 bit")
}
- return types.NewXDate(date2.Native().AddDate(0, 0, int(dec1.Native().IntPart())))
+ return types.NewXDateTime(date2.Native().AddDate(0, 0, int(dec1.Native().IntPart())))
}
// one of these doesn't look like a valid decimal either, bail
@@ -1479,11 +1479,11 @@ func LegacyAdd(env utils.Environment, arg1 types.XValue, arg2 types.XValue) type
// @(read_code("abcdef")) -> a b c , d e f
//
// @function read_code(code)
-func ReadCode(env utils.Environment, val types.XString) types.XValue {
+func ReadCode(env utils.Environment, val types.XText) types.XValue {
var output bytes.Buffer
// remove any leading +
- val = types.NewXString(strings.TrimLeft(val.Native(), "+"))
+ val = types.NewXText(strings.TrimLeft(val.Native(), "+"))
length := val.Length()
@@ -1496,7 +1496,7 @@ func ReadCode(env utils.Environment, val types.XString) types.XValue {
}
output.WriteString(strings.Join(strings.Split(val.Native()[i:i+3], ""), " "))
}
- return types.NewXString(output.String())
+ return types.NewXText(output.String())
}
// groups of four
@@ -1507,7 +1507,7 @@ func ReadCode(env utils.Environment, val types.XString) types.XValue {
}
output.WriteString(strings.Join(strings.Split(val.Native()[i:i+4], ""), " "))
}
- return types.NewXString(output.String())
+ return types.NewXText(output.String())
}
// default, just do one at a time
@@ -1518,5 +1518,5 @@ func ReadCode(env utils.Environment, val types.XString) types.XValue {
output.WriteRune(c)
}
- return types.NewXString(output.String())
+ return types.NewXText(output.String())
}
diff --git a/excellent/functions/functions_test.go b/excellent/functions/functions_test.go
index 87e44bee6..f0c2b6b8d 100644
--- a/excellent/functions/functions_test.go
+++ b/excellent/functions/functions_test.go
@@ -15,10 +15,10 @@ import (
var errorArg = types.NewXErrorf("I am error")
var la, _ = time.LoadLocation("America/Los_Angeles")
-var xs = types.NewXString
+var xs = types.NewXText
var xn = types.RequireXNumberFromString
var xi = types.NewXNumberFromInt
-var xd = types.NewXDate
+var xd = types.NewXDateTime
var ERROR = types.NewXErrorf("any error")
@@ -27,9 +27,9 @@ var funcTests = []struct {
args []types.XValue
expected types.XValue
}{
- {"and", []types.XValue{types.XBoolTrue}, types.XBoolTrue},
- {"and", []types.XValue{types.XBoolFalse}, types.XBoolFalse},
- {"and", []types.XValue{types.XBoolTrue, types.XBoolFalse}, types.XBoolFalse},
+ {"and", []types.XValue{types.XBooleanTrue}, types.XBooleanTrue},
+ {"and", []types.XValue{types.XBooleanFalse}, types.XBooleanFalse},
+ {"and", []types.XValue{types.XBooleanTrue, types.XBooleanFalse}, types.XBooleanFalse},
{"and", []types.XValue{}, ERROR},
{"char", []types.XValue{xn("33")}, xs("!")},
@@ -37,14 +37,14 @@ var funcTests = []struct {
{"char", []types.XValue{xs("not a number")}, ERROR},
{"char", []types.XValue{}, ERROR},
- {"or", []types.XValue{types.XBoolTrue}, types.XBoolTrue},
- {"or", []types.XValue{types.XBoolFalse}, types.XBoolFalse},
- {"or", []types.XValue{types.XBoolTrue, types.XBoolFalse}, types.XBoolTrue},
+ {"or", []types.XValue{types.XBooleanTrue}, types.XBooleanTrue},
+ {"or", []types.XValue{types.XBooleanFalse}, types.XBooleanFalse},
+ {"or", []types.XValue{types.XBooleanTrue, types.XBooleanFalse}, types.XBooleanTrue},
{"or", []types.XValue{}, ERROR},
- {"if", []types.XValue{types.XBoolTrue, xs("10"), xs("20")}, xs("10")},
- {"if", []types.XValue{types.XBoolFalse, xs("10"), xs("20")}, xs("20")},
- {"if", []types.XValue{types.XBoolTrue, errorArg, xs("20")}, errorArg},
+ {"if", []types.XValue{types.XBooleanTrue, xs("10"), xs("20")}, xs("10")},
+ {"if", []types.XValue{types.XBooleanFalse, xs("10"), xs("20")}, xs("20")},
+ {"if", []types.XValue{types.XBooleanTrue, errorArg, xs("20")}, errorArg},
{"if", []types.XValue{}, ERROR},
{"if", []types.XValue{errorArg, xs("10"), xs("20")}, errorArg},
@@ -186,11 +186,11 @@ var funcTests = []struct {
{"length", []types.XValue{types.NewXArray()}, xi(0)},
{"length", []types.XValue{}, ERROR},
- {"string_cmp", []types.XValue{xs("abc"), xs("abc")}, xi(0)},
- {"string_cmp", []types.XValue{xs("abc"), xs("def")}, xi(-1)},
- {"string_cmp", []types.XValue{xs("def"), xs("abc")}, xi(1)},
- {"string_cmp", []types.XValue{xs("abc"), types.NewXErrorf("error")}, ERROR},
- {"string_cmp", []types.XValue{}, ERROR},
+ {"text_compare", []types.XValue{xs("abc"), xs("abc")}, xi(0)},
+ {"text_compare", []types.XValue{xs("abc"), xs("def")}, xi(-1)},
+ {"text_compare", []types.XValue{xs("def"), xs("abc")}, xi(1)},
+ {"text_compare", []types.XValue{xs("abc"), types.NewXErrorf("error")}, ERROR},
+ {"text_compare", []types.XValue{}, ERROR},
{"default", []types.XValue{xs("10"), xs("20")}, xs("10")},
{"default", []types.XValue{nil, xs("20")}, xs("20")},
@@ -239,52 +239,52 @@ var funcTests = []struct {
{"format_date", []types.XValue{xs("1977-06-23T15:34:00.000000Z"), xs("YY-MM-DD h:mm:ss AA"), xs("America/Los_Angeles")}, xs("77-06-23 8:34:00 AM")},
{"format_date", []types.XValue{xs("1977-06-23T08:34:00.000-07:00"), xs("YYYY-MM-DDTtt:mm:ss.fffZ"), xs("UTC")}, xs("1977-06-23T15:34:00.000Z")},
- {"parse_date", []types.XValue{xs("1977-06-23T15:34:00.000000Z"), xs("YYYY-MM-DDTtt:mm:ss.ffffffZ"), xs("America/Los_Angeles")}, xd(time.Date(1977, 06, 23, 8, 34, 0, 0, la))},
- {"parse_date", []types.XValue{xs("1977-06-23T15:34:00.1234Z"), xs("YYYY-MM-DDTtt:mm:ssZ"), xs("America/Los_Angeles")}, xd(time.Date(1977, 06, 23, 8, 34, 0, 123400000, la))},
- {"parse_date", []types.XValue{xs("1977-06-23 15:34"), xs("YYYY-MM-DD tt:mm"), xs("America/Los_Angeles")}, xd(time.Date(1977, 06, 23, 15, 34, 0, 0, la))},
- {"parse_date", []types.XValue{xs("1977-06-23 03:34 pm"), xs("YYYY-MM-DD tt:mm aa"), xs("America/Los_Angeles")}, xd(time.Date(1977, 06, 23, 15, 34, 0, 0, la))},
- {"parse_date", []types.XValue{xs("1977-06-23 03:34 PM"), xs("YYYY-MM-DD tt:mm AA"), xs("America/Los_Angeles")}, xd(time.Date(1977, 06, 23, 15, 34, 0, 0, la))},
-
- {"date_diff", []types.XValue{xs("03-12-2017"), xs("01-12-2017"), xs("D")}, xi(2)},
- {"date_diff", []types.XValue{xs("03-12-2017 10:15"), xs("03-12-2017 18:15"), xs("D")}, xi(0)},
- {"date_diff", []types.XValue{xs("03-12-2017"), xs("01-12-2017"), xs("W")}, xi(0)},
- {"date_diff", []types.XValue{xs("22-12-2017"), xs("01-12-2017"), xs("W")}, xi(3)},
- {"date_diff", []types.XValue{xs("03-12-2017"), xs("03-12-2017"), xs("M")}, xi(0)},
- {"date_diff", []types.XValue{xs("01-05-2018"), xs("03-12-2017"), xs("M")}, xi(5)},
- {"date_diff", []types.XValue{xs("01-12-2018"), xs("03-12-2017"), xs("Y")}, xi(1)},
- {"date_diff", []types.XValue{xs("01-01-2017"), xs("03-12-2017"), xs("Y")}, xi(0)},
- {"date_diff", []types.XValue{xs("04-12-2018 10:15"), xs("03-12-2018 14:00"), xs("h")}, xi(20)},
- {"date_diff", []types.XValue{xs("04-12-2018 10:15"), xs("04-12-2018 14:00"), xs("h")}, xi(-3)},
- {"date_diff", []types.XValue{xs("04-12-2018 10:15"), xs("04-12-2018 14:00"), xs("m")}, xi(-225)},
- {"date_diff", []types.XValue{xs("05-12-2018 10:15:15"), xs("05-12-2018 10:15:35"), xs("m")}, xi(0)},
- {"date_diff", []types.XValue{xs("05-12-2018 10:15:15"), xs("05-12-2018 10:16:10"), xs("m")}, xi(0)},
- {"date_diff", []types.XValue{xs("05-12-2018 10:15:15"), xs("05-12-2018 10:15:35"), xs("s")}, xi(-20)},
- {"date_diff", []types.XValue{xs("05-12-2018 10:15:15"), xs("05-12-2018 10:16:10"), xs("s")}, xi(-55)},
- {"date_diff", []types.XValue{xs("03-12-2017"), xs("01-12-2017"), xs("Z")}, ERROR},
- {"date_diff", []types.XValue{xs("xxx"), xs("01-12-2017"), xs("Y")}, ERROR},
- {"date_diff", []types.XValue{xs("01-12-2017"), xs("xxx"), xs("Y")}, ERROR},
- {"date_diff", []types.XValue{xs("01-12-2017"), xs("01-12-2017"), xs("xxx")}, ERROR},
- {"date_diff", []types.XValue{}, ERROR},
-
- {"date_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("2"), xs("Y")}, xd(time.Date(2019, 12, 03, 22, 15, 0, 0, time.UTC))},
- {"date_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("-2"), xs("Y")}, xd(time.Date(2015, 12, 03, 22, 15, 0, 0, time.UTC))},
- {"date_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("2"), xs("M")}, xd(time.Date(2018, 2, 03, 22, 15, 0, 0, time.UTC))},
- {"date_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("-2"), xs("M")}, xd(time.Date(2017, 10, 3, 22, 15, 0, 0, time.UTC))},
- {"date_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("2"), xs("W")}, xd(time.Date(2017, 12, 17, 22, 15, 0, 0, time.UTC))},
- {"date_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("-2"), xs("W")}, xd(time.Date(2017, 11, 19, 22, 15, 0, 0, time.UTC))},
- {"date_add", []types.XValue{xs("03-12-2017"), xs("2"), xs("D")}, xd(time.Date(2017, 12, 5, 0, 0, 0, 0, time.UTC))},
- {"date_add", []types.XValue{xs("03-12-2017"), xs("-4"), xs("D")}, xd(time.Date(2017, 11, 29, 0, 0, 0, 0, time.UTC))},
- {"date_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("2"), xs("h")}, xd(time.Date(2017, 12, 4, 0, 15, 0, 0, time.UTC))},
- {"date_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("-2"), xs("h")}, xd(time.Date(2017, 12, 3, 20, 15, 0, 0, time.UTC))},
- {"date_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("105"), xs("m")}, xd(time.Date(2017, 12, 4, 0, 0, 0, 0, time.UTC))},
- {"date_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("-20"), xs("m")}, xd(time.Date(2017, 12, 3, 21, 55, 0, 0, time.UTC))},
- {"date_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("2"), xs("s")}, xd(time.Date(2017, 12, 3, 22, 15, 2, 0, time.UTC))},
- {"date_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("-2"), xs("s")}, xd(time.Date(2017, 12, 3, 22, 14, 58, 0, time.UTC))},
- {"date_add", []types.XValue{xs("xxx"), xs("2"), xs("D")}, ERROR},
- {"date_add", []types.XValue{xs("03-12-2017 10:15"), xs("xxx"), xs("D")}, ERROR},
- {"date_add", []types.XValue{xs("03-12-2017 10:15"), xs("2"), xs("xxx")}, ERROR},
- {"date_add", []types.XValue{xs("03-12-2017"), xs("2"), xs("Z")}, ERROR},
- {"date_add", []types.XValue{xs("22-12-2017")}, ERROR},
+ {"parse_datetime", []types.XValue{xs("1977-06-23T15:34:00.000000Z"), xs("YYYY-MM-DDTtt:mm:ss.ffffffZ"), xs("America/Los_Angeles")}, xd(time.Date(1977, 06, 23, 8, 34, 0, 0, la))},
+ {"parse_datetime", []types.XValue{xs("1977-06-23T15:34:00.1234Z"), xs("YYYY-MM-DDTtt:mm:ssZ"), xs("America/Los_Angeles")}, xd(time.Date(1977, 06, 23, 8, 34, 0, 123400000, la))},
+ {"parse_datetime", []types.XValue{xs("1977-06-23 15:34"), xs("YYYY-MM-DD tt:mm"), xs("America/Los_Angeles")}, xd(time.Date(1977, 06, 23, 15, 34, 0, 0, la))},
+ {"parse_datetime", []types.XValue{xs("1977-06-23 03:34 pm"), xs("YYYY-MM-DD tt:mm aa"), xs("America/Los_Angeles")}, xd(time.Date(1977, 06, 23, 15, 34, 0, 0, la))},
+ {"parse_datetime", []types.XValue{xs("1977-06-23 03:34 PM"), xs("YYYY-MM-DD tt:mm AA"), xs("America/Los_Angeles")}, xd(time.Date(1977, 06, 23, 15, 34, 0, 0, la))},
+
+ {"datetime_diff", []types.XValue{xs("03-12-2017"), xs("01-12-2017"), xs("D")}, xi(2)},
+ {"datetime_diff", []types.XValue{xs("03-12-2017 10:15"), xs("03-12-2017 18:15"), xs("D")}, xi(0)},
+ {"datetime_diff", []types.XValue{xs("03-12-2017"), xs("01-12-2017"), xs("W")}, xi(0)},
+ {"datetime_diff", []types.XValue{xs("22-12-2017"), xs("01-12-2017"), xs("W")}, xi(3)},
+ {"datetime_diff", []types.XValue{xs("03-12-2017"), xs("03-12-2017"), xs("M")}, xi(0)},
+ {"datetime_diff", []types.XValue{xs("01-05-2018"), xs("03-12-2017"), xs("M")}, xi(5)},
+ {"datetime_diff", []types.XValue{xs("01-12-2018"), xs("03-12-2017"), xs("Y")}, xi(1)},
+ {"datetime_diff", []types.XValue{xs("01-01-2017"), xs("03-12-2017"), xs("Y")}, xi(0)},
+ {"datetime_diff", []types.XValue{xs("04-12-2018 10:15"), xs("03-12-2018 14:00"), xs("h")}, xi(20)},
+ {"datetime_diff", []types.XValue{xs("04-12-2018 10:15"), xs("04-12-2018 14:00"), xs("h")}, xi(-3)},
+ {"datetime_diff", []types.XValue{xs("04-12-2018 10:15"), xs("04-12-2018 14:00"), xs("m")}, xi(-225)},
+ {"datetime_diff", []types.XValue{xs("05-12-2018 10:15:15"), xs("05-12-2018 10:15:35"), xs("m")}, xi(0)},
+ {"datetime_diff", []types.XValue{xs("05-12-2018 10:15:15"), xs("05-12-2018 10:16:10"), xs("m")}, xi(0)},
+ {"datetime_diff", []types.XValue{xs("05-12-2018 10:15:15"), xs("05-12-2018 10:15:35"), xs("s")}, xi(-20)},
+ {"datetime_diff", []types.XValue{xs("05-12-2018 10:15:15"), xs("05-12-2018 10:16:10"), xs("s")}, xi(-55)},
+ {"datetime_diff", []types.XValue{xs("03-12-2017"), xs("01-12-2017"), xs("Z")}, ERROR},
+ {"datetime_diff", []types.XValue{xs("xxx"), xs("01-12-2017"), xs("Y")}, ERROR},
+ {"datetime_diff", []types.XValue{xs("01-12-2017"), xs("xxx"), xs("Y")}, ERROR},
+ {"datetime_diff", []types.XValue{xs("01-12-2017"), xs("01-12-2017"), xs("xxx")}, ERROR},
+ {"datetime_diff", []types.XValue{}, ERROR},
+
+ {"datetime_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("2"), xs("Y")}, xd(time.Date(2019, 12, 03, 22, 15, 0, 0, time.UTC))},
+ {"datetime_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("-2"), xs("Y")}, xd(time.Date(2015, 12, 03, 22, 15, 0, 0, time.UTC))},
+ {"datetime_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("2"), xs("M")}, xd(time.Date(2018, 2, 03, 22, 15, 0, 0, time.UTC))},
+ {"datetime_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("-2"), xs("M")}, xd(time.Date(2017, 10, 3, 22, 15, 0, 0, time.UTC))},
+ {"datetime_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("2"), xs("W")}, xd(time.Date(2017, 12, 17, 22, 15, 0, 0, time.UTC))},
+ {"datetime_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("-2"), xs("W")}, xd(time.Date(2017, 11, 19, 22, 15, 0, 0, time.UTC))},
+ {"datetime_add", []types.XValue{xs("03-12-2017"), xs("2"), xs("D")}, xd(time.Date(2017, 12, 5, 0, 0, 0, 0, time.UTC))},
+ {"datetime_add", []types.XValue{xs("03-12-2017"), xs("-4"), xs("D")}, xd(time.Date(2017, 11, 29, 0, 0, 0, 0, time.UTC))},
+ {"datetime_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("2"), xs("h")}, xd(time.Date(2017, 12, 4, 0, 15, 0, 0, time.UTC))},
+ {"datetime_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("-2"), xs("h")}, xd(time.Date(2017, 12, 3, 20, 15, 0, 0, time.UTC))},
+ {"datetime_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("105"), xs("m")}, xd(time.Date(2017, 12, 4, 0, 0, 0, 0, time.UTC))},
+ {"datetime_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("-20"), xs("m")}, xd(time.Date(2017, 12, 3, 21, 55, 0, 0, time.UTC))},
+ {"datetime_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("2"), xs("s")}, xd(time.Date(2017, 12, 3, 22, 15, 2, 0, time.UTC))},
+ {"datetime_add", []types.XValue{xs("03-12-2017 10:15pm"), xs("-2"), xs("s")}, xd(time.Date(2017, 12, 3, 22, 14, 58, 0, time.UTC))},
+ {"datetime_add", []types.XValue{xs("xxx"), xs("2"), xs("D")}, ERROR},
+ {"datetime_add", []types.XValue{xs("03-12-2017 10:15"), xs("xxx"), xs("D")}, ERROR},
+ {"datetime_add", []types.XValue{xs("03-12-2017 10:15"), xs("2"), xs("xxx")}, ERROR},
+ {"datetime_add", []types.XValue{xs("03-12-2017"), xs("2"), xs("Z")}, ERROR},
+ {"datetime_add", []types.XValue{xs("22-12-2017")}, ERROR},
{"weekday", []types.XValue{xs("01-12-2017")}, xi(5)},
{"weekday", []types.XValue{xs("01-12-2017 10:15pm")}, xi(5)},
diff --git a/excellent/functions/wrappers.go b/excellent/functions/wrappers.go
index d989a901d..498f9cdc9 100644
--- a/excellent/functions/wrappers.go
+++ b/excellent/functions/wrappers.go
@@ -50,10 +50,10 @@ func ThreeArgFunction(f func(utils.Environment, types.XValue, types.XValue, type
})
}
-// OneStringFunction creates an XFunction from a single string function
-func OneStringFunction(f func(utils.Environment, types.XString) types.XValue) XFunction {
+// OneTextFunction creates an XFunction from a function that takes a single text arg
+func OneTextFunction(f func(utils.Environment, types.XText) types.XValue) XFunction {
return ArgCountCheck(1, 1, func(env utils.Environment, args ...types.XValue) types.XValue {
- str, xerr := types.ToXString(args[0])
+ str, xerr := types.ToXText(args[0])
if xerr != nil {
return xerr
}
@@ -61,14 +61,14 @@ func OneStringFunction(f func(utils.Environment, types.XString) types.XValue) XF
})
}
-// TwoStringFunction creates an XFunction from a function that takes two strings
-func TwoStringFunction(f func(utils.Environment, types.XString, types.XString) types.XValue) XFunction {
+// TwoTextFunction creates an XFunction from a function that takes two text args
+func TwoTextFunction(f func(utils.Environment, types.XText, types.XText) types.XValue) XFunction {
return ArgCountCheck(2, 2, func(env utils.Environment, args ...types.XValue) types.XValue {
- str1, xerr := types.ToXString(args[0])
+ str1, xerr := types.ToXText(args[0])
if xerr != nil {
return xerr
}
- str2, xerr := types.ToXString(args[1])
+ str2, xerr := types.ToXText(args[1])
if xerr != nil {
return xerr
}
@@ -76,18 +76,18 @@ func TwoStringFunction(f func(utils.Environment, types.XString, types.XString) t
})
}
-// ThreeStringFunction creates an XFunction from a function that takes three strings
-func ThreeStringFunction(f func(utils.Environment, types.XString, types.XString, types.XString) types.XValue) XFunction {
+// ThreeTextFunction creates an XFunction from a function that takes three text args
+func ThreeTextFunction(f func(utils.Environment, types.XText, types.XText, types.XText) types.XValue) XFunction {
return ArgCountCheck(3, 3, func(env utils.Environment, args ...types.XValue) types.XValue {
- str1, xerr := types.ToXString(args[0])
+ str1, xerr := types.ToXText(args[0])
if xerr != nil {
return xerr
}
- str2, xerr := types.ToXString(args[1])
+ str2, xerr := types.ToXText(args[1])
if xerr != nil {
return xerr
}
- str3, xerr := types.ToXString(args[2])
+ str3, xerr := types.ToXText(args[2])
if xerr != nil {
return xerr
}
@@ -95,10 +95,10 @@ func ThreeStringFunction(f func(utils.Environment, types.XString, types.XString,
})
}
-// StringAndNumberFunction creates an XFunction from a function that takes a string and a number
-func StringAndNumberFunction(f func(utils.Environment, types.XString, types.XNumber) types.XValue) XFunction {
+// TextAndNumberFunction creates an XFunction from a function that takes a text and a number arg
+func TextAndNumberFunction(f func(utils.Environment, types.XText, types.XNumber) types.XValue) XFunction {
return ArgCountCheck(2, 2, func(env utils.Environment, args ...types.XValue) types.XValue {
- str, xerr := types.ToXString(args[0])
+ str, xerr := types.ToXText(args[0])
if xerr != nil {
return xerr
}
@@ -111,10 +111,10 @@ func StringAndNumberFunction(f func(utils.Environment, types.XString, types.XNum
})
}
-// StringAndIntegerFunction creates an XFunction from a function that takes a string and an integer
-func StringAndIntegerFunction(f func(utils.Environment, types.XString, int) types.XValue) XFunction {
+// TextAndIntegerFunction creates an XFunction from a function that takes a text and an integer arg
+func TextAndIntegerFunction(f func(utils.Environment, types.XText, int) types.XValue) XFunction {
return ArgCountCheck(2, 2, func(env utils.Environment, args ...types.XValue) types.XValue {
- str, xerr := types.ToXString(args[0])
+ str, xerr := types.ToXText(args[0])
if xerr != nil {
return xerr
}
@@ -127,10 +127,10 @@ func StringAndIntegerFunction(f func(utils.Environment, types.XString, int) type
})
}
-// StringAndDateFunction creates an XFunction from a function that takes a string and a date
-func StringAndDateFunction(f func(utils.Environment, types.XString, types.XDate) types.XValue) XFunction {
+// TextAndDateFunction creates an XFunction from a function that takes a text and a date arg
+func TextAndDateFunction(f func(utils.Environment, types.XText, types.XDateTime) types.XValue) XFunction {
return ArgCountCheck(2, 2, func(env utils.Environment, args ...types.XValue) types.XValue {
- str, xerr := types.ToXString(args[0])
+ str, xerr := types.ToXText(args[0])
if xerr != nil {
return xerr
}
@@ -191,8 +191,8 @@ func TwoNumberFunction(f func(utils.Environment, types.XNumber, types.XNumber) t
})
}
-// OneDateFunction creates an XFunction from a single number function
-func OneDateFunction(f func(utils.Environment, types.XDate) types.XValue) XFunction {
+// OneDateTimeFunction creates an XFunction from a single number function
+func OneDateTimeFunction(f func(utils.Environment, types.XDateTime) types.XValue) XFunction {
return ArgCountCheck(1, 1, func(env utils.Environment, args ...types.XValue) types.XValue {
date, xerr := types.ToXDate(env, args[0])
if xerr != nil {
diff --git a/excellent/types/array.go b/excellent/types/array.go
index b6ca27e49..4be77e94d 100644
--- a/excellent/types/array.go
+++ b/excellent/types/array.go
@@ -29,22 +29,22 @@ func NewXArray(values ...XValue) XArray {
// Reduce returns the primitive version of this type (i.e. itself)
func (a *xarray) Reduce() XPrimitive { return a }
-// ToXString converts this type to a string
-func (a *xarray) ToXString() XString {
- strs := make([]XString, len(a.values))
+// ToXText converts this type to text
+func (a *xarray) ToXText() XText {
+ strs := make([]XText, len(a.values))
for i := range a.values {
- strs[i] = a.values[i].Reduce().ToXString()
+ strs[i] = a.values[i].Reduce().ToXText()
}
- return MustMarshalToXString(strs)
+ return MustMarshalToXText(strs)
}
-// ToXBool converts this type to a bool
-func (a *xarray) ToXBool() XBool {
- return NewXBool(len(a.values) > 0)
+// ToXBoolean converts this type to a bool
+func (a *xarray) ToXBoolean() XBoolean {
+ return NewXBoolean(len(a.values) > 0)
}
// ToXJSON is called when this type is passed to @(json(...))
-func (a *xarray) ToXJSON() XString {
+func (a *xarray) ToXJSON() XText {
marshaled := make([]json.RawMessage, len(a.values))
for i, v := range a.values {
asJSON, err := ToXJSON(v)
@@ -52,7 +52,7 @@ func (a *xarray) ToXJSON() XString {
marshaled[i] = json.RawMessage(asJSON.Native())
}
}
- return MustMarshalToXString(marshaled)
+ return MustMarshalToXText(marshaled)
}
// MarshalJSON converts this type to internal JSON
diff --git a/excellent/types/base.go b/excellent/types/base.go
index efea945dc..06984a5cc 100644
--- a/excellent/types/base.go
+++ b/excellent/types/base.go
@@ -10,7 +10,7 @@ import (
// XValue is the base interface of all Excellent types
type XValue interface {
- ToXJSON() XString
+ ToXJSON() XText
Reduce() XPrimitive
}
@@ -18,8 +18,8 @@ type XValue interface {
type XPrimitive interface {
XValue
- ToXString() XString
- ToXBool() XBool
+ ToXText() XText
+ ToXBoolean() XBoolean
}
// XResolvable is the interface for types which can be keyed into, e.g. foo.bar
@@ -45,7 +45,7 @@ type baseXPrimitive struct {
}
func (x *baseXPrimitive) String() string {
- return x.ToXString().Native()
+ return x.ToXText().Native()
}
// ResolveKeys is a utility function that resolves multiple keys on an XResolvable and returns the results as a map
@@ -78,12 +78,12 @@ func Compare(x1 XValue, x2 XValue) (int, error) {
return strings.Compare(typed.Error(), x2.(error).Error()), nil
case XNumber:
return typed.Compare(x2.(XNumber)), nil
- case XBool:
- return typed.Compare(x2.(XBool)), nil
- case XDate:
- return typed.Compare(x2.(XDate)), nil
- case XString:
- return typed.Compare(x2.(XString)), nil
+ case XBoolean:
+ return typed.Compare(x2.(XBoolean)), nil
+ case XDateTime:
+ return typed.Compare(x2.(XDateTime)), nil
+ case XText:
+ return typed.Compare(x2.(XText)), nil
}
// TODO: find better fallback
diff --git a/excellent/types/base_test.go b/excellent/types/base_test.go
index 27dec9104..f5543a4ff 100644
--- a/excellent/types/base_test.go
+++ b/excellent/types/base_test.go
@@ -17,12 +17,12 @@ func TestCompare(t *testing.T) {
hasError bool
}{
{nil, nil, 0, false},
- {nil, types.NewXString(""), 0, true},
+ {nil, types.NewXText(""), 0, true},
{types.NewXError(fmt.Errorf("Error")), types.NewXError(fmt.Errorf("Error")), 0, false},
- {types.NewXError(fmt.Errorf("Error")), types.XDateZero, 0, true}, // type mismatch
- {types.NewXString("bob"), types.NewXString("bob"), 0, false},
- {types.NewXString("bob"), types.NewXString("cat"), -1, false},
- {types.NewXString("bob"), types.NewXString("ann"), 1, false},
+ {types.NewXError(fmt.Errorf("Error")), types.XDateTimeZero, 0, true}, // type mismatch
+ {types.NewXText("bob"), types.NewXText("bob"), 0, false},
+ {types.NewXText("bob"), types.NewXText("cat"), -1, false},
+ {types.NewXText("bob"), types.NewXText("ann"), 1, false},
{types.NewXNumberFromInt(123), types.NewXNumberFromInt(123), 0, false},
{types.NewXNumberFromInt(123), types.NewXNumberFromInt(124), -1, false},
{types.NewXNumberFromInt(123), types.NewXNumberFromInt(122), 1, false},
diff --git a/excellent/types/bool.go b/excellent/types/bool.go
deleted file mode 100644
index f652b7d9b..000000000
--- a/excellent/types/bool.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package types
-
-import (
- "encoding/json"
- "strconv"
-)
-
-// XBool is a boolean true or false
-type XBool struct {
- baseXPrimitive
-
- native bool
-}
-
-// NewXBool creates a new XBool
-func NewXBool(value bool) XBool {
- return XBool{native: value}
-}
-
-// Reduce returns the primitive version of this type (i.e. itself)
-func (x XBool) Reduce() XPrimitive { return x }
-
-// ToXString converts this type to a string
-func (x XBool) ToXString() XString { return NewXString(strconv.FormatBool(x.Native())) }
-
-// ToXBool converts this type to a bool
-func (x XBool) ToXBool() XBool { return x }
-
-// ToXJSON is called when this type is passed to @(json(...))
-func (x XBool) ToXJSON() XString { return MustMarshalToXString(x.Native()) }
-
-// Native returns the native value of this type
-func (x XBool) Native() bool { return x.native }
-
-// Compare compares this bool to another
-func (x XBool) Compare(other XBool) int {
- switch {
- case !x.Native() && other.Native():
- return -1
- case x.Native() && !other.Native():
- return 1
- default:
- return 0
- }
-}
-
-// MarshalJSON is called when a struct containing this type is marshaled
-func (x XBool) MarshalJSON() ([]byte, error) {
- return json.Marshal(x.Native())
-}
-
-// UnmarshalJSON is called when a struct containing this type is unmarshaled
-func (x *XBool) UnmarshalJSON(data []byte) error {
- return json.Unmarshal(data, &x.native)
-}
-
-// XBoolFalse is the false boolean value
-var XBoolFalse = NewXBool(false)
-
-// XBoolTrue is the true boolean value
-var XBoolTrue = NewXBool(true)
-
-var _ XPrimitive = XBoolFalse
diff --git a/excellent/types/boolean.go b/excellent/types/boolean.go
new file mode 100644
index 000000000..68786a434
--- /dev/null
+++ b/excellent/types/boolean.go
@@ -0,0 +1,63 @@
+package types
+
+import (
+ "encoding/json"
+ "strconv"
+)
+
+// XBoolean is a boolean true or false
+type XBoolean struct {
+ baseXPrimitive
+
+ native bool
+}
+
+// NewXBoolean creates a new boolean value
+func NewXBoolean(value bool) XBoolean {
+ return XBoolean{native: value}
+}
+
+// Reduce returns the primitive version of this type (i.e. itself)
+func (x XBoolean) Reduce() XPrimitive { return x }
+
+// ToXText converts this type to text
+func (x XBoolean) ToXText() XText { return NewXText(strconv.FormatBool(x.Native())) }
+
+// ToXBoolean converts this type to a bool
+func (x XBoolean) ToXBoolean() XBoolean { return x }
+
+// ToXJSON is called when this type is passed to @(json(...))
+func (x XBoolean) ToXJSON() XText { return MustMarshalToXText(x.Native()) }
+
+// Native returns the native value of this type
+func (x XBoolean) Native() bool { return x.native }
+
+// Compare compares this bool to another
+func (x XBoolean) Compare(other XBoolean) int {
+ switch {
+ case !x.Native() && other.Native():
+ return -1
+ case x.Native() && !other.Native():
+ return 1
+ default:
+ return 0
+ }
+}
+
+// MarshalJSON is called when a struct containing this type is marshaled
+func (x XBoolean) MarshalJSON() ([]byte, error) {
+ return json.Marshal(x.Native())
+}
+
+// UnmarshalJSON is called when a struct containing this type is unmarshaled
+func (x *XBoolean) UnmarshalJSON(data []byte) error {
+ return json.Unmarshal(data, &x.native)
+}
+
+// XBooleanFalse is the false boolean value
+var XBooleanFalse = NewXBoolean(false)
+
+// XBooleanTrue is the true boolean value
+var XBooleanTrue = NewXBoolean(true)
+
+var _ XPrimitive = XBooleanFalse
diff --git a/excellent/types/conversions.go b/excellent/types/conversions.go
index 534f40173..2d7dbd611 100644
--- a/excellent/types/conversions.go
+++ b/excellent/types/conversions.go
@@ -13,49 +13,49 @@ import (
)
// ToXJSON converts the given value to a JSON string
-func ToXJSON(x XValue) (XString, XError) {
+func ToXJSON(x XValue) (XText, XError) {
if utils.IsNil(x) {
- return NewXString(`null`), nil
+ return NewXText(`null`), nil
}
if IsXError(x) {
- return XStringEmpty, x.(XError)
+ return XTextEmpty, x.(XError)
}
return x.ToXJSON(), nil
}
-// ToXString converts the given value to a string
-func ToXString(x XValue) (XString, XError) {
+// ToXText converts the given value to a string
+func ToXText(x XValue) (XText, XError) {
if utils.IsNil(x) {
- return XStringEmpty, nil
+ return XTextEmpty, nil
}
if IsXError(x) {
- return XStringEmpty, x.(XError)
+ return XTextEmpty, x.(XError)
}
- return x.Reduce().ToXString(), nil
+ return x.Reduce().ToXText(), nil
}
// ToXBool converts the given value to a boolean
-func ToXBool(x XValue) (XBool, XError) {
+func ToXBool(x XValue) (XBoolean, XError) {
if utils.IsNil(x) {
- return XBoolFalse, nil
+ return XBooleanFalse, nil
}
if IsXError(x) {
- return XBoolFalse, x.(XError)
+ return XBooleanFalse, x.(XError)
}
primitive, isPrimitive := x.(XPrimitive)
if isPrimitive {
- return primitive.ToXBool(), nil
+ return primitive.ToXBoolean(), nil
}
lengthable, isLengthable := x.(XLengthable)
if isLengthable {
- return NewXBool(lengthable.Length() > 0), nil
+ return NewXBoolean(lengthable.Length() > 0), nil
}
- return x.Reduce().ToXBool(), nil
+ return x.Reduce().ToXBoolean(), nil
}
// ToXNumber converts the given value to a number or returns an error if that isn't possible
@@ -71,7 +71,7 @@ func ToXNumber(x XValue) (XNumber, XError) {
return XNumberZero, typed
case XNumber:
return typed, nil
- case XString:
+ case XText:
parsed, err := parseDecimalFuzzy(typed.Native())
if err == nil {
return NewXNumber(parsed), nil
@@ -82,26 +82,26 @@ func ToXNumber(x XValue) (XNumber, XError) {
}
// ToXDate converts the given value to a time or returns an error if that isn't possible
-func ToXDate(env utils.Environment, x XValue) (XDate, XError) {
+func ToXDate(env utils.Environment, x XValue) (XDateTime, XError) {
if utils.IsNil(x) {
- return XDateZero, nil
+ return XDateTimeZero, nil
}
x = x.Reduce()
switch typed := x.(type) {
case XError:
- return XDateZero, typed
- case XDate:
+ return XDateTimeZero, typed
+ case XDateTime:
return typed, nil
- case XString:
+ case XText:
parsed, err := utils.DateFromString(env, typed.Native())
if err == nil {
- return NewXDate(parsed), nil
+ return NewXDateTime(parsed), nil
}
}
- return XDateZero, NewXErrorf("unable to convert value '%s' of type '%s' to a date", x, reflect.TypeOf(x))
+ return XDateTimeZero, NewXErrorf("unable to convert value '%s' of type '%s' to a date", x, reflect.TypeOf(x))
}
// ToInteger tries to convert the passed in value to an integer or returns an error if that isn't possible
@@ -114,19 +114,19 @@ func ToInteger(x XValue) (int, XError) {
intPart := number.Native().IntPart()
if intPart < math.MinInt32 && intPart > math.MaxInt32 {
- return 0, NewXErrorf("number value %s is out of range for an integer", number.ToXString().Native())
+ return 0, NewXErrorf("number value %s is out of range for an integer", number.ToXText().Native())
}
return int(intPart), nil
}
-// MustMarshalToXString calls json.Marshal in the given value and panics in the case of an error
-func MustMarshalToXString(x interface{}) XString {
+// MustMarshalToXText calls json.Marshal in the given value and panics in the case of an error
+func MustMarshalToXText(x interface{}) XText {
j, err := json.Marshal(x)
if err != nil {
panic(fmt.Sprintf("unable to marshal %s to JSON", x))
}
- return NewXString(string(j))
+ return NewXText(string(j))
}
func parseDecimalFuzzy(val string) (decimal.Decimal, error) {
diff --git a/excellent/types/conversions_test.go b/excellent/types/conversions_test.go
index 20ced8786..424e146fc 100644
--- a/excellent/types/conversions_test.go
+++ b/excellent/types/conversions_test.go
@@ -23,9 +23,9 @@ func NewTestXObject(foo string, bar int) *testXObject {
}
// ToXJSON is called when this type is passed to @(json(...))
-func (v *testXObject) ToXJSON() types.XString {
+func (v *testXObject) ToXJSON() types.XText {
return types.NewXMap(map[string]types.XValue{
- "foo": types.NewXString(v.foo),
+ "foo": types.NewXText(v.foo),
"bar": types.NewXNumberFromInt(v.bar),
}).ToXJSON()
}
@@ -40,7 +40,7 @@ func (v *testXObject) MarshalJSON() ([]byte, error) {
return json.Marshal(e)
}
-func (v *testXObject) Reduce() types.XPrimitive { return types.NewXString(v.foo) }
+func (v *testXObject) Reduce() types.XPrimitive { return types.NewXText(v.foo) }
var _ types.XValue = &testXObject{}
@@ -65,19 +65,19 @@ func TestXValueRequiredConversions(t *testing.T) {
asString: "",
asBool: false,
}, {
- value: types.NewXString(""),
+ value: types.NewXText(""),
asInternalJSON: `""`,
asJSON: `""`,
asString: "",
asBool: false, // empty strings are false
}, {
- value: types.NewXString("FALSE"),
+ value: types.NewXText("FALSE"),
asInternalJSON: `"FALSE"`,
asJSON: `"FALSE"`,
asString: "FALSE",
asBool: false, // because it's string value is "false"
}, {
- value: types.NewXString("hello \"bob\""),
+ value: types.NewXText("hello \"bob\""),
asInternalJSON: `"hello \"bob\""`,
asJSON: `"hello \"bob\""`,
asString: "hello \"bob\"",
@@ -107,25 +107,25 @@ func TestXValueRequiredConversions(t *testing.T) {
asString: "123.45",
asBool: true,
}, {
- value: types.NewXBool(false),
+ value: types.NewXBoolean(false),
asInternalJSON: `false`,
asJSON: `false`,
asString: "false",
asBool: false,
}, {
- value: types.NewXBool(true),
+ value: types.NewXBoolean(true),
asInternalJSON: `true`,
asJSON: `true`,
asString: "true",
asBool: true,
}, {
- value: types.NewXDate(date1),
+ value: types.NewXDateTime(date1),
asInternalJSON: `"2017-06-23T15:30:00Z"`,
asJSON: `"2017-06-23T15:30:00.000000Z"`,
asString: "2017-06-23T15:30:00.000000Z",
asBool: true,
}, {
- value: types.NewXDate(date2),
+ value: types.NewXDateTime(date2),
asInternalJSON: `"2017-07-18T15:30:00-05:00"`,
asJSON: `"2017-07-18T15:30:00.000000-05:00"`,
asString: "2017-07-18T15:30:00.000000-05:00",
@@ -137,7 +137,7 @@ func TestXValueRequiredConversions(t *testing.T) {
asString: `[]`,
asBool: false,
}, {
- value: types.NewXArray(types.NewXDate(date1), types.NewXDate(date2)),
+ value: types.NewXArray(types.NewXDateTime(date1), types.NewXDateTime(date2)),
asInternalJSON: `["2017-06-23T15:30:00Z","2017-07-18T15:30:00-05:00"]`,
asJSON: `["2017-06-23T15:30:00.000000Z","2017-07-18T15:30:00.000000-05:00"]`,
asString: `["2017-06-23T15:30:00.000000Z","2017-07-18T15:30:00.000000-05:00"]`,
@@ -204,13 +204,13 @@ func TestXValueRequiredConversions(t *testing.T) {
for _, test := range tests {
asInternalJSON, _ := json.Marshal(test.value)
asJSON, _ := types.ToXJSON(test.value)
- asString, _ := types.ToXString(test.value)
+ asString, _ := types.ToXText(test.value)
asBool, _ := types.ToXBool(test.value)
assert.Equal(t, test.asInternalJSON, string(asInternalJSON), "json.Marshal failed for %T{%s}", test.value, test.value)
- assert.Equal(t, types.NewXString(test.asJSON), asJSON, "ToXJSON failed for %T{%s}", test.value, test.value)
- assert.Equal(t, types.NewXString(test.asString), asString, "ToXString failed for %T{%s}", test.value, test.value)
- assert.Equal(t, types.NewXBool(test.asBool), asBool, "ToXBool failed for %T{%s}", test.value, test.value)
+ assert.Equal(t, types.NewXText(test.asJSON), asJSON, "ToXJSON failed for %T{%s}", test.value, test.value)
+ assert.Equal(t, types.NewXText(test.asString), asString, "ToXText failed for %T{%s}", test.value, test.value)
+ assert.Equal(t, types.NewXBoolean(test.asBool), asBool, "ToXBool failed for %T{%s}", test.value, test.value)
}
}
@@ -223,8 +223,8 @@ func TestToXNumber(t *testing.T) {
{nil, types.XNumberZero, false},
{types.NewXErrorf("Error"), types.XNumberZero, true},
{types.NewXNumberFromInt(123), types.NewXNumberFromInt(123), false},
- {types.NewXString("15.5"), types.RequireXNumberFromString("15.5"), false},
- {types.NewXString("lO.5"), types.RequireXNumberFromString("10.5"), false},
+ {types.NewXText("15.5"), types.RequireXNumberFromString("15.5"), false},
+ {types.NewXText("lO.5"), types.RequireXNumberFromString("10.5"), false},
{NewTestXObject("Hello", 123), types.XNumberZero, true},
{NewTestXObject("123.45000", 123), types.RequireXNumberFromString("123.45"), false},
}
@@ -244,16 +244,16 @@ func TestToXNumber(t *testing.T) {
func TestToXDate(t *testing.T) {
var tests = []struct {
value types.XValue
- asNumber types.XDate
+ asNumber types.XDateTime
hasError bool
}{
- {nil, types.XDateZero, false},
- {types.NewXError(fmt.Errorf("Error")), types.XDateZero, true},
- {types.NewXNumberFromInt(123), types.XDateZero, true},
- {types.NewXString("2018-06-05"), types.NewXDate(time.Date(2018, 6, 5, 0, 0, 0, 0, time.UTC)), false},
- {types.NewXString("wha?"), types.XDateZero, true},
- {NewTestXObject("Hello", 123), types.XDateZero, true},
- {NewTestXObject("2018/6/5", 123), types.NewXDate(time.Date(2018, 6, 5, 0, 0, 0, 0, time.UTC)), false},
+ {nil, types.XDateTimeZero, false},
+ {types.NewXError(fmt.Errorf("Error")), types.XDateTimeZero, true},
+ {types.NewXNumberFromInt(123), types.XDateTimeZero, true},
+ {types.NewXText("2018-06-05"), types.NewXDateTime(time.Date(2018, 6, 5, 0, 0, 0, 0, time.UTC)), false},
+ {types.NewXText("wha?"), types.XDateTimeZero, true},
+ {NewTestXObject("Hello", 123), types.XDateTimeZero, true},
+ {NewTestXObject("2018/6/5", 123), types.NewXDateTime(time.Date(2018, 6, 5, 0, 0, 0, 0, time.UTC)), false},
}
env := utils.NewDefaultEnvironment()
diff --git a/excellent/types/date.go b/excellent/types/date.go
deleted file mode 100644
index 609724305..000000000
--- a/excellent/types/date.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package types
-
-import (
- "time"
-
- "github.com/nyaruka/goflow/utils"
-)
-
-// XDate is a date
-type XDate struct {
- baseXPrimitive
-
- native time.Time
-}
-
-// NewXDate creates a new date
-func NewXDate(value time.Time) XDate {
- return XDate{native: value}
-}
-
-// Reduce returns the primitive version of this type (i.e. itself)
-func (x XDate) Reduce() XPrimitive { return x }
-
-// ToXString converts this type to a string
-func (x XDate) ToXString() XString { return NewXString(utils.DateToISO(x.Native())) }
-
-// ToXBool converts this type to a bool
-func (x XDate) ToXBool() XBool { return NewXBool(!x.Native().IsZero()) }
-
-// ToXJSON is called when this type is passed to @(json(...))
-func (x XDate) ToXJSON() XString { return MustMarshalToXString(utils.DateToISO(x.Native())) }
-
-// Native returns the native value of this type
-func (x XDate) Native() time.Time { return x.native }
-
-// Compare compares this date to another
-func (x XDate) Compare(other XDate) int {
- switch {
- case x.Native().Before(other.Native()):
- return -1
- case x.Native().After(other.Native()):
- return 1
- default:
- return 0
- }
-}
-
-// MarshalJSON is called when a struct containing this type is marshaled
-func (x XDate) MarshalJSON() ([]byte, error) {
- return x.Native().MarshalJSON()
-}
-
-// UnmarshalJSON is called when a struct containing this type is unmarshaled
-func (x *XDate) UnmarshalJSON(data []byte) error {
- nativePtr := &x.native
- return nativePtr.UnmarshalJSON(data)
-}
-
-// XDateZero is the zero time value
-var XDateZero = NewXDate(time.Time{})
-var _ XPrimitive = XDateZero
diff --git a/excellent/types/datetime.go b/excellent/types/datetime.go
new file mode 100644
index 000000000..ba444ac2d
--- /dev/null
+++ b/excellent/types/datetime.go
@@ -0,0 +1,61 @@
+package types
+
+import (
+ "time"
+
+ "github.com/nyaruka/goflow/utils"
+)
+
+// XDateTime is a datetime value
+type XDateTime struct {
+ baseXPrimitive
+
+ native time.Time
+}
+
+// NewXDateTime creates a new date
+func NewXDateTime(value time.Time) XDateTime {
+ return XDateTime{native: value}
+}
+
+// Reduce returns the primitive version of this type (i.e. itself)
+func (x XDateTime) Reduce() XPrimitive { return x }
+
+// ToXText converts this type to text
+func (x XDateTime) ToXText() XText { return NewXText(utils.DateToISO(x.Native())) }
+
+// ToXBoolean converts this type to a bool
+func (x XDateTime) ToXBoolean() XBoolean { return NewXBoolean(!x.Native().IsZero()) }
+
+// ToXJSON is called when this type is passed to @(json(...))
+func (x XDateTime) ToXJSON() XText { return MustMarshalToXText(utils.DateToISO(x.Native())) }
+
+// Native returns the native value of this type
+func (x XDateTime) Native() time.Time { return x.native }
+
+// Compare compares this date to another
+func (x XDateTime) Compare(other XDateTime) int {
+ switch {
+ case x.Native().Before(other.Native()):
+ return -1
+ case x.Native().After(other.Native()):
+ return 1
+ default:
+ return 0
+ }
+}
+
+// MarshalJSON is called when a struct containing this type is marshaled
+func (x XDateTime) MarshalJSON() ([]byte, error) {
+ return x.Native().MarshalJSON()
+}
+
+// UnmarshalJSON is called when a struct containing this type is unmarshaled
+func (x *XDateTime) UnmarshalJSON(data []byte) error {
+ nativePtr := &x.native
+ return nativePtr.UnmarshalJSON(data)
+}
+
+// XDateTimeZero is the zero time value
+var XDateTimeZero = NewXDateTime(time.Time{})
+var _ XPrimitive = XDateTimeZero
diff --git a/excellent/types/date_test.go b/excellent/types/datetime_test.go
similarity index 56%
rename from excellent/types/date_test.go
rename to excellent/types/datetime_test.go
index 4bbc556b2..8535d2b2c 100644
--- a/excellent/types/date_test.go
+++ b/excellent/types/datetime_test.go
@@ -10,14 +10,14 @@ import (
"github.com/stretchr/testify/assert"
)
-func TestXDateMarshaling(t *testing.T) {
- var date types.XDate
+func TestXDateTimeMarshaling(t *testing.T) {
+ var date types.XDateTime
err := json.Unmarshal([]byte(`"2018-04-09T17:01:30Z"`), &date)
assert.NoError(t, err)
- assert.Equal(t, types.NewXDate(time.Date(2018, 4, 9, 17, 1, 30, 0, time.UTC)), date)
+ assert.Equal(t, types.NewXDateTime(time.Date(2018, 4, 9, 17, 1, 30, 0, time.UTC)), date)
// marshal
- data, err := json.Marshal(types.NewXDate(time.Date(2018, 4, 9, 17, 1, 30, 0, time.UTC)))
+ data, err := json.Marshal(types.NewXDateTime(time.Date(2018, 4, 9, 17, 1, 30, 0, time.UTC)))
assert.NoError(t, err)
assert.Equal(t, []byte(`"2018-04-09T17:01:30Z"`), data)
}
diff --git a/excellent/types/error.go b/excellent/types/error.go
index 0ab96c801..0f2f699ee 100644
--- a/excellent/types/error.go
+++ b/excellent/types/error.go
@@ -34,14 +34,14 @@ func NewXResolveError(resolvable XResolvable, key string) XError {
// Reduce returns the primitive version of this type (i.e. itself)
func (x xerror) Reduce() XPrimitive { return x }
-// ToXString converts this type to a string
-func (x xerror) ToXString() XString { return NewXString(x.Native().Error()) }
+// ToXText converts this type to text
+func (x xerror) ToXText() XText { return NewXText(x.Native().Error()) }
-// ToXBool converts this type to a bool
-func (x xerror) ToXBool() XBool { return XBoolFalse }
+// ToXBoolean converts this type to a bool
+func (x xerror) ToXBoolean() XBoolean { return XBooleanFalse }
// ToXJSON is called when this type is passed to @(json(...))
-func (x xerror) ToXJSON() XString { return MustMarshalToXString(x.Native().Error()) }
+func (x xerror) ToXJSON() XText { return MustMarshalToXText(x.Native().Error()) }
// MarshalJSON converts this type to internal JSON
func (x xerror) MarshalJSON() ([]byte, error) {
diff --git a/excellent/types/json.go b/excellent/types/json.go
index e79fb3608..dbaf81635 100644
--- a/excellent/types/json.go
+++ b/excellent/types/json.go
@@ -11,7 +11,7 @@ import (
// XJSON is the base type for XJSONObject and XJSONArray
type XJSON []byte
-func (x XJSON) ToXJSON() XString { return NewXString(string(x)) }
+func (x XJSON) ToXJSON() XText { return NewXText(string(x)) }
func (x XJSON) Reduce() XPrimitive { return x.ToXJSON() }
@@ -98,7 +98,7 @@ func jsonTypeToXValue(data []byte, valType jsonparser.ValueType) XValue {
case jsonparser.String:
strVal, err := jsonparser.ParseString(data)
if err == nil {
- return NewXString(strVal)
+ return NewXText(strVal)
}
case jsonparser.Number:
decimalVal, err := decimal.NewFromString(string(data))
@@ -108,7 +108,7 @@ func jsonTypeToXValue(data []byte, valType jsonparser.ValueType) XValue {
case jsonparser.Boolean:
boolVal, err := jsonparser.ParseBoolean(data)
if err == nil {
- return NewXBool(boolVal)
+ return NewXBoolean(boolVal)
}
case jsonparser.Array:
return NewXJSONArray(data)
diff --git a/excellent/types/json_test.go b/excellent/types/json_test.go
index be750863a..5cacdff52 100644
--- a/excellent/types/json_test.go
+++ b/excellent/types/json_test.go
@@ -22,25 +22,25 @@ func TestXJSONResolve(t *testing.T) {
{[]byte(`malformed`), "key", nil, true},
// different data types in an object
- {[]byte(`{"foo": "x", "bar": "one"}`), "bar", types.NewXString("one"), false},
+ {[]byte(`{"foo": "x", "bar": "one"}`), "bar", types.NewXText("one"), false},
{[]byte(`{"foo": "x", "bar": 1.23}`), "bar", types.RequireXNumberFromString("1.23"), false},
- {[]byte(`{"foo": "x", "bar": true}`), "bar", types.NewXBool(true), false},
+ {[]byte(`{"foo": "x", "bar": true}`), "bar", types.NewXBoolean(true), false},
{[]byte(`{"foo": "x", "bar": null}`), "bar", nil, false},
// different data types in an array
- {[]byte(`["foo", "one"]`), "1", types.NewXString("one"), false},
+ {[]byte(`["foo", "one"]`), "1", types.NewXText("one"), false},
{[]byte(`["foo", 1.23]`), "1", types.RequireXNumberFromString("1.23"), false},
- {[]byte(`["foo", true]`), "1", types.NewXBool(true), false},
+ {[]byte(`["foo", true]`), "1", types.NewXBoolean(true), false},
{[]byte(`["foo", null]`), "1", nil, false},
- {[]byte(`["one", "two", "three"]`), "0", types.NewXString("one"), false},
- {[]byte(`["escaped \"string\""]`), "0", types.NewXString(`escaped "string"`), false},
- {[]byte(`{"1": "one"}`), "1", types.NewXString("one"), false}, // map key is numerical string
- {[]byte(`{"arr": ["one", "two"]}`), "arr[1]", types.NewXString("two"), false},
- {[]byte(`{"arr": ["one", "two"]}`), "arr.1", types.NewXString("two"), false},
- {[]byte(`{"key": {"key2": "val2"}}`), "key.key2", types.NewXString("val2"), false},
- {[]byte(`{"key": {"key-with-dash": "val2"}}`), `key["key-with-dash"]`, types.NewXString("val2"), false},
- {[]byte(`{"key": {"key with space": "val2"}}`), `key["key with space"]`, types.NewXString("val2"), false},
+ {[]byte(`["one", "two", "three"]`), "0", types.NewXText("one"), false},
+ {[]byte(`["escaped \"string\""]`), "0", types.NewXText(`escaped "string"`), false},
+ {[]byte(`{"1": "one"}`), "1", types.NewXText("one"), false}, // map key is numerical string
+ {[]byte(`{"arr": ["one", "two"]}`), "arr[1]", types.NewXText("two"), false},
+ {[]byte(`{"arr": ["one", "two"]}`), "arr.1", types.NewXText("two"), false},
+ {[]byte(`{"key": {"key2": "val2"}}`), "key.key2", types.NewXText("val2"), false},
+ {[]byte(`{"key": {"key-with-dash": "val2"}}`), `key["key-with-dash"]`, types.NewXText("val2"), false},
+ {[]byte(`{"key": {"key with space": "val2"}}`), `key["key with space"]`, types.NewXText("val2"), false},
{[]byte(`{"arr": ["one", "two"]}`), "arr", types.NewXJSONArray([]byte(`["one", "two"]`)), false},
{[]byte(`{"arr": {"foo": "bar"}}`), "arr", types.NewXJSONObject([]byte(`{"foo": "bar"}`)), false},
diff --git a/excellent/types/map.go b/excellent/types/map.go
index 56ccf2528..550aebf92 100644
--- a/excellent/types/map.go
+++ b/excellent/types/map.go
@@ -37,22 +37,22 @@ func NewXEmptyMap() XMap {
// Reduce returns the primitive version of this type (i.e. itself)
func (m *xmap) Reduce() XPrimitive { return m }
-// ToXString converts this type to a string
-func (m *xmap) ToXString() XString {
- strs := make(map[string]XString, len(m.values))
+// ToXText converts this type to text
+func (m *xmap) ToXText() XText {
+ strs := make(map[string]XText, len(m.values))
for k, v := range m.values {
- strs[k] = v.Reduce().ToXString()
+ strs[k] = v.Reduce().ToXText()
}
- return MustMarshalToXString(strs)
+ return MustMarshalToXText(strs)
}
-// ToXBool converts this type to a bool
-func (m *xmap) ToXBool() XBool {
- return NewXBool(len(m.values) > 0)
+// ToXBoolean converts this type to a bool
+func (m *xmap) ToXBoolean() XBoolean {
+ return NewXBoolean(len(m.values) > 0)
}
// ToXJSON is called when this type is passed to @(json(...))
-func (m *xmap) ToXJSON() XString {
+func (m *xmap) ToXJSON() XText {
marshaled := make(map[string]json.RawMessage, len(m.values))
for k, v := range m.values {
asJSON, err := ToXJSON(v)
@@ -60,7 +60,7 @@ func (m *xmap) ToXJSON() XString {
marshaled[k] = json.RawMessage(asJSON.Native())
}
}
- return MustMarshalToXString(marshaled)
+ return MustMarshalToXText(marshaled)
}
// MarshalJSON converts this type to internal JSON
diff --git a/excellent/types/number.go b/excellent/types/number.go
index b8794d1c4..84c1e2163 100644
--- a/excellent/types/number.go
+++ b/excellent/types/number.go
@@ -38,14 +38,14 @@ func RequireXNumberFromString(value string) XNumber {
// Reduce returns the primitive version of this type (i.e. itself)
func (x XNumber) Reduce() XPrimitive { return x }
-// ToXString converts this type to a string
-func (x XNumber) ToXString() XString { return NewXString(x.Native().String()) }
+// ToXText converts this type to text
+func (x XNumber) ToXText() XText { return NewXText(x.Native().String()) }
-// ToXBool converts this type to a bool
-func (x XNumber) ToXBool() XBool { return NewXBool(!x.Equals(XNumberZero)) }
+// ToXBoolean converts this type to a bool
+func (x XNumber) ToXBoolean() XBoolean { return NewXBoolean(!x.Equals(XNumberZero)) }
// ToXJSON is called when this type is passed to @(json(...))
-func (x XNumber) ToXJSON() XString { return MustMarshalToXString(x.Native()) }
+func (x XNumber) ToXJSON() XText { return MustMarshalToXText(x.Native()) }
// Native returns the native value of this type
func (x XNumber) Native() decimal.Decimal { return x.native }
diff --git a/excellent/types/string.go b/excellent/types/string.go
deleted file mode 100644
index a5ff91e64..000000000
--- a/excellent/types/string.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package types
-
-import (
- "encoding/json"
- "strings"
- "unicode/utf8"
-)
-
-// XString is a string of characters
-type XString struct {
- baseXPrimitive
-
- native string
-}
-
-// NewXString creates a new XString
-func NewXString(value string) XString {
- return XString{native: value}
-}
-
-// Reduce returns the primitive version of this type (i.e. itself)
-func (x XString) Reduce() XPrimitive { return x }
-
-// String converts this type to native string
-func (x XString) String() string {
- return x.Native()
-}
-
-// ToXString converts this type to a string
-func (x XString) ToXString() XString { return x }
-
-// ToXBool converts this type to a bool
-func (x XString) ToXBool() XBool {
- return NewXBool(!x.Empty() && strings.ToLower(x.Native()) != "false")
-}
-
-// ToXJSON is called when this type is passed to @(json(...))
-func (x XString) ToXJSON() XString { return MustMarshalToXString(x.Native()) }
-
-// Native returns the native value of this type
-func (x XString) Native() string { return x.native }
-
-// Equals determines equality for this type
-func (x XString) Equals(other XString) bool {
- return x.Native() == other.Native()
-}
-
-// Compare compares this string to another
-func (x XString) Compare(other XString) int {
- return strings.Compare(x.Native(), other.Native())
-}
-
-// Length returns the length of this string
-func (x XString) Length() int { return utf8.RuneCountInString(x.Native()) }
-
-// Empty returns whether this is an empty string
-func (x XString) Empty() bool { return x.Native() == "" }
-
-// MarshalJSON is called when a struct containing this type is marshaled
-func (x XString) MarshalJSON() ([]byte, error) {
- return json.Marshal(x.Native())
-}
-
-// UnmarshalJSON is called when a struct containing this type is unmarshaled
-func (x *XString) UnmarshalJSON(data []byte) error {
- return json.Unmarshal(data, &x.native)
-}
-
-// XStringEmpty is the empty string value
-var XStringEmpty = NewXString("")
-var _ XPrimitive = XStringEmpty
-var _ XLengthable = XStringEmpty
diff --git a/excellent/types/text.go b/excellent/types/text.go
new file mode 100644
index 000000000..2ca5fe050
--- /dev/null
+++ b/excellent/types/text.go
@@ -0,0 +1,72 @@
+package types
+
+import (
+ "encoding/json"
+ "strings"
+ "unicode/utf8"
+)
+
+// XText is a simple tex value
+type XText struct {
+ baseXPrimitive
+
+ native string
+}
+
+// NewXText creates a new text value
+func NewXText(value string) XText {
+ return XText{native: value}
+}
+
+// Reduce returns the primitive version of this type (i.e. itself)
+func (x XText) Reduce() XPrimitive { return x }
+
+// String converts this type to native string
+func (x XText) String() string {
+ return x.Native()
+}
+
+// ToXText converts this type to text
+func (x XText) ToXText() XText { return x }
+
+// ToXBoolean converts this type to a bool
+func (x XText) ToXBoolean() XBoolean {
+ return NewXBoolean(!x.Empty() && strings.ToLower(x.Native()) != "false")
+}
+
+// ToXJSON is called when this type is passed to @(json(...))
+func (x XText) ToXJSON() XText { return MustMarshalToXText(x.Native()) }
+
+// Native returns the native value of this type
+func (x XText) Native() string { return x.native }
+
+// Equals determines equality for this type
+func (x XText) Equals(other XText) bool {
+ return x.Native() == other.Native()
+}
+
+// Compare compares this string to another
+func (x XText) Compare(other XText) int {
+ return strings.Compare(x.Native(), other.Native())
+}
+
+// Length returns the length of this string
+func (x XText) Length() int { return utf8.RuneCountInString(x.Native()) }
+
+// Empty returns whether this is an empty string
+func (x XText) Empty() bool { return x.Native() == "" }
+
+// MarshalJSON is called when a struct containing this type is marshaled
+func (x XText) MarshalJSON() ([]byte, error) {
+ return json.Marshal(x.Native())
+}
+
+// UnmarshalJSON is called when a struct containing this type is unmarshaled
+func (x *XText) UnmarshalJSON(data []byte) error {
+ return json.Unmarshal(data, &x.native)
+}
+
+// XTextEmpty is the empty text value
+var XTextEmpty = NewXText("")
+var _ XPrimitive = XTextEmpty
+var _ XLengthable = XTextEmpty
diff --git a/excellent/visitor.go b/excellent/visitor.go
index f067226de..f1c012bda 100644
--- a/excellent/visitor.go
+++ b/excellent/visitor.go
@@ -66,7 +66,7 @@ func (v *Visitor) VisitStringLiteral(ctx *gen.StringLiteralContext) interface{}
// replace "" with "
unquoted = strings.Replace(unquoted, "\"\"", "\"", -1)
- return types.NewXString(unquoted)
+ return types.NewXText(unquoted)
}
// VisitFunctionCall deals with function calls like TITLE(foo.bar)
@@ -98,12 +98,12 @@ func (v *Visitor) VisitFunctionCall(ctx *gen.FunctionCallContext) interface{} {
// VisitTrue deals with the "true" literal
func (v *Visitor) VisitTrue(ctx *gen.TrueContext) interface{} {
- return types.XBoolTrue
+ return types.XBooleanTrue
}
// VisitFalse deals with the "false" literal
func (v *Visitor) VisitFalse(ctx *gen.FalseContext) interface{} {
- return types.XBoolFalse
+ return types.XBooleanFalse
}
// VisitArrayLookup deals with lookups such as foo[5]
@@ -115,7 +115,7 @@ func (v *Visitor) VisitArrayLookup(ctx *gen.ArrayLookupContext) interface{} {
expression := toXValue(v.Visit(ctx.Expression()))
- lookup, xerr := types.ToXString(expression)
+ lookup, xerr := types.ToXText(expression)
if xerr != nil {
return xerr
}
@@ -172,11 +172,11 @@ func (v *Visitor) VisitConcatenation(ctx *gen.ConcatenationContext) interface{}
arg1 := toXValue(v.Visit(ctx.Expression(0)))
arg2 := toXValue(v.Visit(ctx.Expression(1)))
- str1, xerr := types.ToXString(arg1)
+ str1, xerr := types.ToXText(arg1)
if xerr != nil {
return xerr
}
- str2, xerr := types.ToXString(arg2)
+ str2, xerr := types.ToXText(arg2)
if xerr != nil {
return xerr
}
@@ -185,7 +185,7 @@ func (v *Visitor) VisitConcatenation(ctx *gen.ConcatenationContext) interface{}
buffer.WriteString(str1.Native())
buffer.WriteString(str2.Native())
- return types.NewXString(buffer.String())
+ return types.NewXText(buffer.String())
}
// VisitAdditionOrSubtraction deals with addition and subtraction like 5+5 and 5-3
@@ -213,11 +213,11 @@ func (v *Visitor) VisitEquality(ctx *gen.EqualityContext) interface{} {
arg1 := toXValue(v.Visit(ctx.Expression(0)))
arg2 := toXValue(v.Visit(ctx.Expression(1)))
- str1, xerr := types.ToXString(arg1)
+ str1, xerr := types.ToXText(arg1)
if xerr != nil {
return xerr
}
- str2, xerr := types.ToXString(arg2)
+ str2, xerr := types.ToXText(arg2)
if xerr != nil {
return xerr
}
@@ -225,10 +225,10 @@ func (v *Visitor) VisitEquality(ctx *gen.EqualityContext) interface{} {
isEqual := str1.Equals(str2)
if ctx.EQ() != nil {
- return types.NewXBool(isEqual)
+ return types.NewXBoolean(isEqual)
}
- return types.NewXBool(!isEqual)
+ return types.NewXBoolean(!isEqual)
}
// VisitAtomReference deals with visiting a single atom in our expression
@@ -280,13 +280,13 @@ func (v *Visitor) VisitComparison(ctx *gen.ComparisonContext) interface{} {
switch {
case ctx.LT() != nil:
- return types.NewXBool(cmp < 0)
+ return types.NewXBoolean(cmp < 0)
case ctx.LTE() != nil:
- return types.NewXBool(cmp <= 0)
+ return types.NewXBoolean(cmp <= 0)
case ctx.GTE() != nil:
- return types.NewXBool(cmp >= 0)
+ return types.NewXBoolean(cmp >= 0)
case ctx.GT() != nil:
- return types.NewXBool(cmp > 0)
+ return types.NewXBoolean(cmp > 0)
}
return types.NewXErrorf("unknown comparison operator: %s", ctx.GetText())
diff --git a/flows/attachments.go b/flows/attachments.go
index 24f557235..1744a13b3 100644
--- a/flows/attachments.go
+++ b/flows/attachments.go
@@ -42,19 +42,19 @@ func (a Attachment) URL() string {
func (a Attachment) Resolve(key string) types.XValue {
switch key {
case "content_type":
- return types.NewXString(a.ContentType())
+ return types.NewXText(a.ContentType())
case "url":
- return types.NewXString(a.URL())
+ return types.NewXText(a.URL())
}
return types.NewXResolveError(a, key)
}
// Reduce is called when this object needs to be reduced to a primitive
-func (a Attachment) Reduce() types.XPrimitive { return types.NewXString(a.URL()) }
+func (a Attachment) Reduce() types.XPrimitive { return types.NewXText(a.URL()) }
// ToXJSON is called when this type is passed to @(json(...))
-func (a Attachment) ToXJSON() types.XString {
+func (a Attachment) ToXJSON() types.XText {
return types.ResolveKeys(a, "content_type", "url").ToXJSON()
}
@@ -84,7 +84,7 @@ func (a AttachmentList) Reduce() types.XPrimitive {
}
// ToXJSON is called when this type is passed to @(json(...))
-func (a AttachmentList) ToXJSON() types.XString { return a.Reduce().ToXJSON() }
+func (a AttachmentList) ToXJSON() types.XText { return a.Reduce().ToXJSON() }
var _ types.XValue = (AttachmentList)(nil)
var _ types.XIndexable = (AttachmentList)(nil)
diff --git a/flows/channel.go b/flows/channel.go
index 1c6a8a315..d57edf1b8 100644
--- a/flows/channel.go
+++ b/flows/channel.go
@@ -110,11 +110,11 @@ func (c *channel) HasRole(role ChannelRole) bool {
func (c *channel) Resolve(key string) types.XValue {
switch key {
case "uuid":
- return types.NewXString(string(c.uuid))
+ return types.NewXText(string(c.uuid))
case "name":
- return types.NewXString(c.name)
+ return types.NewXText(c.name)
case "address":
- return types.NewXString(c.address)
+ return types.NewXText(c.address)
}
return types.NewXResolveError(c, key)
@@ -122,11 +122,11 @@ func (c *channel) Resolve(key string) types.XValue {
// Reduce is called when this object needs to be reduced to a primitive
func (c *channel) Reduce() types.XPrimitive {
- return types.NewXString(c.name)
+ return types.NewXText(c.name)
}
// ToXJSON is called when this type is passed to @(json(...))
-func (c *channel) ToXJSON() types.XString {
+func (c *channel) ToXJSON() types.XText {
return types.ResolveKeys(c, "uuid", "name", "address").ToXJSON()
}
diff --git a/flows/contact.go b/flows/contact.go
index b4de2a7e8..52060a53a 100644
--- a/flows/contact.go
+++ b/flows/contact.go
@@ -140,27 +140,27 @@ func (c *Contact) Reference() *ContactReference { return NewContactReference(c.u
func (c *Contact) Resolve(key string) types.XValue {
switch key {
case "uuid":
- return types.NewXString(string(c.uuid))
+ return types.NewXText(string(c.uuid))
case "name":
- return types.NewXString(c.name)
+ return types.NewXText(c.name)
case "first_name":
names := utils.TokenizeString(c.name)
if len(names) >= 1 {
- return types.NewXString(names[0])
+ return types.NewXText(names[0])
}
return nil
case "language":
- return types.NewXString(string(c.language))
+ return types.NewXText(string(c.language))
case "timezone":
if c.timezone != nil {
- return types.NewXString(c.timezone.String())
+ return types.NewXText(c.timezone.String())
}
return nil
case "urns":
return c.urns
case "urn":
if len(c.urns) > 0 {
- return types.NewXString(c.urns[0].Format())
+ return types.NewXText(c.urns[0].Format())
}
return nil
case "groups":
@@ -179,11 +179,11 @@ func (c *Contact) Resolve(key string) types.XValue {
// Reduce is called when this object needs to be reduced to a primitive
func (c *Contact) Reduce() types.XPrimitive {
- return types.NewXString(c.name)
+ return types.NewXText(c.name)
}
// ToXJSON is called when this type is passed to @(json(...))
-func (c *Contact) ToXJSON() types.XString {
+func (c *Contact) ToXJSON() types.XText {
return types.ResolveKeys(c, "uuid", "name", "language", "timezone", "urns", "groups", "fields", "channel").ToXJSON()
}
@@ -192,7 +192,7 @@ var _ types.XResolvable = (*Contact)(nil)
// SetFieldValue updates the given contact field value for this contact
func (c *Contact) SetFieldValue(env utils.Environment, field *Field, rawValue string) {
- c.fields.setValue(env, field, types.NewXString(rawValue))
+ c.fields.setValue(env, field, types.NewXText(rawValue))
}
// UpdatePreferredChannel updates the preferred channel
@@ -264,11 +264,11 @@ func (c *Contact) ResolveQueryKey(key string) []interface{} {
return nil
case *Location:
nativeValue = typed.Name()
- case types.XString:
+ case types.XText:
nativeValue = typed.Native()
case types.XNumber:
nativeValue = typed.Native()
- case types.XDate:
+ case types.XDateTime:
nativeValue = typed.Native()
}
@@ -286,12 +286,12 @@ var _ contactql.Queryable = (*Contact)(nil)
//------------------------------------------------------------------------------------------
type fieldValueEnvelope struct {
- Text types.XString `json:"text,omitempty"`
- Datetime *types.XDate `json:"datetime,omitempty"`
- Decimal *types.XNumber `json:"decimal,omitempty"`
- State string `json:"state,omitempty"`
- District string `json:"district,omitempty"`
- Ward string `json:"ward,omitempty"`
+ Text types.XText `json:"text,omitempty"`
+ Datetime *types.XDateTime `json:"datetime,omitempty"`
+ Number *types.XNumber `json:"number,omitempty"`
+ State string `json:"state,omitempty"`
+ District string `json:"district,omitempty"`
+ Ward string `json:"ward,omitempty"`
}
type contactEnvelope struct {
@@ -358,7 +358,7 @@ func ReadContact(session Session, data json.RawMessage) (*Contact, error) {
valueEnvelope := envelope.Fields[field.key]
if valueEnvelope != nil {
value.text = valueEnvelope.Text
- value.decimal = valueEnvelope.Decimal
+ value.number = valueEnvelope.Number
value.datetime = valueEnvelope.Datetime
// TODO parse locations
@@ -393,7 +393,7 @@ func (c *Contact) MarshalJSON() ([]byte, error) {
if !v.IsEmpty() {
ce.Fields[v.field.Key()] = &fieldValueEnvelope{
Text: v.text,
- Decimal: v.decimal,
+ Number: v.number,
Datetime: v.datetime,
//State: v.state,
//District: v.district,
diff --git a/flows/definition/flow.go b/flows/definition/flow.go
index 60e8cfa24..2b1038cfc 100644
--- a/flows/definition/flow.go
+++ b/flows/definition/flow.go
@@ -89,9 +89,9 @@ func (f *flow) Validate(assets flows.SessionAssets) error {
func (f *flow) Resolve(key string) types.XValue {
switch key {
case "uuid":
- return types.NewXString(string(f.UUID()))
+ return types.NewXText(string(f.UUID()))
case "name":
- return types.NewXString(f.name)
+ return types.NewXText(f.name)
}
return types.NewXResolveError(f, key)
@@ -99,11 +99,11 @@ func (f *flow) Resolve(key string) types.XValue {
// Reduce is called when this object needs to be reduced to a primitive
func (f *flow) Reduce() types.XPrimitive {
- return types.NewXString(f.name)
+ return types.NewXText(f.name)
}
// ToXJSON is called when this type is passed to @(json(...))
-func (f *flow) ToXJSON() types.XString {
+func (f *flow) ToXJSON() types.XText {
return types.ResolveKeys(f, "uuid", "name").ToXJSON()
}
diff --git a/flows/definition/testdata/flow_validation.json b/flows/definition/testdata/flow_validation.json
index e02e04f12..a9c09d032 100644
--- a/flows/definition/testdata/flow_validation.json
+++ b/flows/definition/testdata/flow_validation.json
@@ -119,7 +119,7 @@
{
"key": "age",
"label": "Age",
- "value_type": "decimal"
+ "value_type": "number"
},
{
"key": "state",
diff --git a/flows/definition/testdata/flow_with_invalid_case_exit.json b/flows/definition/testdata/flow_with_invalid_case_exit.json
index cf33174aa..7f9e382b1 100644
--- a/flows/definition/testdata/flow_with_invalid_case_exit.json
+++ b/flows/definition/testdata/flow_with_invalid_case_exit.json
@@ -13,7 +13,7 @@
"cases": [
{
"uuid": "5d6abc80-39e7-4620-9988-a2447bffe526",
- "type": "is_string_eq",
+ "type": "is_text_eq",
"arguments": ["M"],
"exit_uuid": "37d8813f-1402-4ad2-9cc2-e9054a96525b"
}
diff --git a/flows/definition/testdata/flow_with_invalid_default_exit.json b/flows/definition/testdata/flow_with_invalid_default_exit.json
index 8d735644f..18546d257 100644
--- a/flows/definition/testdata/flow_with_invalid_default_exit.json
+++ b/flows/definition/testdata/flow_with_invalid_default_exit.json
@@ -13,7 +13,7 @@
"cases": [
{
"uuid": "5d6abc80-39e7-4620-9988-a2447bffe526",
- "type": "is_string_eq",
+ "type": "is_text_eq",
"arguments": ["M"],
"exit_uuid": "37d8813f-1402-4ad2-9cc2-e9054a96525b"
}
diff --git a/flows/fields.go b/flows/fields.go
index 965b4253c..90f362646 100644
--- a/flows/fields.go
+++ b/flows/fields.go
@@ -16,7 +16,7 @@ type FieldValueType string
// field value types
const (
FieldValueTypeText FieldValueType = "text"
- FieldValueTypeDecimal FieldValueType = "decimal"
+ FieldValueTypeNumber FieldValueType = "number"
FieldValueTypeDatetime FieldValueType = "datetime"
FieldValueTypeWard FieldValueType = "ward"
FieldValueTypeDistrict FieldValueType = "district"
@@ -47,16 +47,16 @@ func (f *Field) Key() FieldKey { return f.key }
// FieldValue represents a contact's value for a specific field
type FieldValue struct {
field *Field
- text types.XString
- datetime *types.XDate
- decimal *types.XNumber
+ text types.XText
+ datetime *types.XDateTime
+ number *types.XNumber
state *Location
district *Location
ward *Location
}
func (v *FieldValue) IsEmpty() bool {
- return !(!v.text.Empty() || v.datetime != nil || v.decimal != nil || v.state != nil || v.district != nil || v.ward != nil)
+ return !(!v.text.Empty() || v.datetime != nil || v.number != nil || v.state != nil || v.district != nil || v.ward != nil)
}
func (v *FieldValue) TypedValue() types.XValue {
@@ -67,9 +67,9 @@ func (v *FieldValue) TypedValue() types.XValue {
if v.datetime != nil {
return *v.datetime
}
- case FieldValueTypeDecimal:
- if v.decimal != nil {
- return *v.decimal
+ case FieldValueTypeNumber:
+ if v.number != nil {
+ return *v.number
}
case FieldValueTypeState:
return v.state
@@ -96,7 +96,7 @@ func (v *FieldValue) Reduce() types.XPrimitive {
}
// ToXJSON is called when this type is passed to @(json(...))
-func (v *FieldValue) ToXJSON() types.XString { return v.Reduce().ToXJSON() }
+func (v *FieldValue) ToXJSON() types.XText { return v.Reduce().ToXJSON() }
var _ types.XValue = (*FieldValue)(nil)
var _ types.XResolvable = (*FieldValue)(nil)
@@ -113,8 +113,8 @@ func (f FieldValues) clone() FieldValues {
return clone
}
-func (f FieldValues) setValue(env utils.Environment, field *Field, rawValue types.XString) {
- var asDate *types.XDate
+func (f FieldValues) setValue(env utils.Environment, field *Field, rawValue types.XText) {
+ var asDate *types.XDateTime
var asNumber *types.XNumber
if parsedNumber, xerr := types.ToXNumber(rawValue); xerr == nil {
@@ -131,7 +131,7 @@ func (f FieldValues) setValue(env utils.Environment, field *Field, rawValue type
field: field,
text: rawValue,
datetime: asDate,
- decimal: asNumber,
+ number: asNumber,
}
}
@@ -159,7 +159,7 @@ func (f FieldValues) Reduce() types.XPrimitive {
}
// ToXJSON is called when this type is passed to @(json(...))
-func (f FieldValues) ToXJSON() types.XString {
+func (f FieldValues) ToXJSON() types.XText {
return f.Reduce().ToXJSON()
}
diff --git a/flows/group.go b/flows/group.go
index fdb2ebc32..e118e43b0 100644
--- a/flows/group.go
+++ b/flows/group.go
@@ -80,19 +80,19 @@ func (g *Group) Reference() *GroupReference { return NewGroupReference(g.uuid, g
func (g *Group) Resolve(key string) types.XValue {
switch key {
case "uuid":
- return types.NewXString(string(g.uuid))
+ return types.NewXText(string(g.uuid))
case "name":
- return types.NewXString(g.name)
+ return types.NewXText(g.name)
}
return types.NewXResolveError(g, key)
}
// Reduce is called when this object needs to be reduced to a primitive
-func (g *Group) Reduce() types.XPrimitive { return types.NewXString(g.name) }
+func (g *Group) Reduce() types.XPrimitive { return types.NewXText(g.name) }
// ToXJSON is called when this type is passed to @(json(...))
-func (g *Group) ToXJSON() types.XString {
+func (g *Group) ToXJSON() types.XText {
return types.ResolveKeys(g, "uuid", "name").ToXJSON()
}
@@ -176,7 +176,7 @@ func (l GroupList) Reduce() types.XPrimitive {
}
// ToXJSON is called when this type is passed to @(json(...))
-func (l GroupList) ToXJSON() types.XString {
+func (l GroupList) ToXJSON() types.XText {
return l.Reduce().ToXJSON()
}
diff --git a/flows/inputs/base.go b/flows/inputs/base.go
index 8cf4c0f1c..f1ea321a6 100644
--- a/flows/inputs/base.go
+++ b/flows/inputs/base.go
@@ -21,9 +21,9 @@ func (i *baseInput) CreatedOn() time.Time { return i.createdOn }
func (i *baseInput) Resolve(key string) types.XValue {
switch key {
case "uuid":
- return types.NewXString(string(i.uuid))
+ return types.NewXText(string(i.uuid))
case "created_on":
- return types.NewXDate(i.createdOn)
+ return types.NewXDateTime(i.createdOn)
case "channel":
return i.channel
}
diff --git a/flows/inputs/msg.go b/flows/inputs/msg.go
index 152757a14..e051d8f35 100644
--- a/flows/inputs/msg.go
+++ b/flows/inputs/msg.go
@@ -39,11 +39,11 @@ func (i *MsgInput) Type() string { return TypeMsg }
func (i *MsgInput) Resolve(key string) types.XValue {
switch key {
case "type":
- return types.NewXString(TypeMsg)
+ return types.NewXText(TypeMsg)
case "urn":
return i.urn
case "text":
- return types.NewXString(i.text)
+ return types.NewXText(i.text)
case "attachments":
return i.attachments
}
@@ -59,11 +59,11 @@ func (i *MsgInput) Reduce() types.XPrimitive {
for _, attachment := range i.attachments {
parts = append(parts, attachment.URL())
}
- return types.NewXString(strings.Join(parts, "\n"))
+ return types.NewXText(strings.Join(parts, "\n"))
}
// ToXJSON is called when this type is passed to @(json(...))
-func (i *MsgInput) ToXJSON() types.XString {
+func (i *MsgInput) ToXJSON() types.XText {
return types.ResolveKeys(i, "uuid", "created_on", "channel", "type", "urn", "text", "attachments").ToXJSON()
}
diff --git a/flows/locations.go b/flows/locations.go
index 1c663faf1..69b18dd9d 100644
--- a/flows/locations.go
+++ b/flows/locations.go
@@ -48,10 +48,10 @@ func (b *Location) Parent() *Location { return b.parent }
func (b *Location) Children() []*Location { return b.children }
// Reduce is called when this object needs to be reduced to a primitive
-func (b *Location) Reduce() types.XPrimitive { return types.NewXString(b.name) }
+func (b *Location) Reduce() types.XPrimitive { return types.NewXText(b.name) }
// ToXJSON is called when this type is passed to @(json(...))
-func (b *Location) ToXJSON() types.XString { return types.NewXString("TODO") }
+func (b *Location) ToXJSON() types.XText { return types.NewXText("TODO") }
var _ types.XValue = (*Location)(nil)
diff --git a/flows/results.go b/flows/results.go
index 2e1cb182a..6309c188c 100644
--- a/flows/results.go
+++ b/flows/results.go
@@ -37,18 +37,18 @@ type Result struct {
func (r *Result) Resolve(key string) types.XValue {
switch key {
case "name":
- return types.NewXString(r.Name)
+ return types.NewXText(r.Name)
case "value":
- return types.NewXString(r.Value)
+ return types.NewXText(r.Value)
case "category":
- return types.NewXString(r.Category)
+ return types.NewXText(r.Category)
case "category_localized":
if r.CategoryLocalized == "" {
- return types.NewXString(r.Category)
+ return types.NewXText(r.Category)
}
- return types.NewXString(r.CategoryLocalized)
+ return types.NewXText(r.CategoryLocalized)
case "created_on":
- return types.NewXDate(r.CreatedOn)
+ return types.NewXDateTime(r.CreatedOn)
}
return types.NewXResolveError(r, key)
@@ -56,11 +56,11 @@ func (r *Result) Resolve(key string) types.XValue {
// Reduce is called when this object needs to be reduced to a primitive
func (r *Result) Reduce() types.XPrimitive {
- return types.NewXString(r.Value)
+ return types.NewXText(r.Value)
}
// ToXJSON is called when this type is passed to @(json(...))
-func (r *Result) ToXJSON() types.XString {
+func (r *Result) ToXJSON() types.XText {
return types.ResolveKeys(r, "name", "value", "category", "category_localized", "created_on").ToXJSON()
}
@@ -123,7 +123,7 @@ func (r Results) Reduce() types.XPrimitive {
}
// ToXJSON is called when this type is passed to @(json(...))
-func (r Results) ToXJSON() types.XString {
+func (r Results) ToXJSON() types.XText {
return r.Reduce().ToXJSON()
}
diff --git a/flows/results_test.go b/flows/results_test.go
index 342909309..0dffeea0b 100644
--- a/flows/results_test.go
+++ b/flows/results_test.go
@@ -19,9 +19,9 @@ func TestResults(t *testing.T) {
}{
{[]byte(`{}`), "key", ERROR},
{[]byte(`{ "name": { "result_name": "Name", "value": "Ryan Lewis", "node": "uuid", "created_on": "2000-01-01T00:00:00.000000000-00:00"}}`), "key", ERROR},
- {[]byte(`{ "name": { "result_name": "Name", "value": "Ryan Lewis", "node": "uuid", "created_on": "2000-01-01T00:00:00.000000000-00:00"}}`), "name", types.NewXString("Ryan Lewis")},
- {[]byte(`{ "last_name": { "result_name": "Last Name", "value": "Lewis", "node": "uuid", "created_on": "2000-01-01T00:00:00.000000000-00:00"}}`), "last_name", types.NewXString("Lewis")},
- {[]byte(`{ "last_name": { "result_name": "Last Name", "value": "Lewis", "node": "uuid", "created_on": "2000-01-01T00:00:00.000000000-00:00"}}`), "Last Name", types.NewXString("Lewis")},
+ {[]byte(`{ "name": { "result_name": "Name", "value": "Ryan Lewis", "node": "uuid", "created_on": "2000-01-01T00:00:00.000000000-00:00"}}`), "name", types.NewXText("Ryan Lewis")},
+ {[]byte(`{ "last_name": { "result_name": "Last Name", "value": "Lewis", "node": "uuid", "created_on": "2000-01-01T00:00:00.000000000-00:00"}}`), "last_name", types.NewXText("Lewis")},
+ {[]byte(`{ "last_name": { "result_name": "Last Name", "value": "Lewis", "node": "uuid", "created_on": "2000-01-01T00:00:00.000000000-00:00"}}`), "Last Name", types.NewXText("Lewis")},
}
env := utils.NewDefaultEnvironment()
diff --git a/flows/routers/switch.go b/flows/routers/switch.go
index 77d956ea6..45a09d774 100644
--- a/flows/routers/switch.go
+++ b/flows/routers/switch.go
@@ -80,7 +80,7 @@ func (r *SwitchRouter) PickRoute(run flows.FlowRun, exits []flows.Exit, step flo
if err != nil {
run.AddError(step, nil, err)
}
- operandAsStr, _ := types.ToXString(operand)
+ operandAsStr, _ := types.ToXText(operand)
// each of our cases
for _, c := range r.Cases {
@@ -118,7 +118,7 @@ func (r *SwitchRouter) PickRoute(run flows.FlowRun, exits []flows.Exit, step flo
case tests.XTestResult:
// looks truthy, lets return this exit
if typedResult.Matched() {
- resultAsStr, xerr := types.ToXString(typedResult.Match())
+ resultAsStr, xerr := types.ToXText(typedResult.Match())
if xerr != nil {
return "", flows.NoRoute, xerr
}
@@ -133,7 +133,7 @@ func (r *SwitchRouter) PickRoute(run flows.FlowRun, exits []flows.Exit, step flo
// we have a default exit, use that
if r.Default != "" {
// evaluate our operand as a string
- value, xerr := types.ToXString(operand)
+ value, xerr := types.ToXText(operand)
if xerr != nil {
run.AddError(step, nil, xerr)
}
diff --git a/flows/routers/tests/result.go b/flows/routers/tests/result.go
index 95413f550..04c221d33 100644
--- a/flows/routers/tests/result.go
+++ b/flows/routers/tests/result.go
@@ -20,7 +20,7 @@ func (t XTestResult) Match() types.XValue { return t.match }
func (t XTestResult) Resolve(key string) types.XValue {
switch key {
case "matched":
- return types.NewXBool(t.matched)
+ return types.NewXBoolean(t.matched)
case "match":
return t.match
}
@@ -29,11 +29,11 @@ func (t XTestResult) Resolve(key string) types.XValue {
// Reduce is called when this object needs to be reduced to a primitive
func (t XTestResult) Reduce() types.XPrimitive {
- return types.NewXBool(t.matched)
+ return types.NewXBoolean(t.matched)
}
// ToXJSON is called when this type is passed to @(json(...))
-func (t XTestResult) ToXJSON() types.XString {
+func (t XTestResult) ToXJSON() types.XText {
return types.ResolveKeys(t, "matched", "match").ToXJSON()
}
diff --git a/flows/routers/tests/tests.go b/flows/routers/tests/tests.go
index e2cb38b2d..948bf7b3a 100644
--- a/flows/routers/tests/tests.go
+++ b/flows/routers/tests/tests.go
@@ -37,32 +37,32 @@ var XTESTS = map[string]functions.XFunction{
"has_group": functions.TwoArgFunction(HasGroup),
"has_wait_timed_out": functions.OneArgFunction(HasWaitTimedOut),
- "is_string_eq": functions.TwoStringFunction(IsStringEQ),
- "has_phrase": functions.TwoStringFunction(HasPhrase),
- "has_only_phrase": functions.TwoStringFunction(HasOnlyPhrase),
- "has_any_word": functions.TwoStringFunction(HasAnyWord),
- "has_all_words": functions.TwoStringFunction(HasAllWords),
- "has_beginning": functions.TwoStringFunction(HasBeginning),
- "has_text": functions.OneStringFunction(HasText),
- "has_pattern": functions.TwoStringFunction(HasPattern),
-
- "has_number": functions.OneStringFunction(HasNumber),
+ "is_text_eq": functions.TwoTextFunction(IsTextEQ),
+ "has_phrase": functions.TwoTextFunction(HasPhrase),
+ "has_only_phrase": functions.TwoTextFunction(HasOnlyPhrase),
+ "has_any_word": functions.TwoTextFunction(HasAnyWord),
+ "has_all_words": functions.TwoTextFunction(HasAllWords),
+ "has_beginning": functions.TwoTextFunction(HasBeginning),
+ "has_text": functions.OneTextFunction(HasText),
+ "has_pattern": functions.TwoTextFunction(HasPattern),
+
+ "has_number": functions.OneTextFunction(HasNumber),
"has_number_between": functions.ThreeArgFunction(HasNumberBetween),
- "has_number_lt": functions.StringAndNumberFunction(HasNumberLT),
- "has_number_lte": functions.StringAndNumberFunction(HasNumberLTE),
- "has_number_eq": functions.StringAndNumberFunction(HasNumberEQ),
- "has_number_gte": functions.StringAndNumberFunction(HasNumberGTE),
- "has_number_gt": functions.StringAndNumberFunction(HasNumberGT),
+ "has_number_lt": functions.TextAndNumberFunction(HasNumberLT),
+ "has_number_lte": functions.TextAndNumberFunction(HasNumberLTE),
+ "has_number_eq": functions.TextAndNumberFunction(HasNumberEQ),
+ "has_number_gte": functions.TextAndNumberFunction(HasNumberGTE),
+ "has_number_gt": functions.TextAndNumberFunction(HasNumberGT),
- "has_date": functions.OneStringFunction(HasDate),
- "has_date_lt": functions.StringAndDateFunction(HasDateLT),
- "has_date_eq": functions.StringAndDateFunction(HasDateEQ),
- "has_date_gt": functions.StringAndDateFunction(HasDateGT),
+ "has_date": functions.OneTextFunction(HasDate),
+ "has_date_lt": functions.TextAndDateFunction(HasDateLT),
+ "has_date_eq": functions.TextAndDateFunction(HasDateEQ),
+ "has_date_gt": functions.TextAndDateFunction(HasDateGT),
- "has_phone": functions.TwoStringFunction(HasPhone),
- "has_email": functions.OneStringFunction(HasEmail),
+ "has_phone": functions.TwoTextFunction(HasPhone),
+ "has_email": functions.OneTextFunction(HasEmail),
- "has_state": functions.OneStringFunction(HasState),
+ "has_state": functions.OneTextFunction(HasState),
"has_district": HasDistrict,
"has_ward": HasWard,
}
@@ -71,21 +71,21 @@ var XTESTS = map[string]functions.XFunction{
// Tests
//------------------------------------------------------------------------------------------
-// IsStringEQ returns whether two strings are equal (case sensitive). In the case that they
-// are, it will return the string as the match.
+// IsTextEQ returns whether two text values are equal (case sensitive). In the case that they
+// are, it will return the text as the match.
//
-// @(is_string_eq("foo", "foo")) -> true
-// @(is_string_eq("foo", "FOO")) -> false
-// @(is_string_eq("foo", "bar")) -> false
-// @(is_string_eq("foo", " foo ")) -> false
-// @(is_string_eq(run.status, "completed")) -> true
-// @(is_string_eq(run.webhook.status, "success")) -> true
-// @(is_string_eq(run.webhook.status, "connection_error")) -> false
+// @(is_text_eq("foo", "foo")) -> true
+// @(is_text_eq("foo", "FOO")) -> false
+// @(is_text_eq("foo", "bar")) -> false
+// @(is_text_eq("foo", " foo ")) -> false
+// @(is_text_eq(run.status, "completed")) -> true
+// @(is_text_eq(run.webhook.status, "success")) -> true
+// @(is_text_eq(run.webhook.status, "connection_error")) -> false
//
-// @test is_string_eq(string, string)
-func IsStringEQ(env utils.Environment, str1 types.XString, str2 types.XString) types.XValue {
- if str1.Equals(str2) {
- return XTestResult{true, str1}
+// @test is_text_eq(text1, text2)
+func IsTextEQ(env utils.Environment, text1 types.XText, text2 types.XText) types.XValue {
+ if text1.Equals(text2) {
+ return XTestResult{true, text1}
}
return XFalseResult
@@ -169,7 +169,7 @@ func HasGroup(env utils.Environment, arg1 types.XValue, arg2 types.XValue) types
return types.NewXErrorf("must have a contact as its first argument")
}
- groupUUID, xerr := types.ToXString(arg2)
+ groupUUID, xerr := types.ToXText(arg2)
if xerr != nil {
return xerr
}
@@ -183,7 +183,7 @@ func HasGroup(env utils.Environment, arg1 types.XValue, arg2 types.XValue) types
return XFalseResult
}
-// HasPhrase tests whether `phrase` is contained in `string`
+// HasPhrase tests whether `phrase` is contained in `text`
//
// The words in the test phrase must appear in the same order with no other words
// in between.
@@ -193,12 +193,12 @@ func HasGroup(env utils.Environment, arg1 types.XValue, arg2 types.XValue) types
// @(has_phrase("the Quick Brown fox", "")) -> true
// @(has_phrase("the.quick.brown.fox", "the quick").match) -> the quick
//
-// @test has_phrase(string, phrase)
-func HasPhrase(env utils.Environment, str types.XString, test types.XString) types.XValue {
- return testStringTokens(env, str, test, hasPhraseTest)
+// @test has_phrase(text, phrase)
+func HasPhrase(env utils.Environment, text types.XText, test types.XText) types.XValue {
+ return testStringTokens(env, text, test, hasPhraseTest)
}
-// HasAllWords tests whether all the `words` are contained in `string`
+// HasAllWords tests whether all the `words` are contained in `text`
//
// The words can be in any order and may appear more than once.
//
@@ -206,12 +206,12 @@ func HasPhrase(env utils.Environment, str types.XString, test types.XString) typ
// @(has_all_words("the quick brown FOX", "the fox").match) -> the FOX
// @(has_all_words("the quick brown fox", "red fox")) -> false
//
-// @test has_all_words(string, words)
-func HasAllWords(env utils.Environment, str types.XString, test types.XString) types.XValue {
- return testStringTokens(env, str, test, hasAllWordsTest)
+// @test has_all_words(text, words)
+func HasAllWords(env utils.Environment, text types.XText, test types.XText) types.XValue {
+ return testStringTokens(env, text, test, hasAllWordsTest)
}
-// HasAnyWord tests whether any of the `words` are contained in the `string`
+// HasAnyWord tests whether any of the `words` are contained in the `text`
//
// Only one of the words needs to match and it may appear more than once.
//
@@ -219,14 +219,14 @@ func HasAllWords(env utils.Environment, str types.XString, test types.XString) t
// @(has_any_word("The Quick Brown Fox", "red fox")) -> true
// @(has_any_word("The Quick Brown Fox", "red fox").match) -> Fox
//
-// @test has_any_word(string, words)
-func HasAnyWord(env utils.Environment, str types.XString, test types.XString) types.XValue {
- return testStringTokens(env, str, test, hasAnyWordTest)
+// @test has_any_word(text, words)
+func HasAnyWord(env utils.Environment, text types.XText, test types.XText) types.XValue {
+ return testStringTokens(env, text, test, hasAnyWordTest)
}
-// HasOnlyPhrase tests whether the `string` contains only `phrase`
+// HasOnlyPhrase tests whether the `text` contains only `phrase`
//
-// The phrase must be the only text in the string to match
+// The phrase must be the only text in the text to match
//
// @(has_only_phrase("The Quick Brown Fox", "quick brown")) -> false
// @(has_only_phrase("Quick Brown", "quick brown")) -> true
@@ -235,12 +235,12 @@ func HasAnyWord(env utils.Environment, str types.XString, test types.XString) ty
// @(has_only_phrase("Quick Brown", "quick brown").match) -> Quick Brown
// @(has_only_phrase("The Quick Brown Fox", "red fox")) -> false
//
-// @test has_only_phrase(string, phrase)
-func HasOnlyPhrase(env utils.Environment, str types.XString, test types.XString) types.XValue {
- return testStringTokens(env, str, test, hasOnlyPhraseTest)
+// @test has_only_phrase(text, phrase)
+func HasOnlyPhrase(env utils.Environment, text types.XText, test types.XText) types.XValue {
+ return testStringTokens(env, text, test, hasOnlyPhraseTest)
}
-// HasText tests whether there the string has any characters in it
+// HasText tests whether there the text has any characters in it
//
// @(has_text("quick brown")) -> true
// @(has_text("quick brown").match) -> quick brown
@@ -248,22 +248,22 @@ func HasOnlyPhrase(env utils.Environment, str types.XString, test types.XString)
// @(has_text(" \n")) -> false
// @(has_text(123)) -> true
//
-// @test has_text(string)
-func HasText(env utils.Environment, str types.XString) types.XValue {
+// @test has_text(text)
+func HasText(env utils.Environment, text types.XText) types.XValue {
// trim any whitespace
- str = types.NewXString(strings.TrimSpace(str.Native()))
+ text = types.NewXText(strings.TrimSpace(text.Native()))
// if there is anything left then we have text
- if str.Length() > 0 {
- return XTestResult{true, str}
+ if text.Length() > 0 {
+ return XTestResult{true, text}
}
return XFalseResult
}
-// HasBeginning tests whether `string` starts with `beginning`
+// HasBeginning tests whether `text` starts with `beginning`
//
-// Both strings are trimmed of surrounding whitespace, but otherwise matching is strict
+// Both text values are trimmed of surrounding whitespace, but otherwise matching is strict
// without any tokenization.
//
// @(has_beginning("The Quick Brown", "the quick")) -> true
@@ -271,11 +271,11 @@ func HasText(env utils.Environment, str types.XString) types.XValue {
// @(has_beginning("The Quick Brown", "the quick")) -> false
// @(has_beginning("The Quick Brown", "quick brown")) -> false
//
-// @test has_beginning(string, beginning)
-func HasBeginning(env utils.Environment, str1 types.XString, str2 types.XString) types.XValue {
+// @test has_beginning(text, beginning)
+func HasBeginning(env utils.Environment, text types.XText, beginning types.XText) types.XValue {
// trim both
- hayStack := strings.TrimSpace(str1.Native())
- pinCushion := strings.TrimSpace(str2.Native())
+ hayStack := strings.TrimSpace(text.Native())
+ pinCushion := strings.TrimSpace(beginning.Native())
// either are empty, no match
if hayStack == "" || pinCushion == "" {
@@ -289,7 +289,7 @@ func HasBeginning(env utils.Environment, str1 types.XString, str2 types.XString)
segment := hayStack[:len(pinCushion)]
if strings.ToLower(segment) == strings.ToLower(pinCushion) {
- return XTestResult{true, types.NewXString(segment)}
+ return XTestResult{true, types.NewXText(segment)}
}
return XFalseResult
@@ -303,7 +303,7 @@ type patternMatch struct {
func newPatternMatch(matches []string) *patternMatch {
groups := types.NewXArray()
for _, match := range matches {
- groups.Append(types.NewXString(match))
+ groups.Append(types.NewXText(match))
}
return &patternMatch{groups: groups}
}
@@ -320,20 +320,20 @@ func (m *patternMatch) Resolve(key string) types.XValue {
// Reduce is called when this object needs to be reduced to a primitive
func (m *patternMatch) Reduce() types.XPrimitive {
- return m.groups.Index(0).(types.XString)
+ return m.groups.Index(0).(types.XText)
}
// ToXJSON is called when this type is passed to @(json(...))
-func (m *patternMatch) ToXJSON() types.XString {
+func (m *patternMatch) ToXJSON() types.XText {
return types.ResolveKeys(m, "groups").ToXJSON()
}
var _ types.XValue = (*patternMatch)(nil)
var _ types.XResolvable = (*patternMatch)(nil)
-// HasPattern tests whether `string` matches the regex `pattern`
+// HasPattern tests whether `text` matches the regex `pattern`
//
-// Both strings are trimmed of surrounding whitespace and matching is case-insensitive.
+// Both text values are trimmed of surrounding whitespace and matching is case-insensitive.
//
// @(has_pattern("Sell cheese please", "buy (\w+)")) -> false
// @(has_pattern("Buy cheese please", "buy (\w+)")) -> true
@@ -341,14 +341,14 @@ var _ types.XResolvable = (*patternMatch)(nil)
// @(has_pattern("Buy cheese please", "buy (\w+)").match.groups[0]) -> Buy cheese
// @(has_pattern("Buy cheese please", "buy (\w+)").match.groups[1]) -> cheese
//
-// @test has_pattern(string, pattern)
-func HasPattern(env utils.Environment, haystack types.XString, pattern types.XString) types.XValue {
+// @test has_pattern(text, pattern)
+func HasPattern(env utils.Environment, text types.XText, pattern types.XText) types.XValue {
regex, err := regexp.Compile("(?i)" + strings.TrimSpace(pattern.Native()))
if err != nil {
return types.NewXErrorf("must be called with a valid regular expression")
}
- matches := regex.FindStringSubmatch(strings.TrimSpace(haystack.Native()))
+ matches := regex.FindStringSubmatch(strings.TrimSpace(text.Native()))
if matches != nil {
return XTestResult{true, newPatternMatch(matches)}
}
@@ -356,18 +356,18 @@ func HasPattern(env utils.Environment, haystack types.XString, pattern types.XSt
return XFalseResult
}
-// HasNumber tests whether `string` contains a number
+// HasNumber tests whether `text` contains a number
//
// @(has_number("the number is 42")) -> true
// @(has_number("the number is 42").match) -> 42
// @(has_number("the number is forty two")) -> false
//
-// @test has_number(string)
-func HasNumber(env utils.Environment, str types.XString) types.XValue {
- return testNumber(env, str, types.XNumberZero, isNumberTest)
+// @test has_number(text)
+func HasNumber(env utils.Environment, text types.XText) types.XValue {
+ return testNumber(env, text, types.XNumberZero, isNumberTest)
}
-// HasNumberBetween tests whether `string` contains a number between `min` and `max` inclusive
+// HasNumberBetween tests whether `text` contains a number between `min` and `max` inclusive
//
// @(has_number_between("the number is 42", 40, 44)) -> true
// @(has_number_between("the number is 42", 40, 44).match) -> 42
@@ -375,9 +375,9 @@ func HasNumber(env utils.Environment, str types.XString) types.XValue {
// @(has_number_between("the number is not there", 50, 60)) -> false
// @(has_number_between("the number is not there", "foo", 60)) -> ERROR
//
-// @test has_number_between(string, min, max)
+// @test has_number_between(text, min, max)
func HasNumberBetween(env utils.Environment, arg1 types.XValue, arg2 types.XValue, arg3 types.XValue) types.XValue {
- str, xerr := types.ToXString(arg1)
+ str, xerr := types.ToXText(arg1)
if xerr != nil {
return xerr
}
@@ -392,7 +392,7 @@ func HasNumberBetween(env utils.Environment, arg1 types.XValue, arg2 types.XValu
// for each of our values, try to evaluate to a decimal
for _, value := range strings.Fields(str.Native()) {
- num, xerr := types.ToXNumber(types.NewXString(value))
+ num, xerr := types.ToXNumber(types.NewXText(value))
if xerr == nil {
if num.Compare(min) >= 0 && num.Compare(max) <= 0 {
return XTestResult{true, num}
@@ -402,7 +402,7 @@ func HasNumberBetween(env utils.Environment, arg1 types.XValue, arg2 types.XValu
return XFalseResult
}
-// HasNumberLT tests whether `string` contains a number less than `max`
+// HasNumberLT tests whether `text` contains a number less than `max`
//
// @(has_number_lt("the number is 42", 44)) -> true
// @(has_number_lt("the number is 42", 44).match) -> 42
@@ -410,12 +410,12 @@ func HasNumberBetween(env utils.Environment, arg1 types.XValue, arg2 types.XValu
// @(has_number_lt("the number is not there", 40)) -> false
// @(has_number_lt("the number is not there", "foo")) -> ERROR
//
-// @test has_number_lt(string, max)
-func HasNumberLT(env utils.Environment, str types.XString, num types.XNumber) types.XValue {
- return testNumber(env, str, num, isNumberLT)
+// @test has_number_lt(text, max)
+func HasNumberLT(env utils.Environment, text types.XText, num types.XNumber) types.XValue {
+ return testNumber(env, text, num, isNumberLT)
}
-// HasNumberLTE tests whether `value` contains a number less than or equal to `max`
+// HasNumberLTE tests whether `text` contains a number less than or equal to `max`
//
// @(has_number_lte("the number is 42", 42)) -> true
// @(has_number_lte("the number is 42", 44).match) -> 42
@@ -423,12 +423,12 @@ func HasNumberLT(env utils.Environment, str types.XString, num types.XNumber) ty
// @(has_number_lte("the number is not there", 40)) -> false
// @(has_number_lte("the number is not there", "foo")) -> ERROR
//
-// @test has_number_lte(string, max)
-func HasNumberLTE(env utils.Environment, str types.XString, num types.XNumber) types.XValue {
- return testNumber(env, str, num, isNumberLTE)
+// @test has_number_lte(text, max)
+func HasNumberLTE(env utils.Environment, text types.XText, num types.XNumber) types.XValue {
+ return testNumber(env, text, num, isNumberLTE)
}
-// HasNumberEQ tests whether `strung` contains a number equal to the `value`
+// HasNumberEQ tests whether `text` contains a number equal to the `value`
//
// @(has_number_eq("the number is 42", 42)) -> true
// @(has_number_eq("the number is 42", 42).match) -> 42
@@ -436,12 +436,12 @@ func HasNumberLTE(env utils.Environment, str types.XString, num types.XNumber) t
// @(has_number_eq("the number is not there", 40)) -> false
// @(has_number_eq("the number is not there", "foo")) -> ERROR
//
-// @test has_number_eq(string, value)
-func HasNumberEQ(env utils.Environment, str types.XString, num types.XNumber) types.XValue {
- return testNumber(env, str, num, isNumberEQ)
+// @test has_number_eq(text, value)
+func HasNumberEQ(env utils.Environment, text types.XText, num types.XNumber) types.XValue {
+ return testNumber(env, text, num, isNumberEQ)
}
-// HasNumberGTE tests whether `string` contains a number greater than or equal to `min`
+// HasNumberGTE tests whether `text` contains a number greater than or equal to `min`
//
// @(has_number_gte("the number is 42", 42)) -> true
// @(has_number_gte("the number is 42", 42).match) -> 42
@@ -449,12 +449,12 @@ func HasNumberEQ(env utils.Environment, str types.XString, num types.XNumber) ty
// @(has_number_gte("the number is not there", 40)) -> false
// @(has_number_gte("the number is not there", "foo")) -> ERROR
//
-// @test has_number_gte(string, min)
-func HasNumberGTE(env utils.Environment, str types.XString, num types.XNumber) types.XValue {
- return testNumber(env, str, num, isNumberGTE)
+// @test has_number_gte(text, min)
+func HasNumberGTE(env utils.Environment, text types.XText, num types.XNumber) types.XValue {
+ return testNumber(env, text, num, isNumberGTE)
}
-// HasNumberGT tests whether `string` contains a number greater than `min`
+// HasNumberGT tests whether `text` contains a number greater than `min`
//
// @(has_number_gt("the number is 42", 40)) -> true
// @(has_number_gt("the number is 42", 40).match) -> 42
@@ -462,35 +462,35 @@ func HasNumberGTE(env utils.Environment, str types.XString, num types.XNumber) t
// @(has_number_gt("the number is not there", 40)) -> false
// @(has_number_gt("the number is not there", "foo")) -> ERROR
//
-// @test has_number_gt(string, min)
-func HasNumberGT(env utils.Environment, str types.XString, num types.XNumber) types.XValue {
- return testNumber(env, str, num, isNumberGT)
+// @test has_number_gt(text, min)
+func HasNumberGT(env utils.Environment, text types.XText, num types.XNumber) types.XValue {
+ return testNumber(env, text, num, isNumberGT)
}
-// HasDate tests whether `string` contains a date formatted according to our environment
+// HasDate tests whether `text` contains a date formatted according to our environment
//
// @(has_date("the date is 2017-01-15")) -> true
// @(has_date("the date is 2017-01-15").match) -> 2017-01-15T00:00:00.000000-05:00
// @(has_date("there is no date here, just a year 2017")) -> false
//
-// @test has_date(string)
-func HasDate(env utils.Environment, str types.XString) types.XValue {
- return testDate(env, str, types.XDateZero, isDateTest)
+// @test has_date(text)
+func HasDate(env utils.Environment, text types.XText) types.XValue {
+ return testDate(env, text, types.XDateTimeZero, isDateTest)
}
-// HasDateLT tests whether `value` contains a date before the date `max`
+// HasDateLT tests whether `text` contains a date before the date `max`
//
// @(has_date_lt("the date is 2017-01-15", "2017-06-01")) -> true
// @(has_date_lt("the date is 2017-01-15", "2017-06-01").match) -> 2017-01-15T00:00:00.000000-05:00
// @(has_date_lt("there is no date here, just a year 2017", "2017-06-01")) -> false
// @(has_date_lt("there is no date here, just a year 2017", "not date")) -> ERROR
//
-// @test has_date_lt(string, max)
-func HasDateLT(env utils.Environment, str types.XString, date types.XDate) types.XValue {
- return testDate(env, str, date, isDateLTTest)
+// @test has_date_lt(text, max)
+func HasDateLT(env utils.Environment, text types.XText, date types.XDateTime) types.XValue {
+ return testDate(env, text, date, isDateLTTest)
}
-// HasDateEQ tests whether `string` a date equal to `date`
+// HasDateEQ tests whether `text` a date equal to `date`
//
// @(has_date_eq("the date is 2017-01-15", "2017-01-15")) -> true
// @(has_date_eq("the date is 2017-01-15", "2017-01-15").match) -> 2017-01-15T00:00:00.000000-05:00
@@ -498,12 +498,12 @@ func HasDateLT(env utils.Environment, str types.XString, date types.XDate) types
// @(has_date_eq("there is no date here, just a year 2017", "2017-06-01")) -> false
// @(has_date_eq("there is no date here, just a year 2017", "not date")) -> ERROR
//
-// @test has_date_eq(string, date)
-func HasDateEQ(env utils.Environment, str types.XString, date types.XDate) types.XValue {
- return testDate(env, str, date, isDateEQTest)
+// @test has_date_eq(text, date)
+func HasDateEQ(env utils.Environment, text types.XText, date types.XDateTime) types.XValue {
+ return testDate(env, text, date, isDateEQTest)
}
-// HasDateGT tests whether `string` a date after the date `min`
+// HasDateGT tests whether `text` a date after the date `min`
//
// @(has_date_gt("the date is 2017-01-15", "2017-01-01")) -> true
// @(has_date_gt("the date is 2017-01-15", "2017-01-01").match) -> 2017-01-15T00:00:00.000000-05:00
@@ -511,62 +511,62 @@ func HasDateEQ(env utils.Environment, str types.XString, date types.XDate) types
// @(has_date_gt("there is no date here, just a year 2017", "2017-06-01")) -> false
// @(has_date_gt("there is no date here, just a year 2017", "not date")) -> ERROR
//
-// @test has_date_gt(string, min)
-func HasDateGT(env utils.Environment, str types.XString, date types.XDate) types.XValue {
- return testDate(env, str, date, isDateGTTest)
+// @test has_date_gt(text, min)
+func HasDateGT(env utils.Environment, text types.XText, date types.XDateTime) types.XValue {
+ return testDate(env, text, date, isDateGTTest)
}
var emailAddressRE = regexp.MustCompile(`([\pL\pN][-_.\pL\pN]*)@([\pL\pN][-_\pL\pN]*)(\.[\pL\pN][-_\pL\pN]*)+`)
-// HasEmail tests whether an email is contained in `string`
+// HasEmail tests whether an email is contained in `text`
//
// @(has_email("my email is foo1@bar.com, please respond")) -> true
// @(has_email("my email is foo1@bar.com, please respond").match) -> foo1@bar.com
// @(has_email("my email is ")) -> true
// @(has_email("i'm not sharing my email")) -> false
//
-// @test has_email(string)
-func HasEmail(env utils.Environment, str types.XString) types.XValue {
+// @test has_email(text)
+func HasEmail(env utils.Environment, text types.XText) types.XValue {
// split by whitespace
- email := emailAddressRE.FindString(str.Native())
+ email := emailAddressRE.FindString(text.Native())
if email != "" {
- return XTestResult{true, types.NewXString(email)}
+ return XTestResult{true, types.NewXText(email)}
}
return XFalseResult
}
-// HasPhone tests whether a phone number (in the passed in `country_code`) is contained in the `string`
+// HasPhone tests whether a phone number (in the passed in `country_code`) is contained in the `text`
//
// @(has_phone("my number is 2067799294", "US")) -> true
// @(has_phone("my number is 206 779 9294", "US").match) -> +12067799294
// @(has_phone("my number is none of your business", "US")) -> false
//
-// @test has_phone(string, country_code)
-func HasPhone(env utils.Environment, str types.XString, country types.XString) types.XValue {
+// @test has_phone(text, country_code)
+func HasPhone(env utils.Environment, text types.XText, country types.XText) types.XValue {
// try to find a phone number
- phone, err := phonenumbers.Parse(str.Native(), country.Native())
+ phone, err := phonenumbers.Parse(text.Native(), country.Native())
if err != nil {
return XFalseResult
}
// format as E164 number
formatted := phonenumbers.Format(phone, phonenumbers.E164)
- return XTestResult{true, types.NewXString(formatted)}
+ return XTestResult{true, types.NewXText(formatted)}
}
-// HasState tests whether a state name is contained in the `string`
+// HasState tests whether a state name is contained in the `text`
//
// @(has_state("Kigali")) -> true
// @(has_state("Boston")) -> false
// @(has_state("¡Kigali!")) -> true
// @(has_state("I live in Kigali")) -> true
//
-// @test has_state(string)
-func HasState(env utils.Environment, str types.XString) types.XValue {
+// @test has_state(text)
+func HasState(env utils.Environment, text types.XText) types.XValue {
runEnv, _ := env.(flows.RunEnvironment)
- states, err := runEnv.FindLocationsFuzzy(str.Native(), flows.LocationLevel(1), nil)
+ states, err := runEnv.FindLocationsFuzzy(text.Native(), flows.LocationLevel(1), nil)
if err != nil {
return types.NewXError(err)
}
@@ -576,7 +576,7 @@ func HasState(env utils.Environment, str types.XString) types.XValue {
return XFalseResult
}
-// HasDistrict tests whether a district name is contained in the `string`. If `state` is also provided
+// HasDistrict tests whether a district name is contained in the `text`. If `state` is also provided
// then the returned district must be within that state.
//
// @(has_district("Gasabo", "Kigali")) -> true
@@ -584,7 +584,7 @@ func HasState(env utils.Environment, str types.XString) types.XValue {
// @(has_district("Gasabo", "Boston")) -> false
// @(has_district("Gasabo")) -> true
//
-// @test has_district(string, state)
+// @test has_district(text, state)
func HasDistrict(env utils.Environment, args ...types.XValue) types.XValue {
if len(args) != 1 && len(args) != 2 {
return types.NewXErrorf("takes one or two arguments, got %d", len(args))
@@ -592,15 +592,15 @@ func HasDistrict(env utils.Environment, args ...types.XValue) types.XValue {
runEnv, _ := env.(flows.RunEnvironment)
- var text, stateText types.XString
+ var text, stateText types.XText
var xerr types.XError
// grab the text we will search and the parent state name
- if text, xerr = types.ToXString(args[0]); xerr != nil {
+ if text, xerr = types.ToXText(args[0]); xerr != nil {
return xerr
}
if len(args) == 2 {
- if stateText, xerr = types.ToXString(args[1]); xerr != nil {
+ if stateText, xerr = types.ToXText(args[1]); xerr != nil {
return xerr
}
}
@@ -633,7 +633,7 @@ func HasDistrict(env utils.Environment, args ...types.XValue) types.XValue {
return XFalseResult
}
-// HasWard tests whether a ward name is contained in the `string`
+// HasWard tests whether a ward name is contained in the `text`
//
// @(has_ward("Gisozi", "Gasabo", "Kigali")) -> true
// @(has_ward("I live in Gisozi", "Gasabo", "Kigali")) -> true
@@ -643,7 +643,7 @@ func HasDistrict(env utils.Environment, args ...types.XValue) types.XValue {
// @(has_ward("Gasabo")) -> false
// @(has_ward("Gisozi")) -> true
//
-// @test has_ward(string, district, state)
+// @test has_ward(text, district, state)
func HasWard(env utils.Environment, args ...types.XValue) types.XValue {
if len(args) != 1 && len(args) != 3 {
return types.NewXErrorf("takes one or three arguments, got %d", len(args))
@@ -651,18 +651,18 @@ func HasWard(env utils.Environment, args ...types.XValue) types.XValue {
runEnv, _ := env.(flows.RunEnvironment)
- var text, districtText, stateText types.XString
+ var text, districtText, stateText types.XText
var xerr types.XError
// grab the text we will search, as well as the parent district and state names
- if text, xerr = types.ToXString(args[0]); xerr != nil {
+ if text, xerr = types.ToXText(args[0]); xerr != nil {
return xerr
}
if len(args) == 3 {
- if districtText, xerr = types.ToXString(args[1]); xerr != nil {
+ if districtText, xerr = types.ToXText(args[1]); xerr != nil {
return xerr
}
- if stateText, xerr = types.ToXString(args[2]); xerr != nil {
+ if stateText, xerr = types.ToXText(args[2]); xerr != nil {
return xerr
}
}
@@ -702,12 +702,12 @@ func HasWard(env utils.Environment, args ...types.XValue) types.XValue {
}
//------------------------------------------------------------------------------------------
-// String Test Functions
+// Text Test Functions
//------------------------------------------------------------------------------------------
type stringTokenTest func(origHayTokens []string, hayTokens []string, pinTokens []string) XTestResult
-func testStringTokens(env utils.Environment, str types.XString, testStr types.XString, testFunc stringTokenTest) types.XValue {
+func testStringTokens(env utils.Environment, str types.XText, testStr types.XText, testFunc stringTokenTest) types.XValue {
hayStack := strings.TrimSpace(str.Native())
needle := strings.TrimSpace(testStr.Native())
@@ -720,7 +720,7 @@ func testStringTokens(env utils.Environment, str types.XString, testStr types.XS
func hasPhraseTest(origHays []string, hays []string, pins []string) XTestResult {
if len(pins) == 0 {
- return XTestResult{true, types.XStringEmpty}
+ return XTestResult{true, types.XTextEmpty}
}
pinIdx := 0
@@ -738,7 +738,7 @@ func hasPhraseTest(origHays []string, hays []string, pins []string) XTestResult
}
if pinIdx == len(pins) {
- return XTestResult{true, types.NewXString(strings.Join(matches, " "))}
+ return XTestResult{true, types.NewXText(strings.Join(matches, " "))}
}
return XFalseResult
@@ -772,7 +772,7 @@ func hasAllWordsTest(origHays []string, hays []string, pins []string) XTestResul
}
if allMatch {
- return XTestResult{true, types.NewXString(strings.Join(matches, " "))}
+ return XTestResult{true, types.NewXText(strings.Join(matches, " "))}
}
return XFalseResult
@@ -795,7 +795,7 @@ func hasAnyWordTest(origHays []string, hays []string, pins []string) XTestResult
}
if len(matches) > 0 {
- return XTestResult{true, types.NewXString(strings.Join(matches, " "))}
+ return XTestResult{true, types.NewXText(strings.Join(matches, " "))}
}
return XFalseResult
@@ -816,7 +816,7 @@ func hasOnlyPhraseTest(origHays []string, hays []string, pins []string) XTestRes
matches = append(matches, origHays[i])
}
- return XTestResult{true, types.NewXString(strings.Join(matches, " "))}
+ return XTestResult{true, types.NewXText(strings.Join(matches, " "))}
}
//------------------------------------------------------------------------------------------
@@ -825,10 +825,10 @@ func hasOnlyPhraseTest(origHays []string, hays []string, pins []string) XTestRes
type decimalTest func(value decimal.Decimal, test decimal.Decimal) bool
-func testNumber(env utils.Environment, str types.XString, testNum types.XNumber, testFunc decimalTest) types.XValue {
+func testNumber(env utils.Environment, str types.XText, testNum types.XNumber, testFunc decimalTest) types.XValue {
// for each of our values, try to evaluate to a decimal
for _, value := range strings.Fields(str.Native()) {
- num, xerr := types.ToXNumber(types.NewXString(value))
+ num, xerr := types.ToXNumber(types.NewXText(value))
if xerr == nil {
if testFunc(num.Native(), testNum.Native()) {
return XTestResult{true, num}
@@ -869,7 +869,7 @@ func isNumberGT(value decimal.Decimal, test decimal.Decimal) bool {
type dateTest func(value time.Time, test time.Time) bool
-func testDate(env utils.Environment, str types.XString, testDate types.XDate, testFunc dateTest) types.XValue {
+func testDate(env utils.Environment, str types.XText, testDate types.XDateTime, testFunc dateTest) types.XValue {
// error is if we don't find a date on our test value, that's ok but no match
value, xerr := types.ToXDate(env, str)
if xerr != nil {
diff --git a/flows/routers/tests/tests_test.go b/flows/routers/tests/tests_test.go
index 04b4ad483..48ecce7de 100644
--- a/flows/routers/tests/tests_test.go
+++ b/flows/routers/tests/tests_test.go
@@ -13,17 +13,17 @@ import (
"github.com/stretchr/testify/assert"
)
-var xs = types.NewXString
+var xs = types.NewXText
var xn = types.RequireXNumberFromString
var xi = types.NewXNumberFromInt
-var xt = types.NewXDate
+var xt = types.NewXDateTime
type testResolvable struct{}
func (r *testResolvable) Resolve(key string) types.XValue {
switch key {
case "foo":
- return types.NewXString("bar")
+ return types.NewXText("bar")
case "zed":
return types.NewXNumberFromInt(123)
case "missing":
@@ -35,11 +35,11 @@ func (r *testResolvable) Resolve(key string) types.XValue {
// Reduce is called when this object needs to be reduced to a primitive
func (r *testResolvable) Reduce() types.XPrimitive {
- return types.NewXString("hello")
+ return types.NewXText("hello")
}
// ToXJSON is called when this type is passed to @(json(...))
-func (r *testResolvable) ToXJSON() types.XString {
+func (r *testResolvable) ToXJSON() types.XText {
return types.ResolveKeys(r, "foo", "zed").ToXJSON()
}
diff --git a/flows/runs/context.go b/flows/runs/context.go
index 44fbb714b..f9d9d5df5 100644
--- a/flows/runs/context.go
+++ b/flows/runs/context.go
@@ -36,11 +36,11 @@ func (c *runContext) Resolve(key string) types.XValue {
}
func (c *runContext) Reduce() types.XPrimitive {
- return types.NewXString(c.run.UUID().String())
+ return types.NewXText(c.run.UUID().String())
}
// ToXJSON can never actually be called on the context root
-func (c *runContext) ToXJSON() types.XString {
+func (c *runContext) ToXJSON() types.XText {
panic("shouldn't be possible to call ToXJSON on the context root")
}
@@ -64,13 +64,13 @@ func newRelatedRunContext(run flows.RunSummary) *relatedRunContext {
func (c *relatedRunContext) Resolve(key string) types.XValue {
switch key {
case "uuid":
- return types.NewXString(string(c.run.UUID()))
+ return types.NewXText(string(c.run.UUID()))
case "contact":
return c.run.Contact()
case "flow":
return c.run.Flow()
case "status":
- return types.NewXString(string(c.run.Status()))
+ return types.NewXText(string(c.run.Status()))
case "results":
return c.run.Results()
}
@@ -79,11 +79,11 @@ func (c *relatedRunContext) Resolve(key string) types.XValue {
}
func (c *relatedRunContext) Reduce() types.XPrimitive {
- return types.NewXString(c.run.UUID().String())
+ return types.NewXText(c.run.UUID().String())
}
// ToXJSON is called when this type is passed to @(json(...))
-func (c *relatedRunContext) ToXJSON() types.XString {
+func (c *relatedRunContext) ToXJSON() types.XText {
return types.ResolveKeys(c, "uuid", "contact", "flow", "status", "results").ToXJSON()
}
diff --git a/flows/runs/run.go b/flows/runs/run.go
index e79022d08..93b987426 100644
--- a/flows/runs/run.go
+++ b/flows/runs/run.go
@@ -251,7 +251,7 @@ func (r *flowRun) GetTranslatedTextArray(uuid utils.UUID, key string, native []s
func (r *flowRun) Resolve(key string) types.XValue {
switch key {
case "uuid":
- return types.NewXString(string(r.UUID()))
+ return types.NewXText(string(r.UUID()))
case "contact":
return r.Contact()
case "flow":
@@ -261,14 +261,14 @@ func (r *flowRun) Resolve(key string) types.XValue {
case "webhook":
return r.Webhook()
case "status":
- return types.NewXString(string(r.Status()))
+ return types.NewXText(string(r.Status()))
case "results":
return r.Results()
case "created_on":
- return types.NewXDate(r.CreatedOn())
+ return types.NewXDateTime(r.CreatedOn())
case "exited_on":
if r.exitedOn != nil {
- return types.NewXDate(*r.exitedOn)
+ return types.NewXDateTime(*r.exitedOn)
}
return nil
}
@@ -278,10 +278,10 @@ func (r *flowRun) Resolve(key string) types.XValue {
// Reduce is called when this object needs to be reduced to a primitive
func (r *flowRun) Reduce() types.XPrimitive {
- return types.NewXString(string(r.uuid))
+ return types.NewXText(string(r.uuid))
}
-func (r *flowRun) ToXJSON() types.XString {
+func (r *flowRun) ToXJSON() types.XText {
return types.ResolveKeys(r, "uuid", "contact", "flow", "input", "webhook", "status", "results", "created_on", "exited_on").ToXJSON()
}
diff --git a/flows/triggers/base.go b/flows/triggers/base.go
index e0b71066a..f9b0ed35f 100644
--- a/flows/triggers/base.go
+++ b/flows/triggers/base.go
@@ -34,5 +34,5 @@ func (t *baseTrigger) Resolve(key string) types.XValue {
// Reduce is called when this object needs to be reduced to a primitive
func (t *baseTrigger) Reduce() types.XPrimitive {
- return types.NewXString(string(t.flow.UUID()))
+ return types.NewXText(string(t.flow.UUID()))
}
diff --git a/flows/triggers/flow_action.go b/flows/triggers/flow_action.go
index c95a08742..a84eb4f62 100644
--- a/flows/triggers/flow_action.go
+++ b/flows/triggers/flow_action.go
@@ -53,14 +53,14 @@ func (t *FlowActionTrigger) Run() flows.RunSummary { return t.run }
func (t *FlowActionTrigger) Resolve(key string) types.XValue {
switch key {
case "type":
- return types.NewXString(TypeFlowAction)
+ return types.NewXText(TypeFlowAction)
}
return t.baseTrigger.Resolve(key)
}
// ToXJSON is called when this type is passed to @(json(...))
-func (t *FlowActionTrigger) ToXJSON() types.XString {
+func (t *FlowActionTrigger) ToXJSON() types.XText {
return types.ResolveKeys(t, "type", "params").ToXJSON()
}
diff --git a/flows/triggers/manual.go b/flows/triggers/manual.go
index 2273d0819..4a687e002 100644
--- a/flows/triggers/manual.go
+++ b/flows/triggers/manual.go
@@ -41,14 +41,14 @@ func (t *ManualTrigger) Type() string { return TypeManual }
func (t *ManualTrigger) Resolve(key string) types.XValue {
switch key {
case "type":
- return types.NewXString(TypeManual)
+ return types.NewXText(TypeManual)
}
return t.baseTrigger.Resolve(key)
}
// ToXJSON is called when this type is passed to @(json(...))
-func (t *ManualTrigger) ToXJSON() types.XString {
+func (t *ManualTrigger) ToXJSON() types.XText {
return types.ResolveKeys(t, "type", "params").ToXJSON()
}
diff --git a/flows/urns.go b/flows/urns.go
index 0795ad080..1b60e7f4f 100644
--- a/flows/urns.go
+++ b/flows/urns.go
@@ -74,11 +74,11 @@ func (u *ContactURN) SetChannel(channel Channel) { u.channel = channel }
func (u *ContactURN) Resolve(key string) types.XValue {
switch key {
case "scheme":
- return types.NewXString(u.URN.Scheme())
+ return types.NewXText(u.URN.Scheme())
case "path":
- return types.NewXString(u.URN.Path())
+ return types.NewXText(u.URN.Path())
case "display":
- return types.NewXString(u.URN.Display())
+ return types.NewXText(u.URN.Display())
case "channel":
return u.Channel()
}
@@ -86,10 +86,10 @@ func (u *ContactURN) Resolve(key string) types.XValue {
}
// Reduce is called when this object needs to be reduced to a primitive
-func (u *ContactURN) Reduce() types.XPrimitive { return types.NewXString(string(u.URN)) }
+func (u *ContactURN) Reduce() types.XPrimitive { return types.NewXText(string(u.URN)) }
// ToXJSON is called when this type is passed to @(json(...))
-func (u *ContactURN) ToXJSON() types.XString {
+func (u *ContactURN) ToXJSON() types.XText {
return types.ResolveKeys(u, "scheme", "path", "display").ToXJSON()
}
@@ -185,7 +185,7 @@ func (l URNList) Reduce() types.XPrimitive {
}
// ToXJSON is called when this type is passed to @(json(...))
-func (l URNList) ToXJSON() types.XString {
+func (l URNList) ToXJSON() types.XText {
return l.Reduce().ToXJSON()
}
diff --git a/flows/webhook.go b/flows/webhook.go
index 11a1f605a..3219b54ce 100644
--- a/flows/webhook.go
+++ b/flows/webhook.go
@@ -100,17 +100,17 @@ func (w *WebhookCall) JSON() types.XValue { return types.JSONToXValue([]byte(w.b
func (w *WebhookCall) Resolve(key string) types.XValue {
switch key {
case "body":
- return types.NewXString(w.Body())
+ return types.NewXText(w.Body())
case "json":
return w.JSON()
case "url":
- return types.NewXString(w.URL())
+ return types.NewXText(w.URL())
case "request":
- return types.NewXString(w.Request())
+ return types.NewXText(w.Request())
case "response":
- return types.NewXString(w.Response())
+ return types.NewXText(w.Response())
case "status":
- return types.NewXString(string(w.Status()))
+ return types.NewXText(string(w.Status()))
case "status_code":
return types.NewXNumberFromInt(w.StatusCode())
}
@@ -120,11 +120,11 @@ func (w *WebhookCall) Resolve(key string) types.XValue {
// Reduce is called when this object needs to be reduced to a primitive
func (w *WebhookCall) Reduce() types.XPrimitive {
- return types.NewXString(w.body)
+ return types.NewXText(w.body)
}
// ToXJSON is called when this type is passed to @(json(...))
-func (w *WebhookCall) ToXJSON() types.XString {
+func (w *WebhookCall) ToXJSON() types.XText {
return types.ResolveKeys(w, "body", "json", "url", "request", "response", "status", "status_code").ToXJSON()
}
diff --git a/legacy/definition.go b/legacy/definition.go
index 0b2aea385..d84a785ce 100644
--- a/legacy/definition.go
+++ b/legacy/definition.go
@@ -649,13 +649,13 @@ func migrateRule(baseLanguage utils.Language, exitMap map[string]flows.Exit, r R
arguments = []string{string(test.Test.UUID)}
case "subflow":
- newType = "is_string_eq"
+ newType = "is_text_eq"
test := subflowTest{}
err = json.Unmarshal(r.Test.Data, &test)
arguments = []string{test.ExitType}
case "webhook_status":
- newType = "is_string_eq"
+ newType = "is_text_eq"
test := webhookTest{}
err = json.Unmarshal(r.Test.Data, &test)
if test.Status == "success" {
@@ -767,7 +767,7 @@ func parseRules(baseLanguage utils.Language, r RuleSet, localization flows.Local
exits = append(exits, connectionErrorExit)
cases = append(cases, routers.Case{
UUID: utils.UUID(utils.NewUUID()),
- Type: "is_string_eq",
+ Type: "is_text_eq",
Arguments: []string{"connection_error"},
OmitOperand: false,
ExitUUID: connectionErrorExitUUID,
diff --git a/legacy/expressions.go b/legacy/expressions.go
index c6a82f525..8588b1639 100644
--- a/legacy/expressions.go
+++ b/legacy/expressions.go
@@ -69,7 +69,7 @@ func (v *varMapper) Resolve(key string) types.XValue {
// is this a complete substitution?
if substitute, ok := v.substitutions[key]; ok {
- return types.NewXString(substitute)
+ return types.NewXText(substitute)
}
newPath := make([]string, 0, 1)
@@ -97,7 +97,7 @@ func (v *varMapper) Resolve(key string) types.XValue {
// or a simple string in which case we add to the end of the path and return that
newPath = append(newPath, value.(string))
- return types.NewXString(strings.Join(newPath, "."))
+ return types.NewXText(strings.Join(newPath, "."))
}
// then it must be an arbitrary item
@@ -114,16 +114,16 @@ func (v *varMapper) Resolve(key string) types.XValue {
}
}
- return types.NewXString(strings.Join(newPath, "."))
+ return types.NewXText(strings.Join(newPath, "."))
}
// Reduce is called when this object needs to be reduced to a primitive
func (v *varMapper) Reduce() types.XPrimitive {
- return types.NewXString(v.String())
+ return types.NewXText(v.String())
}
// ToXJSON won't be called on this but needs to be defined
-func (v *varMapper) ToXJSON() types.XString { return types.XStringEmpty }
+func (v *varMapper) ToXJSON() types.XText { return types.XTextEmpty }
func (v *varMapper) String() string {
sub, exists := v.substitutions["__default__"]
@@ -158,13 +158,13 @@ func (m *extraMapper) Resolve(key string) types.XValue {
func (m *extraMapper) Reduce() types.XPrimitive {
switch m.extraAs {
case ExtraAsWebhookJSON:
- return types.NewXString(fmt.Sprintf("run.webhook.json.%s", m.path))
+ return types.NewXText(fmt.Sprintf("run.webhook.json.%s", m.path))
case ExtraAsTriggerParams:
- return types.NewXString(fmt.Sprintf("trigger.params.%s", m.path))
+ return types.NewXText(fmt.Sprintf("trigger.params.%s", m.path))
case ExtraAsFunction:
- return types.NewXString(fmt.Sprintf("if(is_error(run.webhook.json.%s), trigger.params.%s, run.webhook.json.%s)", m.path, m.path, m.path))
+ return types.NewXText(fmt.Sprintf("if(is_error(run.webhook.json.%s), trigger.params.%s, run.webhook.json.%s)", m.path, m.path, m.path))
}
- return types.XStringEmpty
+ return types.XTextEmpty
}
var _ types.XValue = (*extraMapper)(nil)
@@ -182,16 +182,16 @@ type functionTemplate struct {
var functionTemplates = map[string]functionTemplate{
"first_word": {name: "word", params: "(%s, 0)"},
"datevalue": {name: "date"},
- "edate": {name: "date_add", params: "(%s, %s, \"M\")"},
+ "edate": {name: "datetime_add", params: "(%s, %s, \"M\")"},
"word": {name: "word", params: "(%s, %s - 1)"},
"word_slice": {name: "word_slice", params: "(%s, %s - 1)", three: "(%s, %s - 1, %s - 1)"},
"field": {name: "field", params: "(%s, %s - 1, %s)"},
- "datedif": {name: "date_diff"},
+ "datedif": {name: "datetime_diff"},
"date": {name: "date", params: "(\"%s-%s-%s\")"},
- "days": {name: "date_diff", params: "(%s, %s, \"D\")"},
+ "days": {name: "datetime_diff", params: "(%s, %s, \"D\")"},
"now": {name: "now", params: "()"},
"average": {name: "mean"},
- "fixed": {name: "format_num", params: "(%s)", two: "(%s, %s)", three: "(%s, %s, %v)"},
+ "fixed": {name: "format_number", params: "(%s)", two: "(%s, %s)", three: "(%s, %s, %v)"},
"roundup": {name: "round_up"},
"int": {name: "round_down"},
@@ -216,7 +216,7 @@ var functionTemplates = map[string]functionTemplate{
"power": {params: "%s ^ %s"},
"sum": {params: "%s + %s"},
- // this one is a special case format, we sum these parts into seconds for date_add
+ // this one is a special case format, we sum these parts into seconds for datetime_add
"time": {name: "time", params: "(%s %s %s)"},
}
@@ -300,8 +300,8 @@ func newMigrationBaseVars() map[string]interface{} {
"__default__": `now()`,
"now": `now()`,
"today": `today()`,
- "tomorrow": `date_add(today(), 1, "D")`,
- "yesterday": `date_add(today(), -1, "D")`,
+ "tomorrow": `datetime_add(today(), 1, "D")`,
+ "yesterday": `datetime_add(today(), -1, "D")`,
},
},
}
@@ -418,7 +418,7 @@ func migrateLegacyTemplateAsString(resolver types.XValue, template string) (stri
func toString(params interface{}) (string, error) {
switch typed := params.(type) {
case types.XValue:
- str, xerr := types.ToXString(typed)
+ str, xerr := types.ToXText(typed)
return str.Native(), xerr
case string:
return typed, nil
@@ -513,7 +513,7 @@ func (v *legacyVisitor) VisitDecimalLiteral(ctx *gen.DecimalLiteralContext) inte
func (v *legacyVisitor) VisitDotLookup(ctx *gen.DotLookupContext) interface{} {
value := v.Visit(ctx.Atom(0)).(types.XValue)
expression := v.Visit(ctx.Atom(1)).(types.XValue)
- lookup, err := types.ToXString(expression)
+ lookup, err := types.ToXText(expression)
if err != nil {
return err
}
@@ -611,7 +611,7 @@ func (v *legacyVisitor) VisitFalse(ctx *gen.FalseContext) interface{} {
func (v *legacyVisitor) VisitArrayLookup(ctx *gen.ArrayLookupContext) interface{} {
value := v.Visit(ctx.Atom()).(types.XValue)
expression := v.Visit(ctx.Expression()).(types.XValue)
- lookup, err := types.ToXString(expression)
+ lookup, err := types.ToXText(expression)
if err != nil {
return err
}
@@ -727,9 +727,9 @@ func (v *legacyVisitor) VisitAdditionOrSubtraction(ctx *gen.AdditionOrSubtractio
if (firstIsDate || secondIsDate) && (firstNumberErr != nil || secondNumberErr != nil) {
// we are adding two values where we know at least one side is a date
- template := "date_add(%s, %s, \"%s\")"
+ template := "datetime_add(%s, %s, \"%s\")"
if op == "-" {
- template = "date_add(%s, -%s, \"%s\")"
+ template = "datetime_add(%s, -%s, \"%s\")"
}
// determine the order of our parameters
diff --git a/legacy/expressions_test.go b/legacy/expressions_test.go
index 160e3d25b..7c59803c8 100644
--- a/legacy/expressions_test.go
+++ b/legacy/expressions_test.go
@@ -64,8 +64,8 @@ func TestMigrateTemplate(t *testing.T) {
{old: `@date`, new: `@(now())`},
{old: `@date.now`, new: `@(now())`},
{old: `@date.today`, new: `@(today())`},
- {old: `@date.tomorrow`, new: `@(date_add(today(), 1, "D"))`},
- {old: `@date.yesterday`, new: `@(date_add(today(), -1, "D"))`},
+ {old: `@date.tomorrow`, new: `@(datetime_add(today(), 1, "D"))`},
+ {old: `@date.yesterday`, new: `@(datetime_add(today(), -1, "D"))`},
// variables in parens
{old: `@(contact.tel)`, new: `@(format_urn(contact.urns.tel.0))`},
@@ -104,9 +104,9 @@ func TestMigrateTemplate(t *testing.T) {
{old: `@(AVERAGE(1, 2, 3, 4, 5))`, new: `@(mean(1, 2, 3, 4, 5))`},
{old: `@(AND(contact.age > 30, flow.amount < 5))`, new: `@(and(contact.fields.age > 30, run.results.amount < 5))`},
{old: `@(DATEVALUE("2012-02-03"))`, new: `@(date("2012-02-03"))`},
- {old: `@(EDATE("2012-02-03", 1))`, new: `@(date_add("2012-02-03", 1, "M"))`},
- {old: `@(DATEDIF(contact.join_date, date.now, "M"))`, new: `@(date_diff(contact.fields.join_date, now(), "M"))`},
- {old: `@(DAYS("2016-02-28", "2015-02-28"))`, new: `@(date_diff("2016-02-28", "2015-02-28", "D"))`},
+ {old: `@(EDATE("2012-02-03", 1))`, new: `@(datetime_add("2012-02-03", 1, "M"))`},
+ {old: `@(DATEDIF(contact.join_date, date.now, "M"))`, new: `@(datetime_diff(contact.fields.join_date, now(), "M"))`},
+ {old: `@(DAYS("2016-02-28", "2015-02-28"))`, new: `@(datetime_diff("2016-02-28", "2015-02-28", "D"))`},
{old: `@(DAY(contact.join_date))`, new: `@(format_date(contact.fields.join_date, "D"))`},
{old: `@(HOUR(NOW()))`, new: `@(format_date(now(), "h"))`},
{old: `@(MINUTE(NOW()))`, new: `@(format_date(now(), "m"))`},
@@ -114,23 +114,23 @@ func TestMigrateTemplate(t *testing.T) {
{old: `@(NOW())`, new: `@(now())`},
{old: `@(SECOND(NOW()))`, new: `@(format_date(now(), "s"))`},
- // date addition should get converted to date_add
- {old: `@(date.now + 5)`, new: `@(date_add(now(), 5, "D"))`},
- {old: `@(now() + 5)`, new: `@(date_add(now(), 5, "D"))`},
- {old: `@(date + 5)`, new: `@(date_add(now(), 5, "D"))`},
- {old: `@(date.now + 5 + contact.age)`, new: `@(legacy_add(date_add(now(), 5, "D"), contact.fields.age))`},
+ // date addition should get converted to datetime_add
+ {old: `@(date.now + 5)`, new: `@(datetime_add(now(), 5, "D"))`},
+ {old: `@(now() + 5)`, new: `@(datetime_add(now(), 5, "D"))`},
+ {old: `@(date + 5)`, new: `@(datetime_add(now(), 5, "D"))`},
+ {old: `@(date.now + 5 + contact.age)`, new: `@(legacy_add(datetime_add(now(), 5, "D"), contact.fields.age))`},
// legacy_add permutations
{old: `@(contact.age + 5)`, new: `@(legacy_add(contact.fields.age, 5))`},
{old: `@(contact.join_date + 5 + contact.age)`, new: `@(legacy_add(legacy_add(contact.fields.join_date, 5), contact.fields.age))`},
{old: `@(contact.age + 100 - 5)`, new: `@(legacy_add(legacy_add(contact.fields.age, 100), -5))`},
- {old: `@(date.yesterday - 3 + 10)`, new: `@(legacy_add(legacy_add(date_add(today(), -1, "D"), -3), 10))`},
+ {old: `@(date.yesterday - 3 + 10)`, new: `@(legacy_add(legacy_add(datetime_add(today(), -1, "D"), -3), 10))`},
- {old: `@(3 + date.now)`, new: `@(date_add(now(), 3, "D"))`},
- {old: `@(date.tomorrow - 3)`, new: `@(legacy_add(date_add(today(), 1, "D"), -3))`},
- {old: `@(date.now + TIME(2, 30, 0))`, new: `@(date_add(now(), 9000, "s"))`},
- {old: `@(TIME(0, 1, 5) + contact.join_date)`, new: `@(date_add(contact.fields.join_date, 65, "s"))`},
- {old: `@(contact.join_date - TIME(0,0,12))`, new: `@(date_add(contact.fields.join_date, -12, "s"))`},
+ {old: `@(3 + date.now)`, new: `@(datetime_add(now(), 3, "D"))`},
+ {old: `@(date.tomorrow - 3)`, new: `@(legacy_add(datetime_add(today(), 1, "D"), -3))`},
+ {old: `@(date.now + TIME(2, 30, 0))`, new: `@(datetime_add(now(), 9000, "s"))`},
+ {old: `@(TIME(0, 1, 5) + contact.join_date)`, new: `@(datetime_add(contact.fields.join_date, 65, "s"))`},
+ {old: `@(contact.join_date - TIME(0,0,12))`, new: `@(datetime_add(contact.fields.join_date, -12, "s"))`},
// TODO: beware different org format, need a like function
{old: `@(DATE(2012, 12, 25))`, new: `@(date("2012-12-25"))`},
@@ -165,9 +165,9 @@ func TestMigrateTemplate(t *testing.T) {
{old: `@(CODE("A"))`, new: `@(code("A"))`},
{old: `@(CONCATENATE(contact.first_name, " ", contact.language))`, new: `@(contact.first_name & " " & contact.language)`},
- {old: `@(FIXED(contact.age))`, new: `@(format_num(contact.fields.age))`},
- {old: `@(FIXED(contact.age, 2))`, new: `@(format_num(contact.fields.age, 2))`},
- {old: `@(FIXED(contact.age, 2, false))`, new: `@(format_num(contact.fields.age, 2, false))`},
+ {old: `@(FIXED(contact.age))`, new: `@(format_number(contact.fields.age))`},
+ {old: `@(FIXED(contact.age, 2))`, new: `@(format_number(contact.fields.age, 2))`},
+ {old: `@(FIXED(contact.age, 2, false))`, new: `@(format_number(contact.fields.age, 2, false))`},
{old: `@(INT(contact.age))`, new: `@(round_down(contact.fields.age))`},
{old: `@(LEFT(contact.name, 4))`, new: `@(left(contact.name, 4))`},
{old: `@(RIGHT(contact.name, 4))`, new: `@(right(contact.name, 4))`},
@@ -177,7 +177,7 @@ func TestMigrateTemplate(t *testing.T) {
{old: `@(PROPER(contact))`, new: `@(title(contact))`},
{old: `@(REPT("*", 10))`, new: `@(repeat("*", 10))`},
- {old: `@((DATEDIF(DATEVALUE("1970-01-01"), date.now, "D") * 24 * 60 * 60) + ((((HOUR(date.now)+7) * 60) + MINUTE(date.now)) * 60))`, new: `@(legacy_add((date_diff(date("1970-01-01"), now(), "D") * 24 * 60 * 60), ((legacy_add(((legacy_add(format_date(now(), "h"), 7)) * 60), format_date(now(), "m"))) * 60)))`},
+ {old: `@((DATEDIF(DATEVALUE("1970-01-01"), date.now, "D") * 24 * 60 * 60) + ((((HOUR(date.now)+7) * 60) + MINUTE(date.now)) * 60))`, new: `@(legacy_add((datetime_diff(date("1970-01-01"), now(), "D") * 24 * 60 * 60), ((legacy_add(((legacy_add(format_date(now(), "h"), 7)) * 60), format_date(now(), "m"))) * 60)))`},
{old: `@extra.results.0.state`, new: `@run.webhook.json.results.0.state`, extraAs: ExtraAsWebhookJSON},
{old: `@extra.address.state`, new: `@trigger.params.address.state`, extraAs: ExtraAsTriggerParams},
diff --git a/legacy/testdata/migrations/rulesets.json b/legacy/testdata/migrations/rulesets.json
index df8ead100..fa3f056d3 100644
--- a/legacy/testdata/migrations/rulesets.json
+++ b/legacy/testdata/migrations/rulesets.json
@@ -356,19 +356,19 @@
"cases": [
{
"uuid": "������������������������������������",
- "type": "is_string_eq",
+ "type": "is_text_eq",
"arguments": ["success"],
"exit_uuid": "7fab0ddd-3e4d-4541-84df-8470e05ead16"
},
{
"uuid": "������������������������������������",
- "type": "is_string_eq",
+ "type": "is_text_eq",
"arguments": ["response_error"],
"exit_uuid": "f3e4cb68-408f-4435-b337-82826e928875"
},
{
"uuid": "������������������������������������",
- "type": "is_string_eq",
+ "type": "is_text_eq",
"arguments": ["connection_error"],
"exit_uuid": "������������������������������������"
}
@@ -456,13 +456,13 @@
"cases": [
{
"uuid": "������������������������������������",
- "type": "is_string_eq",
+ "type": "is_text_eq",
"arguments": ["completed"],
"exit_uuid": "d53e9ab2-8e88-4ffc-9452-eb819b50bdb2"
},
{
"uuid": "������������������������������������",
- "type": "is_string_eq",
+ "type": "is_text_eq",
"arguments": ["expired"],
"exit_uuid": "279a7adf-4681-4efb-a65f-34369a7a4f42"
}
diff --git a/legacy/testdata/migrations/tests.json b/legacy/testdata/migrations/tests.json
index 71dd769e3..093528fe2 100644
--- a/legacy/testdata/migrations/tests.json
+++ b/legacy/testdata/migrations/tests.json
@@ -348,7 +348,7 @@
},
"expected_case": {
"uuid": "������������������������������������",
- "type": "is_string_eq",
+ "type": "is_text_eq",
"arguments": ["completed"],
"exit_uuid": "c072ecb5-0686-40ea-8ed3-898dc1349783"
},
@@ -361,7 +361,7 @@
},
"expected_case": {
"uuid": "������������������������������������",
- "type": "is_string_eq",
+ "type": "is_text_eq",
"arguments": ["expired"],
"exit_uuid": "c072ecb5-0686-40ea-8ed3-898dc1349783"
},
@@ -388,7 +388,7 @@
},
"expected_case": {
"uuid": "������������������������������������",
- "type": "is_string_eq",
+ "type": "is_text_eq",
"arguments": ["success"],
"exit_uuid": "c072ecb5-0686-40ea-8ed3-898dc1349783"
},
@@ -401,7 +401,7 @@
},
"expected_case": {
"uuid": "������������������������������������",
- "type": "is_string_eq",
+ "type": "is_text_eq",
"arguments": ["response_error"],
"exit_uuid": "c072ecb5-0686-40ea-8ed3-898dc1349783"
},
diff --git a/test/session.go b/test/session.go
index a159b8480..772dcec84 100644
--- a/test/session.go
+++ b/test/session.go
@@ -148,7 +148,7 @@ var sessionAssets = `[
"url": "http://testserver/assets/field",
"content": [
{"key": "gender", "label": "Gender", "value_type": "text"},
- {"key": "age", "label": "Age", "value_type": "decimal"},
+ {"key": "age", "label": "Age", "value_type": "number"},
{"key": "join_date", "label": "Join Date", "value_type": "datetime"},
{"key": "activation_token", "label": "Activation Token", "value_type": "text"}
]
@@ -249,7 +249,7 @@ var sessionTrigger = `{
"urns": [],
"fields": {
"age": {
- "text": "33 years", "decimal": 33
+ "text": "33 years", "number": 33
},
"gender": {
"text": "Female"