funcs_str.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. // Copyright 2022-2023 EMQ Technologies Co., Ltd.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package function
  15. import (
  16. "bytes"
  17. "fmt"
  18. "regexp"
  19. "strings"
  20. "unicode"
  21. "unicode/utf8"
  22. "github.com/lf-edge/ekuiper/pkg/api"
  23. "github.com/lf-edge/ekuiper/pkg/ast"
  24. "github.com/lf-edge/ekuiper/pkg/cast"
  25. )
  26. func registerStrFunc() {
  27. builtins["concat"] = builtinFunc{
  28. fType: ast.FuncTypeScalar,
  29. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  30. var b bytes.Buffer
  31. for _, arg := range args {
  32. b.WriteString(cast.ToStringAlways(arg))
  33. }
  34. return b.String(), true
  35. },
  36. val: func(_ api.FunctionContext, args []ast.Expr) error {
  37. if len(args) == 0 {
  38. return fmt.Errorf("The arguments should be at least one.")
  39. }
  40. for i, a := range args {
  41. if ast.IsNumericArg(a) || ast.IsTimeArg(a) || ast.IsBooleanArg(a) {
  42. return ProduceErrInfo(i, "string")
  43. }
  44. }
  45. return nil
  46. },
  47. }
  48. builtins["endswith"] = builtinFunc{
  49. fType: ast.FuncTypeScalar,
  50. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  51. if args[0] == nil || args[1] == nil {
  52. return false, true
  53. }
  54. arg0, arg1 := cast.ToStringAlways(args[0]), cast.ToStringAlways(args[1])
  55. return strings.HasSuffix(arg0, arg1), true
  56. },
  57. val: ValidateTwoStrArg,
  58. }
  59. builtins["indexof"] = builtinFunc{
  60. fType: ast.FuncTypeScalar,
  61. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  62. if args[0] == nil || args[1] == nil {
  63. return -1, true
  64. }
  65. arg0, arg1 := cast.ToStringAlways(args[0]), cast.ToStringAlways(args[1])
  66. return strings.Index(arg0, arg1), true
  67. },
  68. val: ValidateTwoStrArg,
  69. }
  70. builtins["length"] = builtinFunc{
  71. fType: ast.FuncTypeScalar,
  72. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  73. arg0 := cast.ToStringAlways(args[0])
  74. switch v := args[0].(type) {
  75. case []interface{}:
  76. return len(v), true
  77. case map[string]interface{}:
  78. return len(v), true
  79. default:
  80. }
  81. return utf8.RuneCountInString(arg0), true
  82. },
  83. val: ValidateOneArg,
  84. }
  85. builtins["lower"] = builtinFunc{
  86. fType: ast.FuncTypeScalar,
  87. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  88. if args[0] == nil {
  89. return nil, true
  90. }
  91. arg0 := cast.ToStringAlways(args[0])
  92. return strings.ToLower(arg0), true
  93. },
  94. val: ValidateOneStrArg,
  95. }
  96. builtins["lpad"] = builtinFunc{
  97. fType: ast.FuncTypeScalar,
  98. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  99. if args[0] == nil {
  100. return nil, true
  101. }
  102. arg0 := cast.ToStringAlways(args[0])
  103. arg1, err := cast.ToInt(args[1], cast.STRICT)
  104. if err != nil {
  105. return err, false
  106. }
  107. return strings.Repeat(" ", arg1) + arg0, true
  108. },
  109. val: ValidateOneStrOneInt,
  110. }
  111. builtins["ltrim"] = builtinFunc{
  112. fType: ast.FuncTypeScalar,
  113. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  114. if args[0] == nil {
  115. return nil, true
  116. }
  117. arg0 := cast.ToStringAlways(args[0])
  118. return strings.TrimLeftFunc(arg0, unicode.IsSpace), true
  119. },
  120. val: ValidateOneStrArg,
  121. }
  122. builtins["numbytes"] = builtinFunc{
  123. fType: ast.FuncTypeScalar,
  124. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  125. arg0 := cast.ToStringAlways(args[0])
  126. return len(arg0), true
  127. },
  128. val: ValidateOneStrArg,
  129. }
  130. builtins["format_time"] = builtinFunc{
  131. fType: ast.FuncTypeScalar,
  132. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  133. if args[0] == nil {
  134. return nil, true
  135. }
  136. arg0, err := cast.InterfaceToTime(args[0], "")
  137. if err != nil {
  138. return err, false
  139. }
  140. arg1 := cast.ToStringAlways(args[1])
  141. if s, err := cast.FormatTime(arg0, arg1); err == nil {
  142. return s, true
  143. } else {
  144. return err, false
  145. }
  146. },
  147. val: func(_ api.FunctionContext, args []ast.Expr) error {
  148. if err := ValidateLen(2, len(args)); err != nil {
  149. return err
  150. }
  151. if ast.IsNumericArg(args[0]) || ast.IsStringArg(args[0]) || ast.IsBooleanArg(args[0]) {
  152. return ProduceErrInfo(0, "datetime")
  153. }
  154. if ast.IsNumericArg(args[1]) || ast.IsTimeArg(args[1]) || ast.IsBooleanArg(args[1]) {
  155. return ProduceErrInfo(1, "string")
  156. }
  157. return nil
  158. },
  159. }
  160. builtins["regexp_matches"] = builtinFunc{
  161. fType: ast.FuncTypeScalar,
  162. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  163. if args[0] == nil || args[1] == nil {
  164. return false, true
  165. }
  166. arg0, arg1 := cast.ToStringAlways(args[0]), cast.ToStringAlways(args[1])
  167. if matched, err := regexp.MatchString(arg1, arg0); err != nil {
  168. return err, false
  169. } else {
  170. return matched, true
  171. }
  172. },
  173. val: ValidateTwoStrArg,
  174. }
  175. builtins["regexp_replace"] = builtinFunc{
  176. fType: ast.FuncTypeScalar,
  177. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  178. if args[0] == nil || args[1] == nil || args[2] == nil {
  179. return nil, true
  180. }
  181. arg0, arg1, arg2 := cast.ToStringAlways(args[0]), cast.ToStringAlways(args[1]), cast.ToStringAlways(args[2])
  182. if re, err := regexp.Compile(arg1); err != nil {
  183. return err, false
  184. } else {
  185. return re.ReplaceAllString(arg0, arg2), true
  186. }
  187. },
  188. val: func(_ api.FunctionContext, args []ast.Expr) error {
  189. if err := ValidateLen(3, len(args)); err != nil {
  190. return err
  191. }
  192. for i := 0; i < 3; i++ {
  193. if ast.IsNumericArg(args[i]) || ast.IsTimeArg(args[i]) || ast.IsBooleanArg(args[i]) {
  194. return ProduceErrInfo(i, "string")
  195. }
  196. }
  197. return nil
  198. },
  199. }
  200. builtins["regexp_substr"] = builtinFunc{
  201. fType: ast.FuncTypeScalar,
  202. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  203. if args[0] == nil || args[1] == nil {
  204. return nil, true
  205. }
  206. arg0, arg1 := cast.ToStringAlways(args[0]), cast.ToStringAlways(args[1])
  207. if re, err := regexp.Compile(arg1); err != nil {
  208. return err, false
  209. } else {
  210. return re.FindString(arg0), true
  211. }
  212. },
  213. val: ValidateTwoStrArg,
  214. }
  215. builtins["rpad"] = builtinFunc{
  216. fType: ast.FuncTypeScalar,
  217. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  218. if args[0] == nil {
  219. return nil, true
  220. }
  221. arg0 := cast.ToStringAlways(args[0])
  222. arg1, err := cast.ToInt(args[1], cast.STRICT)
  223. if err != nil {
  224. return err, false
  225. }
  226. return arg0 + strings.Repeat(" ", arg1), true
  227. },
  228. val: ValidateOneStrOneInt,
  229. }
  230. builtins["rtrim"] = builtinFunc{
  231. fType: ast.FuncTypeScalar,
  232. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  233. if args[0] == nil {
  234. return nil, true
  235. }
  236. arg0 := cast.ToStringAlways(args[0])
  237. return strings.TrimRightFunc(arg0, unicode.IsSpace), true
  238. },
  239. val: ValidateOneStrArg,
  240. }
  241. builtins["substring"] = builtinFunc{
  242. fType: ast.FuncTypeScalar,
  243. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  244. if args[0] == nil {
  245. return nil, true
  246. }
  247. arg0 := cast.ToStringAlways(args[0])
  248. arg1, err := cast.ToInt(args[1], cast.STRICT)
  249. if err != nil {
  250. return err, false
  251. }
  252. if arg1 < 0 {
  253. return fmt.Errorf("start index must be a positive number"), false
  254. }
  255. if len(args) > 2 {
  256. arg2, err := cast.ToInt(args[2], cast.STRICT)
  257. if err != nil {
  258. return err, false
  259. }
  260. if arg2 < 0 {
  261. return fmt.Errorf("end index must be a positive number"), false
  262. }
  263. if arg1 > arg2 {
  264. return fmt.Errorf("start index must be smaller than end index"), false
  265. }
  266. if arg1 > len(arg0) {
  267. return "", true
  268. }
  269. if arg2 > len(arg0) {
  270. return arg0[arg1:], true
  271. }
  272. return arg0[arg1:arg2], true
  273. } else {
  274. if arg1 > len(arg0) {
  275. return "", true
  276. }
  277. return arg0[arg1:], true
  278. }
  279. },
  280. val: func(_ api.FunctionContext, args []ast.Expr) error {
  281. l := len(args)
  282. if l != 2 && l != 3 {
  283. return fmt.Errorf("the arguments for substring should be 2 or 3")
  284. }
  285. if ast.IsNumericArg(args[0]) || ast.IsTimeArg(args[0]) || ast.IsBooleanArg(args[0]) {
  286. return ProduceErrInfo(0, "string")
  287. }
  288. for i := 1; i < l; i++ {
  289. if ast.IsFloatArg(args[i]) || ast.IsTimeArg(args[i]) || ast.IsBooleanArg(args[i]) || ast.IsStringArg(args[i]) {
  290. return ProduceErrInfo(i, "int")
  291. }
  292. }
  293. if s, ok := args[1].(*ast.IntegerLiteral); ok {
  294. sv := s.Val
  295. if sv < 0 {
  296. return fmt.Errorf("The start index should not be a nagtive integer.")
  297. }
  298. if l == 3 {
  299. if e, ok1 := args[2].(*ast.IntegerLiteral); ok1 {
  300. ev := e.Val
  301. if ev < sv {
  302. return fmt.Errorf("The end index should be larger than start index.")
  303. }
  304. }
  305. }
  306. }
  307. return nil
  308. },
  309. }
  310. builtins["startswith"] = builtinFunc{
  311. fType: ast.FuncTypeScalar,
  312. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  313. if args[0] == nil {
  314. return false, true
  315. }
  316. arg0, arg1 := cast.ToStringAlways(args[0]), cast.ToStringAlways(args[1])
  317. return strings.HasPrefix(arg0, arg1), true
  318. },
  319. val: ValidateTwoStrArg,
  320. }
  321. builtins["split_value"] = builtinFunc{
  322. fType: ast.FuncTypeScalar,
  323. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  324. if args[0] == nil || args[1] == nil {
  325. return nil, true
  326. }
  327. arg0, arg1 := cast.ToStringAlways(args[0]), cast.ToStringAlways(args[1])
  328. ss := strings.Split(arg0, arg1)
  329. v, _ := cast.ToInt(args[2], cast.STRICT)
  330. if v > (len(ss) - 1) {
  331. return fmt.Errorf("%d out of index array (size = %d)", v, len(ss)), false
  332. } else {
  333. return ss[v], true
  334. }
  335. },
  336. val: func(_ api.FunctionContext, args []ast.Expr) error {
  337. l := len(args)
  338. if l != 3 {
  339. return fmt.Errorf("the arguments for split_value should be 3")
  340. }
  341. if ast.IsNumericArg(args[0]) || ast.IsTimeArg(args[0]) || ast.IsBooleanArg(args[0]) {
  342. return ProduceErrInfo(0, "string")
  343. }
  344. if ast.IsNumericArg(args[1]) || ast.IsTimeArg(args[1]) || ast.IsBooleanArg(args[1]) {
  345. return ProduceErrInfo(1, "string")
  346. }
  347. if ast.IsFloatArg(args[2]) || ast.IsTimeArg(args[2]) || ast.IsBooleanArg(args[2]) || ast.IsStringArg(args[2]) {
  348. return ProduceErrInfo(2, "int")
  349. }
  350. if s, ok := args[2].(*ast.IntegerLiteral); ok {
  351. if s.Val < 0 {
  352. return fmt.Errorf("The index should not be a nagtive integer.")
  353. }
  354. }
  355. return nil
  356. },
  357. }
  358. builtins["trim"] = builtinFunc{
  359. fType: ast.FuncTypeScalar,
  360. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  361. if args[0] == nil {
  362. return nil, true
  363. }
  364. arg0 := cast.ToStringAlways(args[0])
  365. return strings.TrimSpace(arg0), true
  366. },
  367. val: ValidateOneStrArg,
  368. }
  369. builtins["upper"] = builtinFunc{
  370. fType: ast.FuncTypeScalar,
  371. exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
  372. if args[0] == nil {
  373. return nil, true
  374. }
  375. arg0 := cast.ToStringAlways(args[0])
  376. return strings.ToUpper(arg0), true
  377. },
  378. val: ValidateOneStrArg,
  379. }
  380. }