mirror of
https://github.com/dbt-labs/dbt-core
synced 2025-12-21 19:31:28 +00:00
Compare commits
3 Commits
adding-sem
...
cody/ibis
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
158aa81b0c | ||
|
|
5ddb088049 | ||
|
|
3edc9e53ad |
@@ -33,6 +33,8 @@ from dbt.node_types import NodeType, ModelLanguage
|
|||||||
from dbt.events.format import pluralize
|
from dbt.events.format import pluralize
|
||||||
import dbt.tracking
|
import dbt.tracking
|
||||||
|
|
||||||
|
from .language_provider import IbisProvider
|
||||||
|
|
||||||
graph_file_name = "graph.gpickle"
|
graph_file_name = "graph.gpickle"
|
||||||
|
|
||||||
|
|
||||||
@@ -369,7 +371,23 @@ class Compiler:
|
|||||||
)
|
)
|
||||||
compiled_node = _compiled_type_for(node).from_dict(data)
|
compiled_node = _compiled_type_for(node).from_dict(data)
|
||||||
|
|
||||||
if compiled_node.language == ModelLanguage.python:
|
compiled_node.was_ibis = False
|
||||||
|
if compiled_node.language == ModelLanguage.ibis:
|
||||||
|
|
||||||
|
provider = IbisProvider()
|
||||||
|
context = self._create_node_context(compiled_node, manifest, extra_context)
|
||||||
|
sql = provider.compile(node.raw_code, context)
|
||||||
|
|
||||||
|
# lol
|
||||||
|
compiled_node.compiled_code = sql
|
||||||
|
compiled_node.language = ModelLanguage.sql
|
||||||
|
|
||||||
|
# efficiency hack?
|
||||||
|
# doesn't seem to help much, if at all
|
||||||
|
compiled_node.was_ibis = True
|
||||||
|
|
||||||
|
elif compiled_node.language == ModelLanguage.python:
|
||||||
|
|
||||||
# TODO could we also 'minify' this code at all? just aesthetic, not functional
|
# TODO could we also 'minify' this code at all? just aesthetic, not functional
|
||||||
|
|
||||||
# quoating seems like something very specific to sql so far
|
# quoating seems like something very specific to sql so far
|
||||||
@@ -390,6 +408,7 @@ class Compiler:
|
|||||||
self.config.quoting = original_quoting
|
self.config.quoting = original_quoting
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
if not compiled_node.was_ibis:
|
||||||
context = self._create_node_context(compiled_node, manifest, extra_context)
|
context = self._create_node_context(compiled_node, manifest, extra_context)
|
||||||
compiled_node.compiled_code = jinja.get_rendered(
|
compiled_node.compiled_code = jinja.get_rendered(
|
||||||
node.raw_code,
|
node.raw_code,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class ParseFileType(StrEnum):
|
|||||||
Documentation = "docs"
|
Documentation = "docs"
|
||||||
Schema = "schema"
|
Schema = "schema"
|
||||||
Hook = "hook" # not a real filetype, from dbt_project.yml
|
Hook = "hook" # not a real filetype, from dbt_project.yml
|
||||||
|
language: str = "sql"
|
||||||
|
|
||||||
|
|
||||||
parse_file_type_to_parser = {
|
parse_file_type_to_parser = {
|
||||||
@@ -194,6 +195,7 @@ class SourceFile(BaseSourceFile):
|
|||||||
docs: List[str] = field(default_factory=list)
|
docs: List[str] = field(default_factory=list)
|
||||||
macros: List[str] = field(default_factory=list)
|
macros: List[str] = field(default_factory=list)
|
||||||
env_vars: List[str] = field(default_factory=list)
|
env_vars: List[str] = field(default_factory=list)
|
||||||
|
language: str = "sql"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def big_seed(cls, path: FilePath) -> "SourceFile":
|
def big_seed(cls, path: FilePath) -> "SourceFile":
|
||||||
|
|||||||
28
core/dbt/dbt_ibis/_dbt_ibis.py
Normal file
28
core/dbt/dbt_ibis/_dbt_ibis.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
"""
|
||||||
|
adapted from https://github.com/dbt-labs/dbt-core/pull/5982/files
|
||||||
|
"""
|
||||||
|
import ibis
|
||||||
|
|
||||||
|
|
||||||
|
def compile(code: str, context):
|
||||||
|
|
||||||
|
conn_params = {
|
||||||
|
"account": context["target"]["account"],
|
||||||
|
"user": context["target"]["user"],
|
||||||
|
"role": context["target"]["role"],
|
||||||
|
"warehouse": context["target"]["warehouse"],
|
||||||
|
"database": context["target"]["database"],
|
||||||
|
"schema": context["target"]["schema"],
|
||||||
|
"authenticator": "externalbrowser",
|
||||||
|
}
|
||||||
|
|
||||||
|
s = ibis.connect(
|
||||||
|
f"snowflake://{conn_params['user']}:_@{conn_params['account']}/{conn_params['database']}/{conn_params['schema']}?warehouse={conn_params['warehouse']}&role={conn_params['role']}&authenticator={conn_params['authenticator']}",
|
||||||
|
)
|
||||||
|
|
||||||
|
# the dirtiest code I've ever written?
|
||||||
|
# run the ibis code and compile the `model` variable
|
||||||
|
exec(code)
|
||||||
|
compiled = str(eval(f"ibis.{context['target']['type']}.compile(model)"))
|
||||||
|
|
||||||
|
return compiled
|
||||||
@@ -80,7 +80,7 @@ class SelectionCriteria:
|
|||||||
def default_method(cls, value: str) -> MethodName:
|
def default_method(cls, value: str) -> MethodName:
|
||||||
if _probably_path(value):
|
if _probably_path(value):
|
||||||
return MethodName.Path
|
return MethodName.Path
|
||||||
elif value.lower().endswith((".sql", ".py", ".csv")):
|
elif value.lower().endswith((".sql", ".py", ".csv", ".ibis")):
|
||||||
return MethodName.File
|
return MethodName.File
|
||||||
else:
|
else:
|
||||||
return MethodName.FQN
|
return MethodName.FQN
|
||||||
|
|||||||
23
core/dbt/language_provider.py
Normal file
23
core/dbt/language_provider.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
class LanguageProvider:
|
||||||
|
|
||||||
|
# def compile(self, code: str) -> ParsedNode:
|
||||||
|
def compile(self, code: str) -> str:
|
||||||
|
"""
|
||||||
|
Compile a given block into a ParsedNode.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError("compile")
|
||||||
|
|
||||||
|
|
||||||
|
class IbisProvider(LanguageProvider):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
# TODO: Uncomment when dbt-ibis is released
|
||||||
|
# if not dbt_ibis:
|
||||||
|
# raise ImportError(
|
||||||
|
# "dbt_ibis is required and not found; try running `pip install dbt-ibis`"
|
||||||
|
# )
|
||||||
|
pass
|
||||||
|
|
||||||
|
def compile(self, code: str, context) -> str:
|
||||||
|
from .dbt_ibis import _dbt_ibis as dbt_ibis
|
||||||
|
|
||||||
|
return dbt_ibis.compile(code, context)
|
||||||
@@ -68,3 +68,4 @@ class RunHookType(StrEnum):
|
|||||||
class ModelLanguage(StrEnum):
|
class ModelLanguage(StrEnum):
|
||||||
python = "python"
|
python = "python"
|
||||||
sql = "sql"
|
sql = "sql"
|
||||||
|
ibis = "ibis"
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ class ConfiguredParser(
|
|||||||
config[key] = [hooks.get_hook_dict(h) for h in config[key]]
|
config[key] = [hooks.get_hook_dict(h) for h in config[key]]
|
||||||
|
|
||||||
def _create_error_node(
|
def _create_error_node(
|
||||||
self, name: str, path: str, original_file_path: str, raw_code: str, language: str = "sql"
|
self, name: str, path: str, original_file_path: str, raw_code: str, language: str
|
||||||
) -> UnparsedNode:
|
) -> UnparsedNode:
|
||||||
"""If we hit an error before we've actually parsed a node, provide some
|
"""If we hit an error before we've actually parsed a node, provide some
|
||||||
level of useful information by attaching this to the exception.
|
level of useful information by attaching this to the exception.
|
||||||
@@ -189,7 +189,9 @@ class ConfiguredParser(
|
|||||||
"""
|
"""
|
||||||
if name is None:
|
if name is None:
|
||||||
name = block.name
|
name = block.name
|
||||||
if block.path.relative_path.endswith(".py"):
|
if block.path.relative_path.endswith(".ibis"):
|
||||||
|
language = ModelLanguage.ibis
|
||||||
|
elif block.path.relative_path.endswith(".py"):
|
||||||
language = ModelLanguage.python
|
language = ModelLanguage.python
|
||||||
else:
|
else:
|
||||||
# this is not ideal but we have a lot of tests to adjust if don't do it
|
# this is not ideal but we have a lot of tests to adjust if don't do it
|
||||||
@@ -223,6 +225,7 @@ class ConfiguredParser(
|
|||||||
path=path,
|
path=path,
|
||||||
original_file_path=block.path.original_file_path,
|
original_file_path=block.path.original_file_path,
|
||||||
raw_code=block.contents,
|
raw_code=block.contents,
|
||||||
|
language=language,
|
||||||
)
|
)
|
||||||
raise ParsingException(msg, node=node)
|
raise ParsingException(msg, node=node)
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import ast
|
|||||||
from dbt.dataclass_schema import ValidationError
|
from dbt.dataclass_schema import ValidationError
|
||||||
from dbt.exceptions import ParsingException, validator_error_message, UndefinedMacroException
|
from dbt.exceptions import ParsingException, validator_error_message, UndefinedMacroException
|
||||||
|
|
||||||
|
|
||||||
dbt_function_key_words = set(["ref", "source", "config", "get"])
|
dbt_function_key_words = set(["ref", "source", "config", "get"])
|
||||||
dbt_function_full_names = set(["dbt.ref", "dbt.source", "dbt.config", "dbt.config.get"])
|
dbt_function_full_names = set(["dbt.ref", "dbt.source", "dbt.config", "dbt.config.get"])
|
||||||
|
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ def read_files(project, files, parser_files, saved_files):
|
|||||||
project,
|
project,
|
||||||
files,
|
files,
|
||||||
project.model_paths,
|
project.model_paths,
|
||||||
[".sql", ".py"],
|
[".sql", ".py", ".ibis"],
|
||||||
ParseFileType.Model,
|
ParseFileType.Model,
|
||||||
saved_files,
|
saved_files,
|
||||||
dbt_ignore_spec,
|
dbt_ignore_spec,
|
||||||
|
|||||||
@@ -270,6 +270,7 @@ class SchemaParser(SimpleParser[GenericTestBlock, ParsedGenericTestNode]):
|
|||||||
path=path,
|
path=path,
|
||||||
original_file_path=target.original_file_path,
|
original_file_path=target.original_file_path,
|
||||||
raw_code=raw_code,
|
raw_code=raw_code,
|
||||||
|
language="sql",
|
||||||
)
|
)
|
||||||
raise ParsingException(msg, node=node) from exc
|
raise ParsingException(msg, node=node) from exc
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user