12
12
import time
13
13
import sqlparse
14
14
15
- CompilableEntities = ["models" , "tests" , "archives" , "analyses" ]
15
+ CompilableEntities = ["models" , "data tests" , "schema tests" , "archives" , "analyses" ]
16
16
17
17
class Compiler (object ):
18
18
def __init__ (self , project , create_template_class ):
@@ -60,6 +60,10 @@ def project_schemas(self):
60
60
source_paths = self .project .get ('source-paths' , [])
61
61
return Source (self .project ).get_schemas (source_paths )
62
62
63
+ def project_tests (self ):
64
+ source_paths = self .project .get ('test-paths' , [])
65
+ return Source (self .project ).get_tests (source_paths )
66
+
63
67
def analysis_sources (self , project ):
64
68
paths = project .get ('analysis-paths' , [])
65
69
return Source (project ).get_analyses (paths )
@@ -109,7 +113,7 @@ def model_can_reference(self, src_model, other_model):
109
113
return other_model .own_project ['name' ] == src_model .own_project ['name' ] \
110
114
or src_model .own_project ['name' ] == src_model .project ['name' ]
111
115
112
- def __ref (self , linker , ctx , model , all_models ):
116
+ def __ref (self , linker , ctx , model , all_models , add_dependency = True ):
113
117
schema = ctx ['env' ]['schema' ]
114
118
115
119
source_model = tuple (model .fqn )
@@ -138,7 +142,7 @@ def do_ref(*args):
138
142
139
143
# this creates a trivial cycle -- should this be a compiler error?
140
144
# we can still interpolate the name w/o making a self-cycle
141
- if source_model == other_model_fqn :
145
+ if source_model == other_model_fqn or not add_dependency :
142
146
pass
143
147
else :
144
148
linker .dependency (source_model , other_model_fqn )
@@ -163,14 +167,15 @@ def wrapped_do_ref(*args):
163
167
164
168
return wrapped_do_ref
165
169
166
- def get_context (self , linker , model , models ):
170
+ def get_context (self , linker , model , models , add_dependency = False ):
167
171
context = self .project .context ()
168
172
169
173
# built-ins
170
- context ['ref' ] = self .__ref (linker , context , model , models )
174
+ context ['ref' ] = self .__ref (linker , context , model , models , add_dependency )
171
175
context ['config' ] = self .__model_config (model , linker )
172
176
context ['this' ] = This (context ['env' ]['schema' ], model .immediate_name , model .name )
173
177
context ['var' ] = Var (model , context = context )
178
+ context ['target' ] = self .project .get ('run-target' )
174
179
175
180
# these get re-interpolated at runtime!
176
181
context ['run_started_at' ] = '{{ run_started_at }}'
@@ -185,15 +190,15 @@ def get_context(self, linker, model, models):
185
190
186
191
return context
187
192
188
- def compile_model (self , linker , model , models ):
193
+ def compile_model (self , linker , model , models , add_dependency = True ):
189
194
try :
190
195
fs_loader = jinja2 .FileSystemLoader (searchpath = model .root_dir )
191
196
jinja = jinja2 .Environment (loader = fs_loader )
192
197
193
198
# this is a dumb jinja2 bug -- on windows, forward slashes are EXPECTED
194
199
posix_filepath = '/' .join (split_path (model .rel_filepath ))
195
200
template = jinja .get_template (posix_filepath )
196
- context = self .get_context (linker , model , models )
201
+ context = self .get_context (linker , model , models , add_dependency = add_dependency )
197
202
198
203
rendered = template .render (context )
199
204
except jinja2 .exceptions .TemplateSyntaxError as e :
@@ -329,6 +334,23 @@ def compile_schema_tests(self, linker):
329
334
330
335
return written_tests
331
336
337
+ def compile_data_tests (self , linker ):
338
+ tests = self .project_tests ()
339
+
340
+ all_models = self .get_models ()
341
+ enabled_models = [model for model in all_models if model .is_enabled ]
342
+
343
+ written_tests = []
344
+ for data_test in tests :
345
+ serialized = data_test .serialize ()
346
+ linker .update_node_data (tuple (data_test .fqn ), serialized )
347
+ query = self .compile_model (linker , data_test , enabled_models , add_dependency = False )
348
+ wrapped = data_test .render (query )
349
+ self .__write (data_test .build_path (), wrapped )
350
+ written_tests .append (data_test )
351
+
352
+ return written_tests
353
+
332
354
def generate_macros (self , all_macros ):
333
355
def do_gen (ctx ):
334
356
macros = []
@@ -351,14 +373,20 @@ def compile_archives(self):
351
373
self .write_graph_file (linker , 'archive' )
352
374
return all_archives
353
375
376
+ def get_models (self ):
377
+ all_models = self .model_sources (this_project = self .project )
378
+ for project in dependency_projects (self .project ):
379
+ all_models .extend (self .model_sources (this_project = self .project , own_project = project ))
380
+
381
+ return all_models
382
+
354
383
def compile (self , dry = False ):
355
384
linker = Linker ()
356
385
357
- all_models = self .model_sources ( this_project = self . project )
386
+ all_models = self .get_models ( )
358
387
all_macros = self .get_macros (this_project = self .project )
359
388
360
389
for project in dependency_projects (self .project ):
361
- all_models .extend (self .model_sources (this_project = self .project , own_project = project ))
362
390
all_macros .extend (self .get_macros (this_project = self .project , own_project = project ))
363
391
364
392
self .macro_generator = self .generate_macros (all_macros )
@@ -369,6 +397,7 @@ def compile(self, dry=False):
369
397
370
398
# TODO : only compile schema tests for enabled models
371
399
written_schema_tests = self .compile_schema_tests (linker )
400
+ written_data_tests = self .compile_data_tests (linker )
372
401
373
402
self .validate_models_unique (compiled_models )
374
403
self .validate_models_unique (written_schema_tests )
@@ -384,7 +413,8 @@ def compile(self, dry=False):
384
413
385
414
return {
386
415
"models" : len (written_models ),
387
- "tests" : len (written_schema_tests ),
416
+ "schema tests" : len (written_schema_tests ),
417
+ "data tests" : len (written_data_tests ),
388
418
"archives" : len (compiled_archives ),
389
419
"analyses" : len (written_analyses )
390
420
}
0 commit comments