@gooddata/sdk-maql-language-server 0.0.0-stage → 11.65.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +7 -0
- package/README.md +118 -2
- package/esm/completions/complete.d.ts +12 -0
- package/esm/completions/complete.d.ts.map +1 -0
- package/esm/completions/complete.js +316 -0
- package/esm/completions/descriptions.d.ts +42 -0
- package/esm/completions/descriptions.d.ts.map +1 -0
- package/esm/completions/descriptions.js +289 -0
- package/esm/completions/findContext.d.ts +19 -0
- package/esm/completions/findContext.d.ts.map +1 -0
- package/esm/completions/findContext.js +171 -0
- package/esm/completions/functionDescriptions.d.ts +3 -0
- package/esm/completions/functionDescriptions.d.ts.map +1 -0
- package/esm/completions/functionDescriptions.js +98 -0
- package/esm/completions/sort.d.ts +4 -0
- package/esm/completions/sort.d.ts.map +1 -0
- package/esm/completions/sort.js +88 -0
- package/esm/constants.d.ts +21 -0
- package/esm/constants.d.ts.map +1 -0
- package/esm/constants.js +22 -0
- package/esm/dateElementFormat.d.ts +9 -0
- package/esm/dateElementFormat.d.ts.map +1 -0
- package/esm/dateElementFormat.js +60 -0
- package/esm/decorations.d.ts +46 -0
- package/esm/decorations.d.ts.map +1 -0
- package/esm/decorations.js +42 -0
- package/esm/diagnostics.d.ts +12 -0
- package/esm/diagnostics.d.ts.map +1 -0
- package/esm/diagnostics.js +259 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/approximate_count.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/approximate_count.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/approximate_count.js +61 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/avg.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/avg.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/avg.js +19 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/count.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/count.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/count.js +72 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/first.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/first.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/first.js +41 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/last.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/last.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/last.js +69 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/max.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/max.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/max.js +61 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/median.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/median.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/median.js +25 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/min.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/min.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/min.js +63 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/sum.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/sum.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/aggregation/sum.js +20 -0
- package/esm/docs/en/docs/create-metrics/maql/conditionals/case.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/conditionals/case.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/conditionals/case.js +73 -0
- package/esm/docs/en/docs/create-metrics/maql/conditionals/if-then-else.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/conditionals/if-then-else.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/conditionals/if-then-else.js +29 -0
- package/esm/docs/en/docs/create-metrics/maql/conditionals/ifnull.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/conditionals/ifnull.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/conditionals/ifnull.js +96 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/filtering-with-ranking-filters.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/filtering-with-ranking-filters.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/filtering-with-ranking-filters.js +71 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/filtering-with-the-having-clause.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/filtering-with-the-having-clause.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/filtering-with-the-having-clause.js +65 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/filtering-with-the-like-clause.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/filtering-with-the-like-clause.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/filtering-with-the-like-clause.js +36 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/filtering-with-the-where-clause.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/filtering-with-the-where-clause.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/filtering-with-the-where-clause.js +36 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-attribute-filters/by-all-in-all-other-dimensions-except-for-attribute.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-attribute-filters/by-all-in-all-other-dimensions-except-for-attribute.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-attribute-filters/by-all-in-all-other-dimensions-except-for-attribute.js +21 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-attribute-filters/by-all-in-all-other-dimensions.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-attribute-filters/by-all-in-all-other-dimensions.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-attribute-filters/by-all-in-all-other-dimensions.js +27 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-attribute-filters/by-all.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-attribute-filters/by-all.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-attribute-filters/by-all.js +64 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-attribute-filters/by-attribute-all-in-all-other-dimensions.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-attribute-filters/by-attribute-all-in-all-other-dimensions.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-attribute-filters/by-attribute-all-in-all-other-dimensions.js +22 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-attribute-filters/by.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-attribute-filters/by.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-attribute-filters/by.js +85 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-parent/with-parent-except.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-parent/with-parent-except.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-parent/with-parent-except.js +37 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-parent/with-parent-filter.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-parent/with-parent-filter.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-parent/with-parent-filter.js +42 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-parent/without-parent-except.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-parent/without-parent-except.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-parent/without-parent-except.js +94 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-parent/without-parent-filter.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-parent/without-parent-filter.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/filters/overriding-parent/without-parent-filter.js +33 -0
- package/esm/docs/en/docs/create-metrics/maql/for-each.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/for-each.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/for-each.js +17 -0
- package/esm/docs/en/docs/create-metrics/maql/logical-operators/and.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/logical-operators/and.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/logical-operators/and.js +37 -0
- package/esm/docs/en/docs/create-metrics/maql/logical-operators/not.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/logical-operators/not.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/logical-operators/not.js +12 -0
- package/esm/docs/en/docs/create-metrics/maql/logical-operators/or.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/logical-operators/or.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/logical-operators/or.js +22 -0
- package/esm/docs/en/docs/create-metrics/maql/maql-and-multidimensionality.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/maql-and-multidimensionality.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/maql-and-multidimensionality.js +59 -0
- package/esm/docs/en/docs/create-metrics/maql/math/abs.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/math/abs.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/math/abs.js +23 -0
- package/esm/docs/en/docs/create-metrics/maql/math/arithmetic-operations.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/math/arithmetic-operations.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/math/arithmetic-operations.js +29 -0
- package/esm/docs/en/docs/create-metrics/maql/math/ceiling.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/math/ceiling.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/math/ceiling.js +21 -0
- package/esm/docs/en/docs/create-metrics/maql/math/exp.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/math/exp.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/math/exp.js +27 -0
- package/esm/docs/en/docs/create-metrics/maql/math/floor.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/math/floor.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/math/floor.js +21 -0
- package/esm/docs/en/docs/create-metrics/maql/math/greatest.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/math/greatest.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/math/greatest.js +13 -0
- package/esm/docs/en/docs/create-metrics/maql/math/least.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/math/least.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/math/least.js +13 -0
- package/esm/docs/en/docs/create-metrics/maql/math/ln.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/math/ln.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/math/ln.js +33 -0
- package/esm/docs/en/docs/create-metrics/maql/math/log.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/math/log.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/math/log.js +29 -0
- package/esm/docs/en/docs/create-metrics/maql/math/power.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/math/power.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/math/power.js +33 -0
- package/esm/docs/en/docs/create-metrics/maql/math/round.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/math/round.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/math/round.js +34 -0
- package/esm/docs/en/docs/create-metrics/maql/math/sign.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/math/sign.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/math/sign.js +30 -0
- package/esm/docs/en/docs/create-metrics/maql/math/sqrt.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/math/sqrt.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/math/sqrt.js +32 -0
- package/esm/docs/en/docs/create-metrics/maql/math/trunc.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/math/trunc.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/math/trunc.js +36 -0
- package/esm/docs/en/docs/create-metrics/maql/ranking/percentile.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/ranking/percentile.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/ranking/percentile.js +57 -0
- package/esm/docs/en/docs/create-metrics/maql/ranking/rank-variations.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/ranking/rank-variations.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/ranking/rank-variations.js +90 -0
- package/esm/docs/en/docs/create-metrics/maql/ranking/where-top-or-bottom-in.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/ranking/where-top-or-bottom-in.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/ranking/where-top-or-bottom-in.js +53 -0
- package/esm/docs/en/docs/create-metrics/maql/ranking/where-top-or-bottom-of.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/ranking/where-top-or-bottom-of.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/ranking/where-top-or-bottom-of.js +29 -0
- package/esm/docs/en/docs/create-metrics/maql/ranking/within-clause.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/ranking/within-clause.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/ranking/within-clause.js +101 -0
- package/esm/docs/en/docs/create-metrics/maql/relational-operators.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/relational-operators.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/relational-operators.js +50 -0
- package/esm/docs/en/docs/create-metrics/maql/runing-totals/rolling-window.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/runing-totals/rolling-window.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/runing-totals/rolling-window.js +71 -0
- package/esm/docs/en/docs/create-metrics/maql/runing-totals/running-total-statistical-functions.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/runing-totals/running-total-statistical-functions.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/runing-totals/running-total-statistical-functions.js +54 -0
- package/esm/docs/en/docs/create-metrics/maql/runing-totals/running-totals-for-core-functions.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/runing-totals/running-totals-for-core-functions.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/runing-totals/running-totals-for-core-functions.js +37 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/correl.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/correl.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/correl.js +47 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/covariance-functions.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/covariance-functions.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/covariance-functions.js +46 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/forecast.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/forecast.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/forecast.js +74 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/least-squares-functions.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/least-squares-functions.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/least-squares-functions.js +44 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/standard-deviation-functions.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/standard-deviation-functions.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/standard-deviation-functions.js +88 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/variance-functions.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/variance-functions.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/statistic/variance-functions.js +54 -0
- package/esm/docs/en/docs/create-metrics/maql/time/for-each.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/time/for-each.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/time/for-each.js +96 -0
- package/esm/docs/en/docs/create-metrics/maql/time/for-next-period.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/time/for-next-period.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/time/for-next-period.js +38 -0
- package/esm/docs/en/docs/create-metrics/maql/time/for-next.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/time/for-next.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/time/for-next.js +27 -0
- package/esm/docs/en/docs/create-metrics/maql/time/for-previous-period.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/time/for-previous-period.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/time/for-previous-period.js +26 -0
- package/esm/docs/en/docs/create-metrics/maql/time/for-previous.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/time/for-previous.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/time/for-previous.js +30 -0
- package/esm/docs/en/docs/create-metrics/maql/time/functions-for-referring-to-past-time-periods.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/time/functions-for-referring-to-past-time-periods.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/time/functions-for-referring-to-past-time-periods.js +36 -0
- package/esm/docs/en/docs/create-metrics/maql/time-arithmetics/datetime-add.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/time-arithmetics/datetime-add.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/time-arithmetics/datetime-add.js +53 -0
- package/esm/docs/en/docs/create-metrics/maql/time-arithmetics/datetime-diff.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/time-arithmetics/datetime-diff.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/time-arithmetics/datetime-diff.js +55 -0
- package/esm/docs/en/docs/create-metrics/maql/time-macros.d.ts +2 -0
- package/esm/docs/en/docs/create-metrics/maql/time-macros.d.ts.map +1 -0
- package/esm/docs/en/docs/create-metrics/maql/time-macros.js +79 -0
- package/esm/docs/index.d.ts +82 -0
- package/esm/docs/index.d.ts.map +1 -0
- package/esm/docs/index.js +143 -0
- package/esm/findObjects.d.ts +13 -0
- package/esm/findObjects.d.ts.map +1 -0
- package/esm/findObjects.js +73 -0
- package/esm/format.d.ts +4 -0
- package/esm/format.d.ts.map +1 -0
- package/esm/format.js +569 -0
- package/esm/highlight/convert.d.ts +3 -0
- package/esm/highlight/convert.d.ts.map +1 -0
- package/esm/highlight/convert.js +12 -0
- package/esm/highlight/semanticsHighlight.d.ts +47 -0
- package/esm/highlight/semanticsHighlight.d.ts.map +1 -0
- package/esm/highlight/semanticsHighlight.js +345 -0
- package/esm/highlight/utils.d.ts +3 -0
- package/esm/highlight/utils.d.ts.map +1 -0
- package/esm/highlight/utils.js +14 -0
- package/esm/hover.d.ts +23 -0
- package/esm/hover.d.ts.map +1 -0
- package/esm/hover.js +60 -0
- package/esm/index.d.ts +11 -0
- package/esm/index.d.ts.map +1 -0
- package/esm/index.js +9 -0
- package/esm/labelElements.d.ts +22 -0
- package/esm/labelElements.d.ts.map +1 -0
- package/esm/labelElements.js +224 -0
- package/esm/maqlLanguageService.d.ts +56 -0
- package/esm/maqlLanguageService.d.ts.map +1 -0
- package/esm/maqlLanguageService.js +104 -0
- package/esm/maqlObjectTypes.d.ts +17 -0
- package/esm/maqlObjectTypes.d.ts.map +1 -0
- package/esm/maqlObjectTypes.js +30 -0
- package/esm/maqlServer.d.ts +4 -0
- package/esm/maqlServer.d.ts.map +1 -0
- package/esm/maqlServer.js +78 -0
- package/esm/metadata/model.d.ts +162 -0
- package/esm/metadata/model.d.ts.map +1 -0
- package/esm/metadata/model.js +143 -0
- package/esm/metadata/parameters.d.ts +16 -0
- package/esm/metadata/parameters.d.ts.map +1 -0
- package/esm/metadata/parameters.js +37 -0
- package/esm/metadata/types.d.ts +16 -0
- package/esm/metadata/types.d.ts.map +1 -0
- package/esm/metadata/types.js +2 -0
- package/esm/metadataService.d.ts +56 -0
- package/esm/metadataService.d.ts.map +1 -0
- package/esm/metadataService.js +159 -0
- package/esm/node/main.d.ts +2 -0
- package/esm/node/main.d.ts.map +1 -0
- package/esm/node/main.js +18 -0
- package/esm/parameterConstraints.d.ts +5 -0
- package/esm/parameterConstraints.d.ts.map +1 -0
- package/esm/parameterConstraints.js +197 -0
- package/esm/parseMaql.d.ts +43 -0
- package/esm/parseMaql.d.ts.map +1 -0
- package/esm/parseMaql.js +96 -0
- package/esm/renderParameters.d.ts +41 -0
- package/esm/renderParameters.d.ts.map +1 -0
- package/esm/renderParameters.js +76 -0
- package/esm/sdk-maql-language-server.d.ts +496 -0
- package/esm/tests/metadata.test.helpers.d.ts +8 -0
- package/esm/tests/metadata.test.helpers.d.ts.map +1 -0
- package/esm/tests/metadata.test.helpers.js +468 -0
- package/esm/tokenRanges.d.ts +36 -0
- package/esm/tokenRanges.d.ts.map +1 -0
- package/esm/tokenRanges.js +55 -0
- package/esm/tsdoc-metadata.json +11 -0
- package/esm/types/hierarchy.d.ts +37 -0
- package/esm/types/hierarchy.d.ts.map +1 -0
- package/esm/types/hierarchy.js +165 -0
- package/esm/types/signatures.d.ts +40 -0
- package/esm/types/signatures.d.ts.map +1 -0
- package/esm/types/signatures.js +141 -0
- package/esm/types/typeChecking.d.ts +54 -0
- package/esm/types/typeChecking.d.ts.map +1 -0
- package/esm/types/typeChecking.js +295 -0
- package/esm/types/typeModel.d.ts +18 -0
- package/esm/types/typeModel.d.ts.map +1 -0
- package/esm/types/typeModel.js +84 -0
- package/package.json +83 -3
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// (C) 2022-2026 GoodData Corporation
|
|
2
|
+
import { Kind } from "./descriptions.js";
|
|
3
|
+
const defaultPrefix = "90__";
|
|
4
|
+
const sortPrefixes = {
|
|
5
|
+
[Kind.LabelElement]: "00__",
|
|
6
|
+
[Kind.Attribute]: "20__",
|
|
7
|
+
// [Kind.Label]: "20__", // this is the same as Kind.Label is the same as Kind.Attribute
|
|
8
|
+
[Kind.Dataset]: "21__",
|
|
9
|
+
[Kind.Fact]: "22__",
|
|
10
|
+
[Kind.Metric]: "25__",
|
|
11
|
+
[Kind.Granularity]: "30__",
|
|
12
|
+
[Kind.Function]: "40__",
|
|
13
|
+
[Kind.Keyword]: "41__",
|
|
14
|
+
[Kind.Boolean]: "42__",
|
|
15
|
+
[Kind.Operator]: "99__",
|
|
16
|
+
};
|
|
17
|
+
function getFunctionSortTemplate(functionName, prefixes) {
|
|
18
|
+
// Handle IFNULL function
|
|
19
|
+
if (functionName === "IFNULL") {
|
|
20
|
+
return prefixes([Kind.Metric, Kind.Function]);
|
|
21
|
+
}
|
|
22
|
+
// Handle statistical functions
|
|
23
|
+
const statisticalFunctions = [
|
|
24
|
+
"CORREL",
|
|
25
|
+
"COVAR",
|
|
26
|
+
"COVARP",
|
|
27
|
+
"FORECAST",
|
|
28
|
+
"RSQ",
|
|
29
|
+
"STDEV",
|
|
30
|
+
"STDEVP",
|
|
31
|
+
"VAR",
|
|
32
|
+
"VARP",
|
|
33
|
+
];
|
|
34
|
+
if (statisticalFunctions.includes(functionName)) {
|
|
35
|
+
return prefixes([Kind.Fact, Kind.Metric]);
|
|
36
|
+
}
|
|
37
|
+
// Default case for other functions
|
|
38
|
+
return prefixes([Kind.Granularity, Kind.Label, Kind.Fact, Kind.Metric, Kind.Function]);
|
|
39
|
+
}
|
|
40
|
+
export function adjustSortText(list, context) {
|
|
41
|
+
let template = Object.assign({}, sortPrefixes);
|
|
42
|
+
const prefixes = (order) => order.reduce((prev, curr, idx) => ({
|
|
43
|
+
...prev,
|
|
44
|
+
[curr]: `${String(idx + 1).padStart(2, "0")}__`,
|
|
45
|
+
}), template);
|
|
46
|
+
// Find the lowest non-empty (therefore complete and valid) AST node if such exists
|
|
47
|
+
const lowestNode = context.nodeStack.find((node) => node.type !== "");
|
|
48
|
+
switch (lowestNode?.type) {
|
|
49
|
+
case "metric":
|
|
50
|
+
template = prefixes([Kind.Function, Kind.Metric, Kind.Fact]);
|
|
51
|
+
break;
|
|
52
|
+
case "and":
|
|
53
|
+
case "or":
|
|
54
|
+
case "not":
|
|
55
|
+
template = prefixes([Kind.Label, Kind.Metric, Kind.Fact]);
|
|
56
|
+
break;
|
|
57
|
+
case "case":
|
|
58
|
+
case "when":
|
|
59
|
+
template = prefixes([Kind.Metric, Kind.Fact, Kind.Label, Kind.Function]);
|
|
60
|
+
break;
|
|
61
|
+
case "where":
|
|
62
|
+
case "having":
|
|
63
|
+
template = prefixes([Kind.Label, Kind.Metric, Kind.Fact, Kind.Function]);
|
|
64
|
+
break;
|
|
65
|
+
case "by":
|
|
66
|
+
template = prefixes([Kind.Dataset, Kind.Label, Kind.Keyword]);
|
|
67
|
+
break;
|
|
68
|
+
case "+":
|
|
69
|
+
case "=":
|
|
70
|
+
case "/":
|
|
71
|
+
case "*":
|
|
72
|
+
template = prefixes([Kind.Fact, Kind.Metric]);
|
|
73
|
+
break;
|
|
74
|
+
case "function":
|
|
75
|
+
case "time macro":
|
|
76
|
+
template = getFunctionSortTemplate(lowestNode.name, prefixes);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
list.items = list.items.map((it) => {
|
|
80
|
+
const prefix = it.kind ? (template[it.kind] ?? defaultPrefix) : defaultPrefix;
|
|
81
|
+
return {
|
|
82
|
+
...it,
|
|
83
|
+
sortText: prefix + (it.sortText ?? it.label),
|
|
84
|
+
preselect: true, // a hack to force the client to use sortText
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
return list;
|
|
88
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const LanguageId: string;
|
|
2
|
+
export declare const diagnosticsSource: string;
|
|
3
|
+
export declare enum ErrorCodes {
|
|
4
|
+
InputMismatch = 0,
|
|
5
|
+
NoViableAlternative = 1,
|
|
6
|
+
FailedPredicate = 2,
|
|
7
|
+
UnspecifiedError = 3,
|
|
8
|
+
UnrecognizedInput = 4,
|
|
9
|
+
UnterminatedString = 5,
|
|
10
|
+
UndefinedKeyword = 6,
|
|
11
|
+
InvalidType = 7,
|
|
12
|
+
ExtraIdentifiersInObject = 8,
|
|
13
|
+
ObjectNotFound = 9,
|
|
14
|
+
LabelElementNotFound = 10,
|
|
15
|
+
InvalidOperator = 11,
|
|
16
|
+
SuspiciousStringLiteral = 12,
|
|
17
|
+
ParameterValueNotAllowed = 13,
|
|
18
|
+
ParameterValueUncovered = 14,
|
|
19
|
+
InvalidLabelElementValue = 15
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,UAAU,EAAE,MAAe,CAAC;AAEzC,eAAO,MAAM,iBAAiB,QAA2B,CAAC;AAE1D,oBAAY,UAAU;IAClB,aAAa,IAAI;IACjB,mBAAmB,IAAI;IACvB,eAAe,IAAI;IACnB,gBAAgB,IAAI;IACpB,iBAAiB,IAAI;IACrB,kBAAkB,IAAI;IACtB,gBAAgB,IAAI;IACpB,WAAW,IAAI;IACf,wBAAwB,IAAI;IAC5B,cAAc,IAAI;IAClB,oBAAoB,KAAK;IACzB,eAAe,KAAK;IACpB,uBAAuB,KAAK;IAC5B,wBAAwB,KAAK;IAC7B,uBAAuB,KAAK;IAC5B,wBAAwB,KAAK;CAChC"}
|
package/esm/constants.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// (C) 2021-2026 GoodData Corporation
|
|
2
|
+
export const LanguageId = "maql";
|
|
3
|
+
export const diagnosticsSource = LanguageId.toUpperCase();
|
|
4
|
+
export var ErrorCodes;
|
|
5
|
+
(function (ErrorCodes) {
|
|
6
|
+
ErrorCodes[ErrorCodes["InputMismatch"] = 0] = "InputMismatch";
|
|
7
|
+
ErrorCodes[ErrorCodes["NoViableAlternative"] = 1] = "NoViableAlternative";
|
|
8
|
+
ErrorCodes[ErrorCodes["FailedPredicate"] = 2] = "FailedPredicate";
|
|
9
|
+
ErrorCodes[ErrorCodes["UnspecifiedError"] = 3] = "UnspecifiedError";
|
|
10
|
+
ErrorCodes[ErrorCodes["UnrecognizedInput"] = 4] = "UnrecognizedInput";
|
|
11
|
+
ErrorCodes[ErrorCodes["UnterminatedString"] = 5] = "UnterminatedString";
|
|
12
|
+
ErrorCodes[ErrorCodes["UndefinedKeyword"] = 6] = "UndefinedKeyword";
|
|
13
|
+
ErrorCodes[ErrorCodes["InvalidType"] = 7] = "InvalidType";
|
|
14
|
+
ErrorCodes[ErrorCodes["ExtraIdentifiersInObject"] = 8] = "ExtraIdentifiersInObject";
|
|
15
|
+
ErrorCodes[ErrorCodes["ObjectNotFound"] = 9] = "ObjectNotFound";
|
|
16
|
+
ErrorCodes[ErrorCodes["LabelElementNotFound"] = 10] = "LabelElementNotFound";
|
|
17
|
+
ErrorCodes[ErrorCodes["InvalidOperator"] = 11] = "InvalidOperator";
|
|
18
|
+
ErrorCodes[ErrorCodes["SuspiciousStringLiteral"] = 12] = "SuspiciousStringLiteral";
|
|
19
|
+
ErrorCodes[ErrorCodes["ParameterValueNotAllowed"] = 13] = "ParameterValueNotAllowed";
|
|
20
|
+
ErrorCodes[ErrorCodes["ParameterValueUncovered"] = 14] = "ParameterValueUncovered";
|
|
21
|
+
ErrorCodes[ErrorCodes["InvalidLabelElementValue"] = 15] = "InvalidLabelElementValue";
|
|
22
|
+
})(ErrorCodes || (ErrorCodes = {}));
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type DateAttributeGranularity } from "@gooddata/sdk-model";
|
|
2
|
+
/**
|
|
3
|
+
* Checks that the value of a date attribute element has the format the backend expects for the granularity.
|
|
4
|
+
*
|
|
5
|
+
* @returns the expected pattern when the value does not match it, undefined when the value is valid
|
|
6
|
+
* or the granularity is not checked
|
|
7
|
+
*/
|
|
8
|
+
export declare function getInvalidDateElementPattern(value: string, granularity: DateAttributeGranularity | undefined): string | undefined;
|
|
9
|
+
//# sourceMappingURL=dateElementFormat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dateElementFormat.d.ts","sourceRoot":"","sources":["../src/dateElementFormat.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAuDpE;;;;;GAKG;AACH,wBAAgB,4BAA4B,CACxC,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,wBAAwB,GAAG,SAAS,GAClD,MAAM,GAAG,SAAS,CAMpB"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
/**
|
|
3
|
+
* Value patterns the backend expects for date attribute elements used in MAQL, per granularity.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the backend (gdc-nas) implementation, which is the source of truth:
|
|
6
|
+
* - patterns: `libraries/calq/calcique-lib/src/main/kotlin/generator/model/date/GregorianChronological.kt`
|
|
7
|
+
* and `FiscalChronological.kt` (`pattern` of each granularity object)
|
|
8
|
+
* - regex derivation: `Chronological.valueRegex` in `.../generator/model/date/Chronological.kt`
|
|
9
|
+
* - check: `TypeHandler.checkDateFormat` in `libraries/calq/calcique-lib/src/main/kotlin/interpreter/TypeHandler.kt`
|
|
10
|
+
*
|
|
11
|
+
* The backend regex is deliberately loose (e.g. month `[01]?\d` accepts "13"), and this check must accept
|
|
12
|
+
* exactly the same values, otherwise the editor would reject expressions the backend accepts.
|
|
13
|
+
* Any change on the backend side has to be aligned here manually.
|
|
14
|
+
*
|
|
15
|
+
* Periodical granularities (day of week, month of year, ...) are validated by the backend as integer ranges
|
|
16
|
+
* that partly depend on the workspace configuration; they are not checked here and rely on the backend
|
|
17
|
+
* error returned by the elements query instead.
|
|
18
|
+
*/
|
|
19
|
+
const granularityPatterns = {
|
|
20
|
+
"GDC.time.second": "YYYY-MM-DD HH24:MI:SS",
|
|
21
|
+
"GDC.time.minute": "YYYY-MM-DD HH24:MI",
|
|
22
|
+
"GDC.time.hour": "YYYY-MM-DD HH24",
|
|
23
|
+
"GDC.time.date": "YYYY-MM-DD",
|
|
24
|
+
"GDC.time.week_us": "IYYY-IW",
|
|
25
|
+
"GDC.time.month": "YYYY-MM",
|
|
26
|
+
"GDC.time.quarter": "YYYY-Q",
|
|
27
|
+
"GDC.time.year": "YYYY",
|
|
28
|
+
"GDC.time.fiscal_month": "YYYY-MM",
|
|
29
|
+
"GDC.time.fiscal_quarter": "YYYY-Q",
|
|
30
|
+
"GDC.time.fiscal_year": "YYYY",
|
|
31
|
+
};
|
|
32
|
+
// Same replacement order as Chronological.valueRegex on the backend
|
|
33
|
+
const patternTokens = [
|
|
34
|
+
["YYYY", "(\\d{1,4})"],
|
|
35
|
+
["IYYY", "(\\d{1,4})"],
|
|
36
|
+
["Q", "([1-4])"],
|
|
37
|
+
["MM", "([01]?\\d)"],
|
|
38
|
+
["IW", "([0-5]?\\d)"],
|
|
39
|
+
["DD", "([0-3]?\\d)"],
|
|
40
|
+
["HH24", "([0-2]?\\d)"],
|
|
41
|
+
["MI", "([0-5]?\\d)"],
|
|
42
|
+
["SS", "([0-5]?\\d)"],
|
|
43
|
+
];
|
|
44
|
+
const granularityRegexes = new Map(Object.entries(granularityPatterns).map(([granularity, pattern]) => [
|
|
45
|
+
granularity,
|
|
46
|
+
new RegExp(`^${patternTokens.reduce((regex, [token, replacement]) => regex.replaceAll(token, replacement), pattern)}$`),
|
|
47
|
+
]));
|
|
48
|
+
/**
|
|
49
|
+
* Checks that the value of a date attribute element has the format the backend expects for the granularity.
|
|
50
|
+
*
|
|
51
|
+
* @returns the expected pattern when the value does not match it, undefined when the value is valid
|
|
52
|
+
* or the granularity is not checked
|
|
53
|
+
*/
|
|
54
|
+
export function getInvalidDateElementPattern(value, granularity) {
|
|
55
|
+
if (!granularity || value === "") {
|
|
56
|
+
return undefined; // the backend considers an empty string to be NULL for dates
|
|
57
|
+
}
|
|
58
|
+
const regex = granularityRegexes.get(granularity);
|
|
59
|
+
return regex && !regex.test(value) ? granularityPatterns[granularity] : undefined;
|
|
60
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type MarkupContent, type Range } from "vscode-languageserver";
|
|
2
|
+
import { type ITigerMetadataObject, type LdmObjects } from "./metadata/model.js";
|
|
3
|
+
/**
|
|
4
|
+
* The decorations as defined in this file are heavily inspired by Monaco editor decorations.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* A decoration in the model.
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export interface IDecoration {
|
|
12
|
+
/**
|
|
13
|
+
* Range that this decoration covers.
|
|
14
|
+
*/
|
|
15
|
+
range: Range;
|
|
16
|
+
/**
|
|
17
|
+
* Options associated with this decoration.
|
|
18
|
+
*/
|
|
19
|
+
options: IDecorationOptions;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Options for a decoration.
|
|
23
|
+
*
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
export interface IDecorationOptions {
|
|
27
|
+
/**
|
|
28
|
+
* Array of MarkdownString to render as the decoration message.
|
|
29
|
+
*/
|
|
30
|
+
hoverMessage?: MarkupContent | MarkupContent[];
|
|
31
|
+
/**
|
|
32
|
+
* If set, text will be injected in the view after the range.
|
|
33
|
+
*/
|
|
34
|
+
label: string;
|
|
35
|
+
/**
|
|
36
|
+
* Type of current decorator
|
|
37
|
+
*/
|
|
38
|
+
type: DecorationType;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
43
|
+
export type DecorationType = ITigerMetadataObject["tigerType"] | "dateAttribute" | "dateLabel";
|
|
44
|
+
export declare function decorate(query: string, ldmObjects?: LdmObjects): IDecoration[];
|
|
45
|
+
export declare function createDecoration(range: Range, label: string, type: DecorationType): IDecoration;
|
|
46
|
+
//# sourceMappingURL=decorations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorations.d.ts","sourceRoot":"","sources":["../src/decorations.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAGvE,OAAO,EACH,KAAK,oBAAoB,EACzB,KAAK,UAAU,EAGlB,MAAM,qBAAqB,CAAC;AAI7B;;GAEG;AAEH;;;;GAIG;AACH,MAAM,WAAW,WAAW;IACxB;;OAEG;IACH,KAAK,EAAE,KAAK,CAAC;IACb;;OAEG;IACH,OAAO,EAAE,kBAAkB,CAAC;CAC/B;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IAC/B;;OAEG;IACH,YAAY,CAAC,EAAE,aAAa,GAAG,aAAa,EAAE,CAAC;IAC/C;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,IAAI,EAAE,cAAc,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,oBAAoB,CAAC,WAAW,CAAC,GAAG,eAAe,GAAG,WAAW,CAAC;AAE/F,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,WAAW,EAAE,CAI9E;AA6BD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,WAAW,CAQ/F"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// (C) 2021-2026 GoodData Corporation
|
|
2
|
+
import { findAllObjects } from "./findObjects.js";
|
|
3
|
+
import { isITigerAttribute, isITigerLabel, } from "./metadata/model.js";
|
|
4
|
+
import { MaqlMetric } from "./parseMaql.js";
|
|
5
|
+
export function decorate(query, ldmObjects) {
|
|
6
|
+
const metric = new MaqlMetric(query);
|
|
7
|
+
// decorate objects with business names
|
|
8
|
+
return ldmObjects ? decorateBusinessNames(metric, ldmObjects) : [];
|
|
9
|
+
}
|
|
10
|
+
function decorateBusinessNames(metric, ldmObjects) {
|
|
11
|
+
const foundObjects = findAllObjects(metric);
|
|
12
|
+
return foundObjects
|
|
13
|
+
.map((objectAndRange) => {
|
|
14
|
+
const fullObject = ldmObjects.findObject(objectAndRange);
|
|
15
|
+
if (!fullObject)
|
|
16
|
+
return null;
|
|
17
|
+
return {
|
|
18
|
+
range: objectAndRange.range.toRange(),
|
|
19
|
+
...fullObject,
|
|
20
|
+
};
|
|
21
|
+
})
|
|
22
|
+
.filter((foundObject) => !!foundObject)
|
|
23
|
+
.map((foundObject) => createDecoration(foundObject.range, foundObject.title, toDecorationType(foundObject)));
|
|
24
|
+
}
|
|
25
|
+
function toDecorationType(object) {
|
|
26
|
+
if (isITigerAttribute(object)) {
|
|
27
|
+
return object.tigerTypeModifier === "date" ? "dateAttribute" : object.tigerType;
|
|
28
|
+
}
|
|
29
|
+
if (isITigerLabel(object)) {
|
|
30
|
+
return object.tigerTypeModifier === "date" ? "dateLabel" : object.tigerType;
|
|
31
|
+
}
|
|
32
|
+
return object.tigerType;
|
|
33
|
+
}
|
|
34
|
+
export function createDecoration(range, label, type) {
|
|
35
|
+
return {
|
|
36
|
+
range,
|
|
37
|
+
options: {
|
|
38
|
+
label,
|
|
39
|
+
type,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Diagnostic } from "vscode-languageserver";
|
|
2
|
+
import { ErrorCodes } from "./constants.js";
|
|
3
|
+
import { type LabelElementsFunc, type LdmObjects } from "./metadata/model.js";
|
|
4
|
+
interface IErrorDescription {
|
|
5
|
+
message(tokenText?: string): string;
|
|
6
|
+
code: ErrorCodes;
|
|
7
|
+
}
|
|
8
|
+
export declare const errorTokenDescriptions: Map<number, IErrorDescription>;
|
|
9
|
+
export declare const errorTokens: number[];
|
|
10
|
+
export declare function validate(query: string, ldmObjects?: LdmObjects, labelElementsFunc?: LabelElementsFunc): Promise<Diagnostic[]>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=diagnostics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,UAAU,EAA6B,MAAM,uBAAuB,CAAC;AAc9E,OAAO,EAAE,UAAU,EAAqB,MAAM,gBAAgB,CAAC;AAI/D,OAAO,EAEH,KAAK,iBAAiB,EACtB,KAAK,UAAU,EAGlB,MAAM,qBAAqB,CAAC;AAO7B,UAAU,iBAAiB;IACvB,OAAO,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAEpC,IAAI,EAAE,UAAU,CAAC;CACpB;AAED,eAAO,MAAM,sBAAsB,gCAgDjC,CAAC;AAEH,eAAO,MAAM,WAAW,EAAE,MAAM,EAA8C,CAAC;AAE/E,wBAAsB,QAAQ,CAC1B,KAAK,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,UAAU,EACvB,iBAAiB,CAAC,EAAE,iBAAiB,GACtC,OAAO,CAAC,UAAU,EAAE,CAAC,CAsBvB"}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
// (C) 2021-2026 GoodData Corporation
|
|
2
|
+
import { DefaultErrorStrategy, FailedPredicateException, InputMismatchException, NoViableAltException, } from "antlr4ng";
|
|
3
|
+
import { groupBy } from "lodash-es";
|
|
4
|
+
import { Diagnostic, DiagnosticSeverity, Range } from "vscode-languageserver";
|
|
5
|
+
import { AbstractAstVisitor, MaqlLexer, SyntaxErrorListener, } from "@gooddata/maql-antlr4ts";
|
|
6
|
+
import { isUnexpectedResponseError } from "@gooddata/sdk-backend-spi";
|
|
7
|
+
import { areObjRefsEqual, serializeObjRef } from "@gooddata/sdk-model";
|
|
8
|
+
import { ErrorCodes, diagnosticsSource } from "./constants.js";
|
|
9
|
+
import { getInvalidDateElementPattern } from "./dateElementFormat.js";
|
|
10
|
+
import { findAllObjects } from "./findObjects.js";
|
|
11
|
+
import { labelElementsFinder } from "./labelElements.js";
|
|
12
|
+
import { isITigerAttribute, isITigerLabel, } from "./metadata/model.js";
|
|
13
|
+
import { validateParameterConstraints } from "./parameterConstraints.js";
|
|
14
|
+
import { MaqlMetric } from "./parseMaql.js";
|
|
15
|
+
import { AntlrRange, defaultRange, tokenRange } from "./tokenRanges.js";
|
|
16
|
+
import { AstTypeChecker } from "./types/typeChecking.js";
|
|
17
|
+
import { TypeModel } from "./types/typeModel.js";
|
|
18
|
+
export const errorTokenDescriptions = new Map([
|
|
19
|
+
[
|
|
20
|
+
MaqlLexer.UnterminatedString,
|
|
21
|
+
{
|
|
22
|
+
message() {
|
|
23
|
+
return "missing '\"' at the end of a string";
|
|
24
|
+
},
|
|
25
|
+
code: ErrorCodes.UnterminatedString,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
// [
|
|
29
|
+
// // TODO Reuse for "no function definition found"
|
|
30
|
+
// MaqlLexer.Identifier,
|
|
31
|
+
// {
|
|
32
|
+
// message(tokenText: string): string {
|
|
33
|
+
// return `undefined keyword '${tokenText}'`;
|
|
34
|
+
// },
|
|
35
|
+
// code: ErrorCodes.UndefinedKeyword,
|
|
36
|
+
// },
|
|
37
|
+
// ],
|
|
38
|
+
[
|
|
39
|
+
MaqlLexer.ERROR_CHARACTER,
|
|
40
|
+
{
|
|
41
|
+
message(tokenText) {
|
|
42
|
+
return `unexpected character '${tokenText}'`;
|
|
43
|
+
},
|
|
44
|
+
code: ErrorCodes.UnrecognizedInput,
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
[
|
|
48
|
+
MaqlLexer.UNKNOWN_TYPE,
|
|
49
|
+
{
|
|
50
|
+
message(tokenText) {
|
|
51
|
+
return `invalid object type '${tokenText}'`;
|
|
52
|
+
},
|
|
53
|
+
code: ErrorCodes.InvalidType,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
// [
|
|
57
|
+
// // was removed with top-win identifiers, will probably be reintroduced at some point in the future
|
|
58
|
+
// MaqlLexer.OBJECT_EXTRA_SUFFIX,
|
|
59
|
+
// {
|
|
60
|
+
// message(tokenText: string): string {
|
|
61
|
+
// return `too many identifiers: ${tokenText.slice(1).replace(/\//g, ", ")}`;
|
|
62
|
+
// },
|
|
63
|
+
// code: ErrorCodes.ExtraIdentifiersInObject,
|
|
64
|
+
// },
|
|
65
|
+
// ],
|
|
66
|
+
]);
|
|
67
|
+
export const errorTokens = Array.from(errorTokenDescriptions.keys());
|
|
68
|
+
export async function validate(query, ldmObjects, labelElementsFunc) {
|
|
69
|
+
const metric = new MaqlMetric(query);
|
|
70
|
+
const parserDiagnostics = validateByParser(metric);
|
|
71
|
+
// If any errors were encountered, go through all tokens and match any error tokens to specific diagnostics
|
|
72
|
+
const lexerDiagnostics = parserDiagnostics.length > 0 ? validateByLexer(metric) : [];
|
|
73
|
+
// Verify that semantic rules are followed
|
|
74
|
+
const semanticDiagnostics = validateSemantics(metric.ast);
|
|
75
|
+
// Verify that objects in the query exist
|
|
76
|
+
const objectsDiagnostics = ldmObjects ? validateObjects(metric, ldmObjects) : [];
|
|
77
|
+
// Verify that strings in the query are valid label elements
|
|
78
|
+
const labelDiagnostics = await validateLabelElements(metric, ldmObjects, labelElementsFunc);
|
|
79
|
+
// Verify types
|
|
80
|
+
const typeDiagnostics = ldmObjects ? validateTypes(metric.ast, ldmObjects) : [];
|
|
81
|
+
const constraintsDiagnostics = ldmObjects ? validateParameterConstraints(metric, ldmObjects) : [];
|
|
82
|
+
return parserDiagnostics.concat(lexerDiagnostics, semanticDiagnostics, typeDiagnostics, objectsDiagnostics, constraintsDiagnostics, labelDiagnostics.flat());
|
|
83
|
+
}
|
|
84
|
+
function validateSemantics(root) {
|
|
85
|
+
const validator = new SemanticValidator();
|
|
86
|
+
return validator.visit(root);
|
|
87
|
+
}
|
|
88
|
+
function validateByParser(metric) {
|
|
89
|
+
const syntaxErrorListener = new SyntaxErrorListener();
|
|
90
|
+
// oxlint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
91
|
+
metric.addErrorListener(syntaxErrorListener).setErrorHandler(new DefaultErrorStrategy()).tree; // parse MAQL
|
|
92
|
+
return syntaxErrorListener.antlrErrors.map((error) => {
|
|
93
|
+
const errorCode = ((parserError) => {
|
|
94
|
+
// only the actual instance of error will match 'true'
|
|
95
|
+
switch (true) {
|
|
96
|
+
case parserError instanceof InputMismatchException:
|
|
97
|
+
return ErrorCodes.InputMismatch;
|
|
98
|
+
case parserError instanceof NoViableAltException:
|
|
99
|
+
return ErrorCodes.NoViableAlternative;
|
|
100
|
+
case parserError instanceof FailedPredicateException:
|
|
101
|
+
return ErrorCodes.FailedPredicate;
|
|
102
|
+
default:
|
|
103
|
+
return ErrorCodes.UnspecifiedError;
|
|
104
|
+
}
|
|
105
|
+
})(error.error);
|
|
106
|
+
const range = error.offendingToken
|
|
107
|
+
? tokenRange(error.offendingToken)
|
|
108
|
+
: defaultRange(error.position.line, error.position.character);
|
|
109
|
+
return Diagnostic.create(range, error.message, DiagnosticSeverity.Error, errorCode, diagnosticsSource);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function validateByLexer(metric) {
|
|
113
|
+
return metric.lexer
|
|
114
|
+
.getAllTokens()
|
|
115
|
+
.map((token) => handleErrorToken(token))
|
|
116
|
+
.filter((diagnostic) => !!diagnostic);
|
|
117
|
+
}
|
|
118
|
+
function validateObjects(metric, ldmObjects) {
|
|
119
|
+
const foundObjects = findAllObjects(metric);
|
|
120
|
+
return foundObjects
|
|
121
|
+
.map((foundObject) => {
|
|
122
|
+
const existingObjects = foundObject.tigerType ? ldmObjects.get(foundObject.tigerType) : undefined;
|
|
123
|
+
if (!existingObjects) {
|
|
124
|
+
return Diagnostic.create(foundObject.range.toRange(), `type '${foundObject.actualType}' is not valid`, DiagnosticSeverity.Error, ErrorCodes.InvalidType, diagnosticsSource);
|
|
125
|
+
}
|
|
126
|
+
return existingObjects.find((obj) => areObjRefsEqual(obj.ref, foundObject.ref))
|
|
127
|
+
? null
|
|
128
|
+
: Diagnostic.create(foundObject.range.toRange(), `${foundObject.tigerType} '${foundObject.id}' not found`, DiagnosticSeverity.Error, ErrorCodes.ObjectNotFound, diagnosticsSource);
|
|
129
|
+
})
|
|
130
|
+
.filter((diagnostic) => !!diagnostic);
|
|
131
|
+
}
|
|
132
|
+
async function validateLabelElements(metric, ldmObjects, labelElementsFunc) {
|
|
133
|
+
if (!ldmObjects && !labelElementsFunc) {
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
136
|
+
const foundPairs = labelElementsFinder(metric);
|
|
137
|
+
const stringsGrouped = groupBy(foundPairs, (pair) => serializeObjRef(pair[0].ref));
|
|
138
|
+
return Promise.all(Object.entries(stringsGrouped).map(async ([_ref, pairs]) => {
|
|
139
|
+
const label = pairs[0][0]; // all the labels from 'pairs' have the same ref (identity)
|
|
140
|
+
const granularity = getDateGranularity(label, ldmObjects);
|
|
141
|
+
const formatDiagnostics = [];
|
|
142
|
+
const elements = [];
|
|
143
|
+
pairs.forEach(([, element]) => {
|
|
144
|
+
const expectedPattern = getInvalidDateElementPattern(element.string, granularity);
|
|
145
|
+
if (expectedPattern) {
|
|
146
|
+
formatDiagnostics.push(invalidLabelElementDiagnostic(element, `"${element.string}" does not match the format ${expectedPattern} expected by {${label.tigerType}/${label.id}}`));
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
elements.push(element);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
if (!labelElementsFunc || elements.length === 0) {
|
|
153
|
+
return formatDiagnostics; // malformed values are not sent to the backend, it would reject them anyway
|
|
154
|
+
}
|
|
155
|
+
const result = await labelElementsFunc([label], [], { elements: { values: elements.map((element) => element.string) } }, elements.length);
|
|
156
|
+
if (result.rejected.includes(label)) {
|
|
157
|
+
// the query for the label was rejected, only a rejection of the values themselves allows a claim
|
|
158
|
+
return formatDiagnostics.concat(rejectedElementsDiagnostics(elements, result.rejectionReasons?.get(label)));
|
|
159
|
+
}
|
|
160
|
+
if (result.list.elements.length === elements.length) {
|
|
161
|
+
return formatDiagnostics; // all label elements were returned
|
|
162
|
+
}
|
|
163
|
+
const resultElements = result.list.elements.map((element) => element.title);
|
|
164
|
+
return formatDiagnostics.concat(elements
|
|
165
|
+
.map((element) => labelElementInResult(element, label, resultElements))
|
|
166
|
+
.filter((diagnostic) => !!diagnostic));
|
|
167
|
+
}));
|
|
168
|
+
}
|
|
169
|
+
function getDateGranularity(label, ldmObjects) {
|
|
170
|
+
const object = ldmObjects?.findObject(label);
|
|
171
|
+
return object &&
|
|
172
|
+
(isITigerLabel(object) || isITigerAttribute(object)) &&
|
|
173
|
+
object.tigerTypeModifier === "date"
|
|
174
|
+
? object.granularity
|
|
175
|
+
: undefined;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* The backend rejects the elements query with 400 Bad Request when the values are invalid for the label,
|
|
179
|
+
* e.g. a date value in a wrong format for a granularity the client-side check does not cover.
|
|
180
|
+
* Any other failure (network, server error, ...) allows no claim about the values.
|
|
181
|
+
*/
|
|
182
|
+
function rejectedElementsDiagnostics(elements, reason) {
|
|
183
|
+
if (!isUnexpectedResponseError(reason) || reason.httpStatus !== 400) {
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
const responseBody = reason.responseBody;
|
|
187
|
+
const detail = typeof responseBody === "object" &&
|
|
188
|
+
responseBody !== null &&
|
|
189
|
+
"detail" in responseBody &&
|
|
190
|
+
typeof responseBody.detail === "string"
|
|
191
|
+
? responseBody.detail
|
|
192
|
+
: undefined;
|
|
193
|
+
if (!detail) {
|
|
194
|
+
return [];
|
|
195
|
+
}
|
|
196
|
+
// the backend reports the first offending value, mark it if it can be identified, otherwise mark all of them
|
|
197
|
+
const offending = elements.filter((element) => detail.includes(`'${element.string}'`));
|
|
198
|
+
return (offending.length > 0 ? offending : elements).map((element) => invalidLabelElementDiagnostic(element, detail));
|
|
199
|
+
}
|
|
200
|
+
function invalidLabelElementDiagnostic(element, message) {
|
|
201
|
+
return Diagnostic.create(element.range.toRange(), message, DiagnosticSeverity.Error, ErrorCodes.InvalidLabelElementValue, diagnosticsSource);
|
|
202
|
+
}
|
|
203
|
+
function validateTypes(ast, ldmObjects) {
|
|
204
|
+
const stringLabelIds = ldmObjects.get("label", "regular").map((label) => label.id);
|
|
205
|
+
const dateLabelIds = ldmObjects.get("label", "date").map((label) => label.id);
|
|
206
|
+
const typeChecker = new AstTypeChecker(new TypeModel(stringLabelIds, dateLabelIds));
|
|
207
|
+
typeChecker.visit(ast);
|
|
208
|
+
const typeViolations = typeChecker.typeConstraintsViolations;
|
|
209
|
+
return typeViolations.map((violation) => {
|
|
210
|
+
const range = violation.range
|
|
211
|
+
? AntlrRange.fromAstRange(violation.range).toRange()
|
|
212
|
+
: Range.create(0, 0, 0, 0);
|
|
213
|
+
return Diagnostic.create(range, violation.message, DiagnosticSeverity.Error, ErrorCodes.InvalidType, diagnosticsSource);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* @returns null if "element" is in "resultElements", diagnostic signifying the error otherwise
|
|
218
|
+
*/
|
|
219
|
+
function labelElementInResult(element, label, resultElements) {
|
|
220
|
+
return resultElements.includes(element.string)
|
|
221
|
+
? null
|
|
222
|
+
: Diagnostic.create(element.range.toRange(), `"${element.string}" is not an element of {${label.tigerType}/${label.id}}`, DiagnosticSeverity.Warning, ErrorCodes.LabelElementNotFound, diagnosticsSource);
|
|
223
|
+
}
|
|
224
|
+
class SemanticValidator extends AbstractAstVisitor {
|
|
225
|
+
EQUALITY_OPERATORS = ["=", "<>", "in", "not in"];
|
|
226
|
+
defaultResult() {
|
|
227
|
+
return [];
|
|
228
|
+
}
|
|
229
|
+
aggregateResult(aggregate, nextResult) {
|
|
230
|
+
return aggregate.concat(nextResult);
|
|
231
|
+
}
|
|
232
|
+
visitOperatorNode(node) {
|
|
233
|
+
const childrenResult = this.visitChildren(node);
|
|
234
|
+
if (!this.EQUALITY_OPERATORS.includes(node.type) &&
|
|
235
|
+
node.range !== undefined &&
|
|
236
|
+
// this is only a shallow check, consider expanding the type system for a full check
|
|
237
|
+
node.content.some((operand) => operand.type === "null")) {
|
|
238
|
+
return this.aggregateResult(childrenResult, [
|
|
239
|
+
Diagnostic.create(AntlrRange.fromAstRange(node.range).toRange(), "Only equality operators can be used with NULL", DiagnosticSeverity.Error, ErrorCodes.InvalidOperator),
|
|
240
|
+
]);
|
|
241
|
+
}
|
|
242
|
+
return childrenResult;
|
|
243
|
+
}
|
|
244
|
+
visitStringLiteralNode(node) {
|
|
245
|
+
if (node.value.toLowerCase() === "null" && node.range) {
|
|
246
|
+
return [
|
|
247
|
+
Diagnostic.create(AntlrRange.fromAstRange(node.range).toRange(), `This is a string literal containing the word "${node.value}". ` +
|
|
248
|
+
"Perhaps you meant the NULL keyword (no quotes)?", DiagnosticSeverity.Warning, ErrorCodes.SuspiciousStringLiteral),
|
|
249
|
+
];
|
|
250
|
+
}
|
|
251
|
+
return [];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function handleErrorToken(token) {
|
|
255
|
+
const errorDescription = errorTokenDescriptions.get(token.type);
|
|
256
|
+
if (!errorDescription)
|
|
257
|
+
return;
|
|
258
|
+
return Diagnostic.create(tokenRange(token), errorDescription.message(token.text), DiagnosticSeverity.Error, errorDescription.code, diagnosticsSource);
|
|
259
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const content = "# APPROXIMATE_COUNT\nUse APPROXIMATE_COUNT to return the approximate number of unique values for an attribute. Because the returned value is a statistical estimate and not an exact figure, this function can increase the processing speed when analyzing large datasets. You can use APPROXIMATE_COUNT anywhere you can use COUNT. The smaller the amount of data to process, the more likely that the returned results of APPROXIMATE_COUNT will match the results of COUNT. \n\n - APPROXIMATE_COUNT is available only for workspaces that use [Vertica](https://www.gooddata.com/developers/cloud-native/doc/hosted/connect-data/create-data-sources/vertica/) Data Sources.\n - APPROXIMATE_COUNT uses the Vertica default behavior for APPROXIMATE_COUNT_DISTINCT. It is not possible to use modifiers.\n - GoodData defaults to COUNT when APPROXIMATE_COUNT is unavailable in a workspace.\n\n## Syntax\n\nAPPROXIMATE_COUNT uses the following syntax:\n\n\n |Form | Syntax | Example|\n |------------------ |------------------------------------------------------------| --------------------------------------------|\n |single parameter |`SELECT APPROXIMATE_COUNT(attribute)` |`SELECT APPROXIMATE_COUNT({attribute/order_id})`|\n |two parameters |`SELECT APPROXIMATE_COUNT(attribute, primary_key)` |`SELECT APPROXIMATE_COUNT({attribute/order_id}, {attribute/campaign_id})`|\n |with USING |`SELECT APPROXIMATE_COUNT(attribute) USING primary_key` |`SELECT APPROXIMATE_COUNT({attribute/order_id}) USING {attribute/campaign_id}`|\n\n\n### Single-Parameter Version\n\nThe single-parameter version of APPROXIMATE_COUNT dynamically gets the context of\nwhere to count from the visualization it is used in.\n\n### Two-Parameter Version\n\nIn the two-parameter version, the context where to count the attribute\nis determined explicitly by the second parameter - the primary key of\nthe dataset.\n\nThe primary key is connection point between datasets. It connects the\nAPPROXIMATE_COUNT function's first parameter to the dataset in which the count is\nto take place.\n\n### Specifying APPROXIMATE_COUNT Context Resolution with USING\n\nIn a metric, USING provides a hint for which context should be used.\nThe context for the computation of APPROXIMATE COUNT may be ambiguous if there are\nmultiple fact datasets in your logical data model that relate to a counted attribute. \n\nThe following image shows a model with the fact datasets `Purchases` and `Sales` and\nhas both datasets connected to the `Store ID` and `Product ID` attributes.\n\n\n\nTo create a metric that resolves with a specific context, you can specify USING in your metric like in the following \nexample: `SELECT COUNT({label/inventory.productid}) USING {label/purchases.purchaseid}`. \n\nWith this example, the visualization will show the approximate number of uniquely purchased products per store \nbecause the attribute `Purchase ID` from the `Purchases` dataset is in the USING clause.\n\nWith the example model, if you build a visualization to display the approximate count of products per store with \n`SELECT COUNT({label/inventory.productid})` and slice it by Store without specifying USING, it is ambiguous whether \nthe visualization is displaying the approximate number of unique products that have been purchased by store or the\napproximate number of unique products that have been sold by the store.\n\nThe attribute in the USING clause can be any attribute which uniquely determines the correct context. For example, you\ncan also use an attribute from the `Purchase Date` dataset in the USING clause. This uses the `Purchases` dataset as \nthe context because the `Sales` dataset has no relationships to `Purchase Date`: \n`SELECT COUNT({label/inventory.productid}) USING {label/purchasedate.year}`";
|
|
2
|
+
//# sourceMappingURL=approximate_count.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approximate_count.d.ts","sourceRoot":"","sources":["../../../../../../../src/docs/en/docs/create-metrics/maql/aggregation/approximate_count.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,OAAO,u6HA2D0D,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// (C) 2021-2026 GoodData Corporation
|
|
2
|
+
export const content = `# APPROXIMATE_COUNT
|
|
3
|
+
Use APPROXIMATE_COUNT to return the approximate number of unique values for an attribute. Because the returned value is a statistical estimate and not an exact figure, this function can increase the processing speed when analyzing large datasets. You can use APPROXIMATE_COUNT anywhere you can use COUNT. The smaller the amount of data to process, the more likely that the returned results of APPROXIMATE_COUNT will match the results of COUNT.
|
|
4
|
+
|
|
5
|
+
- APPROXIMATE_COUNT is available only for workspaces that use [Vertica](https://www.gooddata.com/developers/cloud-native/doc/hosted/connect-data/create-data-sources/vertica/) Data Sources.
|
|
6
|
+
- APPROXIMATE_COUNT uses the Vertica default behavior for APPROXIMATE_COUNT_DISTINCT. It is not possible to use modifiers.
|
|
7
|
+
- GoodData defaults to COUNT when APPROXIMATE_COUNT is unavailable in a workspace.
|
|
8
|
+
|
|
9
|
+
## Syntax
|
|
10
|
+
|
|
11
|
+
APPROXIMATE_COUNT uses the following syntax:
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|Form | Syntax | Example|
|
|
15
|
+
|------------------ |------------------------------------------------------------| --------------------------------------------|
|
|
16
|
+
|single parameter |\`SELECT APPROXIMATE_COUNT(attribute)\` |\`SELECT APPROXIMATE_COUNT({attribute/order_id})\`|
|
|
17
|
+
|two parameters |\`SELECT APPROXIMATE_COUNT(attribute, primary_key)\` |\`SELECT APPROXIMATE_COUNT({attribute/order_id}, {attribute/campaign_id})\`|
|
|
18
|
+
|with USING |\`SELECT APPROXIMATE_COUNT(attribute) USING primary_key\` |\`SELECT APPROXIMATE_COUNT({attribute/order_id}) USING {attribute/campaign_id}\`|
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Single-Parameter Version
|
|
22
|
+
|
|
23
|
+
The single-parameter version of APPROXIMATE_COUNT dynamically gets the context of
|
|
24
|
+
where to count from the visualization it is used in.
|
|
25
|
+
|
|
26
|
+
### Two-Parameter Version
|
|
27
|
+
|
|
28
|
+
In the two-parameter version, the context where to count the attribute
|
|
29
|
+
is determined explicitly by the second parameter - the primary key of
|
|
30
|
+
the dataset.
|
|
31
|
+
|
|
32
|
+
The primary key is connection point between datasets. It connects the
|
|
33
|
+
APPROXIMATE_COUNT function's first parameter to the dataset in which the count is
|
|
34
|
+
to take place.
|
|
35
|
+
|
|
36
|
+
### Specifying APPROXIMATE_COUNT Context Resolution with USING
|
|
37
|
+
|
|
38
|
+
In a metric, USING provides a hint for which context should be used.
|
|
39
|
+
The context for the computation of APPROXIMATE COUNT may be ambiguous if there are
|
|
40
|
+
multiple fact datasets in your logical data model that relate to a counted attribute.
|
|
41
|
+
|
|
42
|
+
The following image shows a model with the fact datasets \`Purchases\` and \`Sales\` and
|
|
43
|
+
has both datasets connected to the \`Store ID\` and \`Product ID\` attributes.
|
|
44
|
+
|
|
45
|
+

|
|
46
|
+
|
|
47
|
+
To create a metric that resolves with a specific context, you can specify USING in your metric like in the following
|
|
48
|
+
example: \`SELECT COUNT({label/inventory.productid}) USING {label/purchases.purchaseid}\`.
|
|
49
|
+
|
|
50
|
+
With this example, the visualization will show the approximate number of uniquely purchased products per store
|
|
51
|
+
because the attribute \`Purchase ID\` from the \`Purchases\` dataset is in the USING clause.
|
|
52
|
+
|
|
53
|
+
With the example model, if you build a visualization to display the approximate count of products per store with
|
|
54
|
+
\`SELECT COUNT({label/inventory.productid})\` and slice it by Store without specifying USING, it is ambiguous whether
|
|
55
|
+
the visualization is displaying the approximate number of unique products that have been purchased by store or the
|
|
56
|
+
approximate number of unique products that have been sold by the store.
|
|
57
|
+
|
|
58
|
+
The attribute in the USING clause can be any attribute which uniquely determines the correct context. For example, you
|
|
59
|
+
can also use an attribute from the \`Purchase Date\` dataset in the USING clause. This uses the \`Purchases\` dataset as
|
|
60
|
+
the context because the \`Sales\` dataset has no relationships to \`Purchase Date\`:
|
|
61
|
+
\`SELECT COUNT({label/inventory.productid}) USING {label/purchasedate.year}\``;
|