You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

826 regels
24 KiB

  1. package redis
  2. import (
  3. "context"
  4. )
  5. // ----------------------
  6. // Search Module Builders
  7. // ----------------------
  8. // SearchBuilder provides a fluent API for FT.SEARCH
  9. // (see original FTSearchOptions for all options).
  10. // EXPERIMENTAL: this API is subject to change, use with caution.
  11. type SearchBuilder struct {
  12. c *Client
  13. ctx context.Context
  14. index string
  15. query string
  16. options *FTSearchOptions
  17. }
  18. // NewSearchBuilder creates a new SearchBuilder for FT.SEARCH commands.
  19. // EXPERIMENTAL: this API is subject to change, use with caution.
  20. func (c *Client) NewSearchBuilder(ctx context.Context, index, query string) *SearchBuilder {
  21. b := &SearchBuilder{c: c, ctx: ctx, index: index, query: query, options: &FTSearchOptions{LimitOffset: -1}}
  22. return b
  23. }
  24. // WithScores includes WITHSCORES.
  25. func (b *SearchBuilder) WithScores() *SearchBuilder {
  26. b.options.WithScores = true
  27. return b
  28. }
  29. // NoContent includes NOCONTENT.
  30. func (b *SearchBuilder) NoContent() *SearchBuilder { b.options.NoContent = true; return b }
  31. // Verbatim includes VERBATIM.
  32. func (b *SearchBuilder) Verbatim() *SearchBuilder { b.options.Verbatim = true; return b }
  33. // NoStopWords includes NOSTOPWORDS.
  34. func (b *SearchBuilder) NoStopWords() *SearchBuilder { b.options.NoStopWords = true; return b }
  35. // WithPayloads includes WITHPAYLOADS.
  36. func (b *SearchBuilder) WithPayloads() *SearchBuilder {
  37. b.options.WithPayloads = true
  38. return b
  39. }
  40. // WithSortKeys includes WITHSORTKEYS.
  41. func (b *SearchBuilder) WithSortKeys() *SearchBuilder {
  42. b.options.WithSortKeys = true
  43. return b
  44. }
  45. // Filter adds a FILTER clause: FILTER <field> <min> <max>.
  46. func (b *SearchBuilder) Filter(field string, min, max interface{}) *SearchBuilder {
  47. b.options.Filters = append(b.options.Filters, FTSearchFilter{
  48. FieldName: field,
  49. Min: min,
  50. Max: max,
  51. })
  52. return b
  53. }
  54. // GeoFilter adds a GEOFILTER clause: GEOFILTER <field> <lon> <lat> <radius> <unit>.
  55. func (b *SearchBuilder) GeoFilter(field string, lon, lat, radius float64, unit string) *SearchBuilder {
  56. b.options.GeoFilter = append(b.options.GeoFilter, FTSearchGeoFilter{
  57. FieldName: field,
  58. Longitude: lon,
  59. Latitude: lat,
  60. Radius: radius,
  61. Unit: unit,
  62. })
  63. return b
  64. }
  65. // InKeys restricts the search to the given keys.
  66. func (b *SearchBuilder) InKeys(keys ...interface{}) *SearchBuilder {
  67. b.options.InKeys = append(b.options.InKeys, keys...)
  68. return b
  69. }
  70. // InFields restricts the search to the given fields.
  71. func (b *SearchBuilder) InFields(fields ...interface{}) *SearchBuilder {
  72. b.options.InFields = append(b.options.InFields, fields...)
  73. return b
  74. }
  75. // ReturnFields adds simple RETURN <n> <field>...
  76. func (b *SearchBuilder) ReturnFields(fields ...string) *SearchBuilder {
  77. for _, f := range fields {
  78. b.options.Return = append(b.options.Return, FTSearchReturn{FieldName: f})
  79. }
  80. return b
  81. }
  82. // ReturnAs adds RETURN <field> AS <alias>.
  83. func (b *SearchBuilder) ReturnAs(field, alias string) *SearchBuilder {
  84. b.options.Return = append(b.options.Return, FTSearchReturn{FieldName: field, As: alias})
  85. return b
  86. }
  87. // Slop adds SLOP <n>.
  88. func (b *SearchBuilder) Slop(slop int) *SearchBuilder {
  89. b.options.Slop = slop
  90. return b
  91. }
  92. // Timeout adds TIMEOUT <ms>.
  93. func (b *SearchBuilder) Timeout(timeout int) *SearchBuilder {
  94. b.options.Timeout = timeout
  95. return b
  96. }
  97. // InOrder includes INORDER.
  98. func (b *SearchBuilder) InOrder() *SearchBuilder {
  99. b.options.InOrder = true
  100. return b
  101. }
  102. // Language sets LANGUAGE <lang>.
  103. func (b *SearchBuilder) Language(lang string) *SearchBuilder {
  104. b.options.Language = lang
  105. return b
  106. }
  107. // Expander sets EXPANDER <expander>.
  108. func (b *SearchBuilder) Expander(expander string) *SearchBuilder {
  109. b.options.Expander = expander
  110. return b
  111. }
  112. // Scorer sets SCORER <scorer>.
  113. func (b *SearchBuilder) Scorer(scorer string) *SearchBuilder {
  114. b.options.Scorer = scorer
  115. return b
  116. }
  117. // ExplainScore includes EXPLAINSCORE.
  118. func (b *SearchBuilder) ExplainScore() *SearchBuilder {
  119. b.options.ExplainScore = true
  120. return b
  121. }
  122. // Payload sets PAYLOAD <payload>.
  123. func (b *SearchBuilder) Payload(payload string) *SearchBuilder {
  124. b.options.Payload = payload
  125. return b
  126. }
  127. // SortBy adds SORTBY <field> ASC|DESC.
  128. func (b *SearchBuilder) SortBy(field string, asc bool) *SearchBuilder {
  129. b.options.SortBy = append(b.options.SortBy, FTSearchSortBy{
  130. FieldName: field,
  131. Asc: asc,
  132. Desc: !asc,
  133. })
  134. return b
  135. }
  136. // WithSortByCount includes WITHCOUNT (when used with SortBy).
  137. func (b *SearchBuilder) WithSortByCount() *SearchBuilder {
  138. b.options.SortByWithCount = true
  139. return b
  140. }
  141. // Param adds a single PARAMS <k> <v>.
  142. func (b *SearchBuilder) Param(key string, value interface{}) *SearchBuilder {
  143. if b.options.Params == nil {
  144. b.options.Params = make(map[string]interface{}, 1)
  145. }
  146. b.options.Params[key] = value
  147. return b
  148. }
  149. // ParamsMap adds multiple PARAMS at once.
  150. func (b *SearchBuilder) ParamsMap(p map[string]interface{}) *SearchBuilder {
  151. if b.options.Params == nil {
  152. b.options.Params = make(map[string]interface{}, len(p))
  153. }
  154. for k, v := range p {
  155. b.options.Params[k] = v
  156. }
  157. return b
  158. }
  159. // Dialect sets DIALECT <version>.
  160. func (b *SearchBuilder) Dialect(version int) *SearchBuilder {
  161. b.options.DialectVersion = version
  162. return b
  163. }
  164. // Limit sets OFFSET and COUNT. CountOnly uses LIMIT 0 0.
  165. func (b *SearchBuilder) Limit(offset, count int) *SearchBuilder {
  166. b.options.LimitOffset = offset
  167. b.options.Limit = count
  168. return b
  169. }
  170. func (b *SearchBuilder) CountOnly() *SearchBuilder { b.options.CountOnly = true; return b }
  171. // Run executes FT.SEARCH and returns a typed result.
  172. func (b *SearchBuilder) Run() (FTSearchResult, error) {
  173. cmd := b.c.FTSearchWithArgs(b.ctx, b.index, b.query, b.options)
  174. return cmd.Result()
  175. }
  176. // ----------------------
  177. // AggregateBuilder for FT.AGGREGATE
  178. // ----------------------
  179. type AggregateBuilder struct {
  180. c *Client
  181. ctx context.Context
  182. index string
  183. query string
  184. options *FTAggregateOptions
  185. }
  186. // NewAggregateBuilder creates a new AggregateBuilder for FT.AGGREGATE commands.
  187. // EXPERIMENTAL: this API is subject to change, use with caution.
  188. func (c *Client) NewAggregateBuilder(ctx context.Context, index, query string) *AggregateBuilder {
  189. return &AggregateBuilder{c: c, ctx: ctx, index: index, query: query, options: &FTAggregateOptions{LimitOffset: -1}}
  190. }
  191. // Verbatim includes VERBATIM.
  192. func (b *AggregateBuilder) Verbatim() *AggregateBuilder { b.options.Verbatim = true; return b }
  193. // AddScores includes ADDSCORES.
  194. func (b *AggregateBuilder) AddScores() *AggregateBuilder { b.options.AddScores = true; return b }
  195. // Scorer sets SCORER <scorer>.
  196. func (b *AggregateBuilder) Scorer(s string) *AggregateBuilder {
  197. b.options.Scorer = s
  198. return b
  199. }
  200. // LoadAll includes LOAD * (mutually exclusive with Load).
  201. func (b *AggregateBuilder) LoadAll() *AggregateBuilder {
  202. b.options.LoadAll = true
  203. return b
  204. }
  205. // Load adds LOAD <n> <field> [AS alias]...
  206. // You can call it multiple times for multiple fields.
  207. func (b *AggregateBuilder) Load(field string, alias ...string) *AggregateBuilder {
  208. // each Load entry becomes one element in options.Load
  209. l := FTAggregateLoad{Field: field}
  210. if len(alias) > 0 {
  211. l.As = alias[0]
  212. }
  213. b.options.Load = append(b.options.Load, l)
  214. return b
  215. }
  216. // Timeout sets TIMEOUT <ms>.
  217. func (b *AggregateBuilder) Timeout(ms int) *AggregateBuilder {
  218. b.options.Timeout = ms
  219. return b
  220. }
  221. // Apply adds APPLY <field> [AS alias].
  222. func (b *AggregateBuilder) Apply(field string, alias ...string) *AggregateBuilder {
  223. a := FTAggregateApply{Field: field}
  224. if len(alias) > 0 {
  225. a.As = alias[0]
  226. }
  227. b.options.Apply = append(b.options.Apply, a)
  228. return b
  229. }
  230. // GroupBy starts a new GROUPBY <fields...> clause.
  231. func (b *AggregateBuilder) GroupBy(fields ...interface{}) *AggregateBuilder {
  232. b.options.GroupBy = append(b.options.GroupBy, FTAggregateGroupBy{
  233. Fields: fields,
  234. })
  235. return b
  236. }
  237. // Reduce adds a REDUCE <fn> [<#args> <args...>] clause to the *last* GROUPBY.
  238. func (b *AggregateBuilder) Reduce(fn SearchAggregator, args ...interface{}) *AggregateBuilder {
  239. if len(b.options.GroupBy) == 0 {
  240. // no GROUPBY yet — nothing to attach to
  241. return b
  242. }
  243. idx := len(b.options.GroupBy) - 1
  244. b.options.GroupBy[idx].Reduce = append(b.options.GroupBy[idx].Reduce, FTAggregateReducer{
  245. Reducer: fn,
  246. Args: args,
  247. })
  248. return b
  249. }
  250. // ReduceAs does the same but also sets an alias: REDUCE <fn> … AS <alias>
  251. func (b *AggregateBuilder) ReduceAs(fn SearchAggregator, alias string, args ...interface{}) *AggregateBuilder {
  252. if len(b.options.GroupBy) == 0 {
  253. return b
  254. }
  255. idx := len(b.options.GroupBy) - 1
  256. b.options.GroupBy[idx].Reduce = append(b.options.GroupBy[idx].Reduce, FTAggregateReducer{
  257. Reducer: fn,
  258. Args: args,
  259. As: alias,
  260. })
  261. return b
  262. }
  263. // SortBy adds SORTBY <field> ASC|DESC.
  264. func (b *AggregateBuilder) SortBy(field string, asc bool) *AggregateBuilder {
  265. sb := FTAggregateSortBy{FieldName: field, Asc: asc, Desc: !asc}
  266. b.options.SortBy = append(b.options.SortBy, sb)
  267. return b
  268. }
  269. // SortByMax sets MAX <n> (only if SortBy was called).
  270. func (b *AggregateBuilder) SortByMax(max int) *AggregateBuilder {
  271. b.options.SortByMax = max
  272. return b
  273. }
  274. // Filter sets FILTER <expr>.
  275. func (b *AggregateBuilder) Filter(expr string) *AggregateBuilder {
  276. b.options.Filter = expr
  277. return b
  278. }
  279. // WithCursor enables WITHCURSOR [COUNT <n>] [MAXIDLE <ms>].
  280. func (b *AggregateBuilder) WithCursor(count, maxIdle int) *AggregateBuilder {
  281. b.options.WithCursor = true
  282. if b.options.WithCursorOptions == nil {
  283. b.options.WithCursorOptions = &FTAggregateWithCursor{}
  284. }
  285. b.options.WithCursorOptions.Count = count
  286. b.options.WithCursorOptions.MaxIdle = maxIdle
  287. return b
  288. }
  289. // Params adds PARAMS <k v> pairs.
  290. func (b *AggregateBuilder) Params(p map[string]interface{}) *AggregateBuilder {
  291. if b.options.Params == nil {
  292. b.options.Params = make(map[string]interface{}, len(p))
  293. }
  294. for k, v := range p {
  295. b.options.Params[k] = v
  296. }
  297. return b
  298. }
  299. // Dialect sets DIALECT <version>.
  300. func (b *AggregateBuilder) Dialect(version int) *AggregateBuilder {
  301. b.options.DialectVersion = version
  302. return b
  303. }
  304. // Run executes FT.AGGREGATE and returns a typed result.
  305. func (b *AggregateBuilder) Run() (*FTAggregateResult, error) {
  306. cmd := b.c.FTAggregateWithArgs(b.ctx, b.index, b.query, b.options)
  307. return cmd.Result()
  308. }
  309. // ----------------------
  310. // CreateIndexBuilder for FT.CREATE
  311. // ----------------------
  312. // CreateIndexBuilder is builder for FT.CREATE
  313. // EXPERIMENTAL: this API is subject to change, use with caution.
  314. type CreateIndexBuilder struct {
  315. c *Client
  316. ctx context.Context
  317. index string
  318. options *FTCreateOptions
  319. schema []*FieldSchema
  320. }
  321. // NewCreateIndexBuilder creates a new CreateIndexBuilder for FT.CREATE commands.
  322. // EXPERIMENTAL: this API is subject to change, use with caution.
  323. func (c *Client) NewCreateIndexBuilder(ctx context.Context, index string) *CreateIndexBuilder {
  324. return &CreateIndexBuilder{c: c, ctx: ctx, index: index, options: &FTCreateOptions{}}
  325. }
  326. // OnHash sets ON HASH.
  327. func (b *CreateIndexBuilder) OnHash() *CreateIndexBuilder { b.options.OnHash = true; return b }
  328. // OnJSON sets ON JSON.
  329. func (b *CreateIndexBuilder) OnJSON() *CreateIndexBuilder { b.options.OnJSON = true; return b }
  330. // Prefix sets PREFIX.
  331. func (b *CreateIndexBuilder) Prefix(prefixes ...interface{}) *CreateIndexBuilder {
  332. b.options.Prefix = prefixes
  333. return b
  334. }
  335. // Filter sets FILTER.
  336. func (b *CreateIndexBuilder) Filter(filter string) *CreateIndexBuilder {
  337. b.options.Filter = filter
  338. return b
  339. }
  340. // DefaultLanguage sets LANGUAGE.
  341. func (b *CreateIndexBuilder) DefaultLanguage(lang string) *CreateIndexBuilder {
  342. b.options.DefaultLanguage = lang
  343. return b
  344. }
  345. // LanguageField sets LANGUAGE_FIELD.
  346. func (b *CreateIndexBuilder) LanguageField(field string) *CreateIndexBuilder {
  347. b.options.LanguageField = field
  348. return b
  349. }
  350. // Score sets SCORE.
  351. func (b *CreateIndexBuilder) Score(score float64) *CreateIndexBuilder {
  352. b.options.Score = score
  353. return b
  354. }
  355. // ScoreField sets SCORE_FIELD.
  356. func (b *CreateIndexBuilder) ScoreField(field string) *CreateIndexBuilder {
  357. b.options.ScoreField = field
  358. return b
  359. }
  360. // PayloadField sets PAYLOAD_FIELD.
  361. func (b *CreateIndexBuilder) PayloadField(field string) *CreateIndexBuilder {
  362. b.options.PayloadField = field
  363. return b
  364. }
  365. // NoOffsets includes NOOFFSETS.
  366. func (b *CreateIndexBuilder) NoOffsets() *CreateIndexBuilder { b.options.NoOffsets = true; return b }
  367. // Temporary sets TEMPORARY seconds.
  368. func (b *CreateIndexBuilder) Temporary(sec int) *CreateIndexBuilder {
  369. b.options.Temporary = sec
  370. return b
  371. }
  372. // NoHL includes NOHL.
  373. func (b *CreateIndexBuilder) NoHL() *CreateIndexBuilder { b.options.NoHL = true; return b }
  374. // NoFields includes NOFIELDS.
  375. func (b *CreateIndexBuilder) NoFields() *CreateIndexBuilder { b.options.NoFields = true; return b }
  376. // NoFreqs includes NOFREQS.
  377. func (b *CreateIndexBuilder) NoFreqs() *CreateIndexBuilder { b.options.NoFreqs = true; return b }
  378. // StopWords sets STOPWORDS.
  379. func (b *CreateIndexBuilder) StopWords(words ...interface{}) *CreateIndexBuilder {
  380. b.options.StopWords = words
  381. return b
  382. }
  383. // SkipInitialScan includes SKIPINITIALSCAN.
  384. func (b *CreateIndexBuilder) SkipInitialScan() *CreateIndexBuilder {
  385. b.options.SkipInitialScan = true
  386. return b
  387. }
  388. // Schema adds a FieldSchema.
  389. func (b *CreateIndexBuilder) Schema(field *FieldSchema) *CreateIndexBuilder {
  390. b.schema = append(b.schema, field)
  391. return b
  392. }
  393. // Run executes FT.CREATE and returns the status.
  394. func (b *CreateIndexBuilder) Run() (string, error) {
  395. cmd := b.c.FTCreate(b.ctx, b.index, b.options, b.schema...)
  396. return cmd.Result()
  397. }
  398. // ----------------------
  399. // DropIndexBuilder for FT.DROPINDEX
  400. // ----------------------
  401. // DropIndexBuilder is a builder for FT.DROPINDEX
  402. // EXPERIMENTAL: this API is subject to change, use with caution.
  403. type DropIndexBuilder struct {
  404. c *Client
  405. ctx context.Context
  406. index string
  407. options *FTDropIndexOptions
  408. }
  409. // NewDropIndexBuilder creates a new DropIndexBuilder for FT.DROPINDEX commands.
  410. // EXPERIMENTAL: this API is subject to change, use with caution.
  411. func (c *Client) NewDropIndexBuilder(ctx context.Context, index string) *DropIndexBuilder {
  412. return &DropIndexBuilder{c: c, ctx: ctx, index: index}
  413. }
  414. // DeleteRuncs includes DD.
  415. func (b *DropIndexBuilder) DeleteDocs() *DropIndexBuilder { b.options.DeleteDocs = true; return b }
  416. // Run executes FT.DROPINDEX.
  417. func (b *DropIndexBuilder) Run() (string, error) {
  418. cmd := b.c.FTDropIndexWithArgs(b.ctx, b.index, b.options)
  419. return cmd.Result()
  420. }
  421. // ----------------------
  422. // AliasBuilder for FT.ALIAS* commands
  423. // ----------------------
  424. // AliasBuilder is builder for FT.ALIAS* commands
  425. // EXPERIMENTAL: this API is subject to change, use with caution.
  426. type AliasBuilder struct {
  427. c *Client
  428. ctx context.Context
  429. alias string
  430. index string
  431. action string // add|del|update
  432. }
  433. // NewAliasBuilder creates a new AliasBuilder for FT.ALIAS* commands.
  434. // EXPERIMENTAL: this API is subject to change, use with caution.
  435. func (c *Client) NewAliasBuilder(ctx context.Context, alias string) *AliasBuilder {
  436. return &AliasBuilder{c: c, ctx: ctx, alias: alias}
  437. }
  438. // Action sets the action for the alias builder.
  439. func (b *AliasBuilder) Action(action string) *AliasBuilder {
  440. b.action = action
  441. return b
  442. }
  443. // Add sets the action to "add" and requires an index.
  444. func (b *AliasBuilder) Add(index string) *AliasBuilder {
  445. b.action = "add"
  446. b.index = index
  447. return b
  448. }
  449. // Del sets the action to "del".
  450. func (b *AliasBuilder) Del() *AliasBuilder {
  451. b.action = "del"
  452. return b
  453. }
  454. // Update sets the action to "update" and requires an index.
  455. func (b *AliasBuilder) Update(index string) *AliasBuilder {
  456. b.action = "update"
  457. b.index = index
  458. return b
  459. }
  460. // Run executes the configured alias command.
  461. func (b *AliasBuilder) Run() (string, error) {
  462. switch b.action {
  463. case "add":
  464. cmd := b.c.FTAliasAdd(b.ctx, b.index, b.alias)
  465. return cmd.Result()
  466. case "del":
  467. cmd := b.c.FTAliasDel(b.ctx, b.alias)
  468. return cmd.Result()
  469. case "update":
  470. cmd := b.c.FTAliasUpdate(b.ctx, b.index, b.alias)
  471. return cmd.Result()
  472. }
  473. return "", nil
  474. }
  475. // ----------------------
  476. // ExplainBuilder for FT.EXPLAIN
  477. // ----------------------
  478. // ExplainBuilder is builder for FT.EXPLAIN
  479. // EXPERIMENTAL: this API is subject to change, use with caution.
  480. type ExplainBuilder struct {
  481. c *Client
  482. ctx context.Context
  483. index string
  484. query string
  485. options *FTExplainOptions
  486. }
  487. // NewExplainBuilder creates a new ExplainBuilder for FT.EXPLAIN commands.
  488. // EXPERIMENTAL: this API is subject to change, use with caution.
  489. func (c *Client) NewExplainBuilder(ctx context.Context, index, query string) *ExplainBuilder {
  490. return &ExplainBuilder{c: c, ctx: ctx, index: index, query: query, options: &FTExplainOptions{}}
  491. }
  492. // Dialect sets dialect for EXPLAINCLI.
  493. func (b *ExplainBuilder) Dialect(d string) *ExplainBuilder { b.options.Dialect = d; return b }
  494. // Run executes FT.EXPLAIN and returns the plan.
  495. func (b *ExplainBuilder) Run() (string, error) {
  496. cmd := b.c.FTExplainWithArgs(b.ctx, b.index, b.query, b.options)
  497. return cmd.Result()
  498. }
  499. // ----------------------
  500. // InfoBuilder for FT.INFO
  501. // ----------------------
  502. type FTInfoBuilder struct {
  503. c *Client
  504. ctx context.Context
  505. index string
  506. }
  507. // NewSearchInfoBuilder creates a new FTInfoBuilder for FT.INFO commands.
  508. func (c *Client) NewSearchInfoBuilder(ctx context.Context, index string) *FTInfoBuilder {
  509. return &FTInfoBuilder{c: c, ctx: ctx, index: index}
  510. }
  511. // Run executes FT.INFO and returns detailed info.
  512. func (b *FTInfoBuilder) Run() (FTInfoResult, error) {
  513. cmd := b.c.FTInfo(b.ctx, b.index)
  514. return cmd.Result()
  515. }
  516. // ----------------------
  517. // SpellCheckBuilder for FT.SPELLCHECK
  518. // ----------------------
  519. // SpellCheckBuilder is builder for FT.SPELLCHECK
  520. // EXPERIMENTAL: this API is subject to change, use with caution.
  521. type SpellCheckBuilder struct {
  522. c *Client
  523. ctx context.Context
  524. index string
  525. query string
  526. options *FTSpellCheckOptions
  527. }
  528. // NewSpellCheckBuilder creates a new SpellCheckBuilder for FT.SPELLCHECK commands.
  529. // EXPERIMENTAL: this API is subject to change, use with caution.
  530. func (c *Client) NewSpellCheckBuilder(ctx context.Context, index, query string) *SpellCheckBuilder {
  531. return &SpellCheckBuilder{c: c, ctx: ctx, index: index, query: query, options: &FTSpellCheckOptions{}}
  532. }
  533. // Distance sets MAXDISTANCE.
  534. func (b *SpellCheckBuilder) Distance(d int) *SpellCheckBuilder { b.options.Distance = d; return b }
  535. // Terms sets INCLUDE or EXCLUDE terms.
  536. func (b *SpellCheckBuilder) Terms(include bool, dictionary string, terms ...interface{}) *SpellCheckBuilder {
  537. if b.options.Terms == nil {
  538. b.options.Terms = &FTSpellCheckTerms{}
  539. }
  540. if include {
  541. b.options.Terms.Inclusion = "INCLUDE"
  542. } else {
  543. b.options.Terms.Inclusion = "EXCLUDE"
  544. }
  545. b.options.Terms.Dictionary = dictionary
  546. b.options.Terms.Terms = terms
  547. return b
  548. }
  549. // Dialect sets dialect version.
  550. func (b *SpellCheckBuilder) Dialect(d int) *SpellCheckBuilder { b.options.Dialect = d; return b }
  551. // Run executes FT.SPELLCHECK and returns suggestions.
  552. func (b *SpellCheckBuilder) Run() ([]SpellCheckResult, error) {
  553. cmd := b.c.FTSpellCheckWithArgs(b.ctx, b.index, b.query, b.options)
  554. return cmd.Result()
  555. }
  556. // ----------------------
  557. // DictBuilder for FT.DICT* commands
  558. // ----------------------
  559. // DictBuilder is builder for FT.DICT* commands
  560. // EXPERIMENTAL: this API is subject to change, use with caution.
  561. type DictBuilder struct {
  562. c *Client
  563. ctx context.Context
  564. dict string
  565. terms []interface{}
  566. action string // add|del|dump
  567. }
  568. // NewDictBuilder creates a new DictBuilder for FT.DICT* commands.
  569. // EXPERIMENTAL: this API is subject to change, use with caution.
  570. func (c *Client) NewDictBuilder(ctx context.Context, dict string) *DictBuilder {
  571. return &DictBuilder{c: c, ctx: ctx, dict: dict}
  572. }
  573. // Action sets the action for the dictionary builder.
  574. func (b *DictBuilder) Action(action string) *DictBuilder {
  575. b.action = action
  576. return b
  577. }
  578. // Add sets the action to "add" and requires terms.
  579. func (b *DictBuilder) Add(terms ...interface{}) *DictBuilder {
  580. b.action = "add"
  581. b.terms = terms
  582. return b
  583. }
  584. // Del sets the action to "del" and requires terms.
  585. func (b *DictBuilder) Del(terms ...interface{}) *DictBuilder {
  586. b.action = "del"
  587. b.terms = terms
  588. return b
  589. }
  590. // Dump sets the action to "dump".
  591. func (b *DictBuilder) Dump() *DictBuilder {
  592. b.action = "dump"
  593. return b
  594. }
  595. // Run executes the configured dictionary command.
  596. func (b *DictBuilder) Run() (interface{}, error) {
  597. switch b.action {
  598. case "add":
  599. cmd := b.c.FTDictAdd(b.ctx, b.dict, b.terms...)
  600. return cmd.Result()
  601. case "del":
  602. cmd := b.c.FTDictDel(b.ctx, b.dict, b.terms...)
  603. return cmd.Result()
  604. case "dump":
  605. cmd := b.c.FTDictDump(b.ctx, b.dict)
  606. return cmd.Result()
  607. }
  608. return nil, nil
  609. }
  610. // ----------------------
  611. // TagValsBuilder for FT.TAGVALS
  612. // ----------------------
  613. // TagValsBuilder is builder for FT.TAGVALS
  614. // EXPERIMENTAL: this API is subject to change, use with caution.
  615. type TagValsBuilder struct {
  616. c *Client
  617. ctx context.Context
  618. index string
  619. field string
  620. }
  621. // NewTagValsBuilder creates a new TagValsBuilder for FT.TAGVALS commands.
  622. // EXPERIMENTAL: this API is subject to change, use with caution.
  623. func (c *Client) NewTagValsBuilder(ctx context.Context, index, field string) *TagValsBuilder {
  624. return &TagValsBuilder{c: c, ctx: ctx, index: index, field: field}
  625. }
  626. // Run executes FT.TAGVALS and returns tag values.
  627. func (b *TagValsBuilder) Run() ([]string, error) {
  628. cmd := b.c.FTTagVals(b.ctx, b.index, b.field)
  629. return cmd.Result()
  630. }
  631. // ----------------------
  632. // CursorBuilder for FT.CURSOR*
  633. // ----------------------
  634. // CursorBuilder is builder for FT.CURSOR* commands
  635. // EXPERIMENTAL: this API is subject to change, use with caution.
  636. type CursorBuilder struct {
  637. c *Client
  638. ctx context.Context
  639. index string
  640. cursorId int64
  641. count int
  642. action string // read|del
  643. }
  644. // NewCursorBuilder creates a new CursorBuilder for FT.CURSOR* commands.
  645. // EXPERIMENTAL: this API is subject to change, use with caution.
  646. func (c *Client) NewCursorBuilder(ctx context.Context, index string, cursorId int64) *CursorBuilder {
  647. return &CursorBuilder{c: c, ctx: ctx, index: index, cursorId: cursorId}
  648. }
  649. // Action sets the action for the cursor builder.
  650. func (b *CursorBuilder) Action(action string) *CursorBuilder {
  651. b.action = action
  652. return b
  653. }
  654. // Read sets the action to "read".
  655. func (b *CursorBuilder) Read() *CursorBuilder {
  656. b.action = "read"
  657. return b
  658. }
  659. // Del sets the action to "del".
  660. func (b *CursorBuilder) Del() *CursorBuilder {
  661. b.action = "del"
  662. return b
  663. }
  664. // Count for READ.
  665. func (b *CursorBuilder) Count(count int) *CursorBuilder { b.count = count; return b }
  666. // Run executes the cursor command.
  667. func (b *CursorBuilder) Run() (interface{}, error) {
  668. switch b.action {
  669. case "read":
  670. cmd := b.c.FTCursorRead(b.ctx, b.index, int(b.cursorId), b.count)
  671. return cmd.Result()
  672. case "del":
  673. cmd := b.c.FTCursorDel(b.ctx, b.index, int(b.cursorId))
  674. return cmd.Result()
  675. }
  676. return nil, nil
  677. }
  678. // ----------------------
  679. // SynUpdateBuilder for FT.SYNUPDATE
  680. // ----------------------
  681. // SyncUpdateBuilder is builder for FT.SYNCUPDATE
  682. // EXPERIMENTAL: this API is subject to change, use with caution.
  683. type SynUpdateBuilder struct {
  684. c *Client
  685. ctx context.Context
  686. index string
  687. groupId interface{}
  688. options *FTSynUpdateOptions
  689. terms []interface{}
  690. }
  691. // NewSynUpdateBuilder creates a new SynUpdateBuilder for FT.SYNUPDATE commands.
  692. // EXPERIMENTAL: this API is subject to change, use with caution.
  693. func (c *Client) NewSynUpdateBuilder(ctx context.Context, index string, groupId interface{}) *SynUpdateBuilder {
  694. return &SynUpdateBuilder{c: c, ctx: ctx, index: index, groupId: groupId, options: &FTSynUpdateOptions{}}
  695. }
  696. // SkipInitialScan includes SKIPINITIALSCAN.
  697. func (b *SynUpdateBuilder) SkipInitialScan() *SynUpdateBuilder {
  698. b.options.SkipInitialScan = true
  699. return b
  700. }
  701. // Terms adds synonyms to the group.
  702. func (b *SynUpdateBuilder) Terms(terms ...interface{}) *SynUpdateBuilder { b.terms = terms; return b }
  703. // Run executes FT.SYNUPDATE.
  704. func (b *SynUpdateBuilder) Run() (string, error) {
  705. cmd := b.c.FTSynUpdateWithArgs(b.ctx, b.index, b.groupId, b.options, b.terms)
  706. return cmd.Result()
  707. }