blob: f5a9818e2645e7ace12952586df4742cbf1a9379 [file] [log] [blame]
{"version":3,"sources":["webpack:///./src/pages/docs/installation/sql_templating.mdx"],"names":["_frontmatter","layoutProps","MDXLayout","DefaultLayout","MDXContent","components","props","mdxType","parentName","isMDXComponent"],"mappings":"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","file":"component---src-pages-docs-installation-sql-templating-mdx-176fbef389eef74e8b00.js","sourcesContent":["import * as React from 'react'\n /* @jsx mdx */\nimport { mdx } from '@mdx-js/react';\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\n\nimport DefaultLayout from \"/home/runner/work/superset/superset/docs/node_modules/gatsby-theme-docz/src/base/Layout.js\";\nexport const _frontmatter = {};\nconst layoutProps = {\n _frontmatter\n};\nconst MDXLayout = DefaultLayout;\nexport default function MDXContent({\n components,\n ...props\n}) {\n return <MDXLayout {...layoutProps} {...props} components={components} mdxType=\"MDXLayout\">\n\n\n <h2 {...{\n \"id\": \"sql-templating\"\n }}>{`SQL Templating`}</h2>\n <h3 {...{\n \"id\": \"jinja-templates\"\n }}>{`Jinja Templates`}</h3>\n <p>{`SQL Lab supports `}<a parentName=\"p\" {...{\n \"href\": \"https://jinja.palletsprojects.com/en/2.11.x/\"\n }}>{`Jinja templating`}</a>{` in queries. You'll\nneed to to overload the default Jinja context in your environment by defining the\nJINJA_CONTEXT_ADDONS in your superset configuration (`}<inlineCode parentName=\"p\">{`superset_config.py`}</inlineCode>{`). Objects referenced in\nthis dictionary are made available for users to use in their SQL code.`}</p>\n <pre><code parentName=\"pre\" {...{\n \"className\": \"language-python\"\n }}>{`JINJA_CONTEXT_ADDONS = {\n 'my_crazy_macro': lambda x: x*2,\n}\n`}</code></pre>\n <p>{`Besides default Jinja templating, SQL lab also supports self-defined template processor by setting\nthe `}<inlineCode parentName=\"p\">{`CUSTOM_TEMPLATE_PROCESSORS`}</inlineCode>{` in your superset configuration. The values in this dictionary\noverwrite the default Jinja template processors of the specified database engine. The example below\nconfigures a custom presto template processor which implements its own logic of processing macro\ntemplate with regex parsing. It uses the `}<inlineCode parentName=\"p\">{`$`}</inlineCode>{` style macro instead of `}<inlineCode parentName=\"p\">{`{{ }}`}</inlineCode>{` style in Jinja\ntemplating.`}</p>\n <p>{`By configuring it with `}<inlineCode parentName=\"p\">{`CUSTOM_TEMPLATE_PROCESSORS`}</inlineCode>{`, a SQL template on a presto database is\nprocessed by the custom one rather than the default one.`}</p>\n <pre><code parentName=\"pre\" {...{\n \"className\": \"language-python\"\n }}>{`def DATE(\n ts: datetime, day_offset: SupportsInt = 0, hour_offset: SupportsInt = 0\n) -> str:\n \"\"\"Current day as a string.\"\"\"\n day_offset, hour_offset = int(day_offset), int(hour_offset)\n offset_day = (ts + timedelta(days=day_offset, hours=hour_offset)).date()\n return str(offset_day)\n\nclass CustomPrestoTemplateProcessor(PrestoTemplateProcessor):\n \"\"\"A custom presto template processor.\"\"\"\n\n engine = \"presto\"\n\n def process_template(self, sql: str, **kwargs) -> str:\n \"\"\"Processes a sql template with $ style macro using regex.\"\"\"\n # Add custom macros functions.\n macros = {\n \"DATE\": partial(DATE, datetime.utcnow())\n } # type: Dict[str, Any]\n # Update with macros defined in context and kwargs.\n macros.update(self.context)\n macros.update(kwargs)\n\n def replacer(match):\n \"\"\"Expand $ style macros with corresponding function calls.\"\"\"\n macro_name, args_str = match.groups()\n args = [a.strip() for a in args_str.split(\",\")]\n if args == [\"\"]:\n args = []\n f = macros[macro_name[1:]]\n return f(*args)\n\n macro_names = [\"$\" + name for name in macros.keys()]\n pattern = r\"(%s)\\\\s*\\\\(([^()]*)\\\\)\" % \"|\".join(map(re.escape, macro_names))\n return re.sub(pattern, replacer, sql)\n\nCUSTOM_TEMPLATE_PROCESSORS = {\n CustomPrestoTemplateProcessor.engine: CustomPrestoTemplateProcessor\n}\n`}</code></pre>\n <p>{`SQL Lab also includes a live query validation feature with pluggable backends. You can configure\nwhich validation implementation is used with which database engine by adding a block like the\nfollowing to your configuration file:`}</p>\n <pre><code parentName=\"pre\" {...{\n \"className\": \"language-python\"\n }}>{`FEATURE_FLAGS = {\n 'SQL_VALIDATORS_BY_ENGINE': {\n 'presto': 'PrestoDBSQLValidator',\n }\n}\n`}</code></pre>\n <p>{`The available validators and names can be found in\n`}<a parentName=\"p\" {...{\n \"href\": \"https://github.com/apache/superset/tree/master/superset/sql_validators\"\n }}>{`sql_validators`}</a>{`.`}</p>\n <h3 {...{\n \"id\": \"available-macros\"\n }}>{`Available Macros`}</h3>\n <p>{`In this section, we'll walkthrough the pre-defined Jinja macros in Superset.`}</p>\n <p><strong parentName=\"p\">{`Current Username`}</strong></p>\n <p>{`The `}<inlineCode parentName=\"p\">{`{{ current_username() }}`}</inlineCode>{` macro returns the username of the currently logged in user.`}</p>\n <p>{`If you have caching enabled in your Superset configuration, then by defaul the the `}<inlineCode parentName=\"p\">{`username`}</inlineCode>{` value will be used\nby Superset when calculating the cache key. A cache key is a unique identifer that determines if there's a\ncache hit in the future and Superset can retrieve cached data.`}</p>\n <p>{`You can disable the inclusion of the `}<inlineCode parentName=\"p\">{`username`}</inlineCode>{` value in the calculation of the\ncache key by adding the following parameter to your Jinja code:`}</p>\n <pre><code parentName=\"pre\" {...{}}>{`{{ current_username(add_to_cache_keys=False) }}\n`}</code></pre>\n <p><strong parentName=\"p\">{`Current User ID`}</strong></p>\n <p>{`The `}<inlineCode parentName=\"p\">{`{{ current_user_id()}}`}</inlineCode>{` macro returns the user_id of the currently logged in user.`}</p>\n <p>{`If you have caching enabled in your Superset configuration, then by defaul the the `}<inlineCode parentName=\"p\">{`user_id`}</inlineCode>{` value will be used\nby Superset when calculating the cache key. A cache key is a unique identifer that determines if there's a\ncache hit in the future and Superset can retrieve cached data.`}</p>\n <p>{`You can disable the inclusion of the `}<inlineCode parentName=\"p\">{`user_id`}</inlineCode>{` value in the calculation of the\ncache key by adding the following parameter to your Jinja code:`}</p>\n <pre><code parentName=\"pre\" {...{}}>{`{{ current_user_id(add_to_cache_keys=False) }}\n`}</code></pre>\n <p><strong parentName=\"p\">{`Custom URL Parameters`}</strong></p>\n <p>{`The `}<inlineCode parentName=\"p\">{`{{ url_param('custom_variable') }}`}</inlineCode>{` macro lets you define arbitrary URL\nparameters and reference them in your SQL code.`}</p>\n <p>{`Here's a concrete example:`}</p>\n <ul>\n <li parentName=\"ul\">\n <p parentName=\"li\">{`You write the following query in SQL Lab:`}</p>\n <pre parentName=\"li\"><code parentName=\"pre\" {...{}}>{`SELECT count(*)\nFROM ORDERS\nWHERE country_code = '{{ url_param('countrycode') }}'\n`}</code></pre>\n </li>\n <li parentName=\"ul\">\n <p parentName=\"li\">{`You're hosting Superset at the domain `}<a parentName=\"p\" {...{\n \"href\": \"http://www.example.com\"\n }}>{`www.example.com`}</a>{` and you send your\ncoworker in Spain the following SQL Lab URL `}<inlineCode parentName=\"p\">{`www.example.com/superset/sqllab?countrycode=ES`}</inlineCode>{`\nand your coworker in the USA the following SQL Lab URL `}<inlineCode parentName=\"p\">{`www.example.com/superset/sqllab?countrycode=US`}</inlineCode></p>\n </li>\n <li parentName=\"ul\">\n <p parentName=\"li\">{`For your coworker in Spain, the SQL Lab query will be rendered as:`}</p>\n <pre parentName=\"li\"><code parentName=\"pre\" {...{}}>{`SELECT count(*)\nFROM ORDERS\nWHERE country_code = 'ES'\n`}</code></pre>\n </li>\n <li parentName=\"ul\">\n <p parentName=\"li\">{`For your coworker in the USA, the SQL Lab query will be rendered as:`}</p>\n <pre parentName=\"li\"><code parentName=\"pre\" {...{}}>{`SELECT count(*)\nFROM ORDERS\nWHERE country_code = 'US'\n`}</code></pre>\n </li>\n </ul>\n <p><strong parentName=\"p\">{`Explicitly Including Values in Cache Key`}</strong></p>\n <p>{`The `}<inlineCode parentName=\"p\">{`{{ cache_key_wrapper() }}`}</inlineCode>{` function explicitly instructs Superset to add a value to the\naccumulated list of values used in the the calculation of the cache key.`}</p>\n <p>{`This function is only needed when you want to wrap your own custom function return values\nin the cache key. You can gain more context\n`}<a parentName=\"p\" {...{\n \"href\": \"https://github.com/apache/superset/blob/efd70077014cbed62e493372d33a2af5237eaadf/superset/jinja_context.py#L133-L148\"\n }}>{`here`}</a>{`.`}</p>\n <p>{`Note that this function powers the caching of the `}<inlineCode parentName=\"p\">{`user_id`}</inlineCode>{` and `}<inlineCode parentName=\"p\">{`username`}</inlineCode>{` values\nin the `}<inlineCode parentName=\"p\">{`current_user_id()`}</inlineCode>{` and `}<inlineCode parentName=\"p\">{`current_username()`}</inlineCode>{` function calls (if you have caching enabled).`}</p>\n <p><strong parentName=\"p\">{`Filter Values`}</strong></p>\n <p>{`You can retrieve the value for a specific filter as a list using `}<inlineCode parentName=\"p\">{`{{ filter_values() }}`}</inlineCode>{`.`}</p>\n <p>{`This is useful if:`}</p>\n <ul>\n <li parentName=\"ul\">{`you want to use a filter component to filter a query where the name of filter component column doesn't match the one in the select statement`}</li>\n <li parentName=\"ul\">{`you want to have the ability for filter inside the main query for speed purposes`}</li>\n </ul>\n <p>{`Here's a concrete example:`}</p>\n <pre><code parentName=\"pre\" {...{}}>{`SELECT action, count(*) as times\nFROM logs\nWHERE\n action in ({{ \"'\" + \"','\".join(filter_values('action_type')) + \"'\" }})\nGROUP BY action\n`}</code></pre>\n <p>{`You can use thisfeature to reference the start & end datetimes from a time filter using:`}</p>\n <ul>\n <li parentName=\"ul\"><inlineCode parentName=\"li\">{`{{ from_dttm }}`}</inlineCode>{`: start datetime value`}</li>\n <li parentName=\"ul\"><inlineCode parentName=\"li\">{`{{ to_dttm }}`}</inlineCode>{`: end datetime value`}</li>\n </ul>\n <p><strong parentName=\"p\">{`Filters for a Specific Column`}</strong></p>\n <p>{`The `}<inlineCode parentName=\"p\">{`{{ get_filters() }}`}</inlineCode>{` macro returns the filters applied to a given column. In addition to\nreturning the values (similar to how `}<inlineCode parentName=\"p\">{`filter_values()`}</inlineCode>{` does), the `}<inlineCode parentName=\"p\">{`get_filters()`}</inlineCode>{` macro\nreturns the operator specified in the Explore UI.`}</p>\n <p>{` This is useful if:`}</p>\n <ul>\n <li parentName=\"ul\">{`you want to handle more than the IN operator in your SQL clause`}</li>\n <li parentName=\"ul\">{`you want to handle generating custom SQL conditions for a filter`}</li>\n <li parentName=\"ul\">{`you want to have the ability to filter inside the main query for speed purposes`}</li>\n </ul>\n <p>{`Here's a concrete example:`}</p>\n <pre><code parentName=\"pre\" {...{}}>{` WITH RECURSIVE\n superiors(employee_id, manager_id, full_name, level, lineage) AS (\n SELECT\n employee_id,\n manager_id,\n full_name,\n 1 as level,\n employee_id as lineage\n FROM\n employees\n WHERE\n 1=1\n\n {# Render a blank line #}\n {%- for filter in get_filters('full_name', remove_filter=True) -%}\n\n {%- if filter.get('op') == 'IN' -%}\n AND\n full_name IN ( {{ \"'\" + \"', '\".join(filter.get('val')) + \"'\" }} )\n {%- endif -%}\n\n {%- if filter.get('op') == 'LIKE' -%}\n AND\n full_name LIKE {{ \"'\" + filter.get('val') + \"'\" }}\n {%- endif -%}\n\n {%- endfor -%}\n UNION ALL\n SELECT\n e.employee_id,\n e.manager_id,\n e.full_name,\n s.level + 1 as level,\n s.lineage\n FROM\n employees e,\n superiors s\n WHERE s.manager_id = e.employee_id\n )\n\n SELECT\n employee_id, manager_id, full_name, level, lineage\n FROM\n superiors\n order by lineage, level\n`}</code></pre>\n\n </MDXLayout>;\n}\n;\nMDXContent.isMDXComponent = true;\n "],"sourceRoot":""}