dbt - If there a macro like { % if is _incremental () %} that will allow me to run a block of code on the initial creation of the object? - dbt

dbt - If there a macro like { % if is _incremental () %} that will allow me to run a block of code on the initial creation of the object?
Also, where is a good resource to learn about existing macros in dbt?

Related

How to store long expression in separate file?

I'm building a Vue app where a user reactively generates an HTML page from certain selections. Therefore, there is a very long expression that produces said HTML page. This expression/template is stored in a separate .html file. I would like to have that expression as a computed property in my app, but not sure what's the best way. I want to be able to use either the {{ }} template syntax, or at least the syntax you get inside directives, rather than have to plaster this. in front of every property and method I use, which is what I'd have to do if I move the template to JS-land (e.g. a separate module or just directly define it in the computed property).
Right now I got it working, but it's extremely hacky:
let appSpec = {
/* [snip] */
computed: {
/* other computed properties and… */
html () {
return getAppHTML(this);
}
},
};
let sheetTemplate = await (await fetch("sheet-template.html")).text();
let templateVars = [
...Object.keys(INITIAL_DATA),
...Object.keys(appSpec.computed),
...Object.keys(appSpec.methods)
];
let getAppHTML = new Function(`{${ templateVars.join(", ") }}`, "return `" + sheetTemplate + "`");
/* ... */
I’m thinking there must be a better way to do this.
I don't want to inject the expression directly into the places it's going to be used in my app (e.g. <iframe :srcdoc>), because I want to have a property that corresponds to it (for watchers etc).
Note that I'm using the in-browser API, no build step, and I'd rather keep it that way.

Get Formatter for a Language

I want to make a relatively simple formatter in VS Code. Essentially, I have a bunch of *.md.j2 files (Jinja2 templates that ultimately become Markdown). I have the Better Jinja extension to render these, with the language jinja-md in VS Code.
I started off just wanting to use prettier's Markdown formatting and call it a day. I tried adding this to settings.json:
"[jinja-md]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
},
This does not work because esbenp.prettier-vscode does not register itself for the jinja-md type; it seems to have no "break glass" option to configure that.
This got me to thinking that it would be nice to make a formatter that ignored Jinja tag lines (e.g. {% if foo == 'bar' %}\n and then passed on the fragments to whatever the underlying file type formatter was. So basically I want to do something like:
vscode.languages.registerDocumentFormattingEditProvider('jinja-md', {
provideDocumentFormattingEdits(document: vscode.TextDocument): vscode.TextEdit[] {
// THIS IS THE QUESTION:
// vscode.languages.getFormatter is not a real method. I want to know
// how to pull off this concept.
mdFormatter = vscode.languages.getFormatter('md');
// Get segments between %}\n and \n{% and route them to the
// `mdFormatter` -- I think I know how to do this and am not bothering
// to write the code here.
}
});
Is this a thing I can do -- can I programmatically get from VSCode "the formatter user-configured for language X"?

How to add external Json as variables to shopify

In my online shop I want to show some more data about each product. I have managed to do this by adding an extra nodes to settings_data.json file. Like this:
{
"current": {
...
...
"7887193478": { //Product ID
"has-badge" => true,
"show-image" => false
...
},
"7887193479": { //Product ID
"has-badge" => true,
"show-image" => true
...
},
}
}
It is working and I am getting the data and showing it successfully.
The good thing about this solution is the page load is very fast.
But the problem is when some one updates the theme setting it overrides the settings_data.json file. Is there any way that I can import this extra json settings separably into my Shopify?
Please do not advise me with Metadata App. Metadata app is very slow and I am not interested to use it.
You can create a snippet products_data.liquid (or any other name you want) that stores the information you need, that's separate from the theme settings file, and won't be overwritten. Here's an example:
{% assign "7887193478-has-badge" = true %}
{% assign "7887193478-show-image" = false %}
{% assign "7887193479-has-badge" = true %}
{% assign "7887193479-show-image" = true %}
...
Then you'll want to include it somewhere in there theme.liquid file, above where you'd be using it:
{% include "products_data" %}
The downside is that it's not as clean in terms of data entry.

How to define global variables in Liquid?

Right now it seems variables I create can't communicate across files.
For Liquid you can pass a variable in the include
{%- assign global_var = "VALUE" -%}
{%- include 'YOUR_FILE' global_var: global_var -%}
For Shopify liquid you can do the following:
There is a work around this, you can set the global variable in the theme settings as an option config/settings_schema.json
{
"type": "text",
"id": "global_variable",
"label": "global variable",
"default": "Variable value"
},
and you can access it in the liquid files through
settings.global_variable
But the value is depending on what you enter in the theme settings.
If you need more dynamic way, you can set cart attributes through ajax like:
$.ajax({
type: 'POST',
url: '/cart/update.js',
data: { attributes: {'global_variable': "MY_VALUE"} },
dataType: 'json',
success: function(cart) {
location.reload();
}
});
And then access it any where in the theme through
cart.attributes.global_variable
But you have to update it each time the cart is empty
It seems the templates are loaded before the theme, so variables set in your layout/theme file wont be present in templates. Frustrating. However you can set them via a snippet, and include this snippet in your templates, layout, etc
In Liquid, as you want for example to determine the language and reuse this code in multiple occasions, you can create an file in the render folder.
instead of calling this using render, use include. Then it returns the assigned value. For example, create "render/current_language.liquid" :
{%- liquid
assign current_language = 'en'
if request.path contains '/nl/'
assign current_language = 'nl'
endif
%}
In a other file you can use as follows:
{%- liquid
include 'get-language'
if current_language == 'en'
else
endif
%}
As long as you use the
{% assign variable = value %}
you should be able to get the value anywhere in the file, and any file included after it has been assigned.
I believe this is the closest you can get to global variables in it.

in SQL, or Django ORM, what's the conventional way to have an ordered one-to-many?

Say I wanted to have a project, and one-to-many with to-do items, and wanted to re-order the to-do items arbitrarily?
In the past, I've added a numbered order field, and when someone wants to change the order, had to update all the items with their new order numbers. This is probably the worst approach, since it's not atomic & required several updates.
I notice Django has a multi-valued CommaSeparatedIntegerField which could contain the order by storing the ordered keys to the items in the to-do items table right in one field of the project table.
I've pondered a dewey decimal system where if I wanted to take item 3 and put it between 1 and 2 I would change it's order number to 1.5.
Something tells me there's an easier option that I'm missing though...
How would you give order to a one-to-many relationship?
I hate this problem ... and I run into it all the time.
For my most recent Django site we had a Newsletter which contained N Articles and, of course, order was important. I assigned the default order as ascending Article.id, but this failed if Articles were entered in something other than "correct" order.
On the Newsletter change_form.html page I added a little bit of jQuery magic using the Interface plugin (http://interface.eyecon.ro/). I show the titles of the associated Articles and the user can drag them around as they like. There is an onChange handler that recomputes the Article.id's in article_order field.
Enjoy,
Peter
For app=content, model=Newsletter, the following is in
templates/admin/content/newslettter/change_form.html
{% extends 'admin/change_form.html' %}
{% block form_top %}{% endblock %}
{% block extrahead %}{{ block.super }}
<script type="text/javascript" src="/media/js/jquery.js"></script>
<script type="text/javascript" src="/media/js/interface.js"></script>
<script>
$(document).ready(
function () {
$('ol.articles').Sortable(
{
accept : 'sortableitem',
helperclass : 'sorthelper',
activeclass : 'sortableactive',
hoverclass : 'sortablehover',
opacity: 0.8,
fx: 200,
axis: 'vertically',
opacity: 0.4,
revert: true,
trim: 'art_',
onchange:
function(list){
var arts = list[0].o[list[0].id];
var vals = new Array();
var a;
for (a in arts) {
vals[a] = arts[a].replace(/article./, '');
}
$('#id_article_order').attr('value', vals.join(','));
}
});
}
);
</script>
{% endblock %}
{% block after_related_objects %}
{% if original.articles %}
<style>
.sortableitem {
cursor:move;
width: 300px;
list-style-type: none;
}
</style>
<h4>Associated Articles</h4>
<ol class="articles" id="article_list">
{% for art in original.articles %}
<li id="article.{{art.id}}" class="sortableitem">{{art.title}}</li>
{% endfor %}
</ol>
{% endif %}
{% endblock %}
"added a numbered order field" - good.
"update all the items with their new order numbers" - avoidable.
Use numbers with gaps.
Floating point. That way, someone can insert "1.1" between 1 and 2. I find that this works nicely, as most people can understand how the sequencing works. And you don't have to worry too much about how much space to leave -- there's lots and lots of space between each number.
On the initial load, number the articles by the 100 or 1000 or something with space between each one. In this case, you have to guess how many digits to leave for reordering.
A comma-separated position. Initially, they're all (1,0), (2,0), (3,0), etc. But when you want to rearrange things, you might have to introduce (2,1) and (2,2) that go after (2,0) but before (3.0).
This looks kind of complicated, but some people like this kind of complexity. It's essentially the same as floating-point, except the single number is replace by a (whole-number, implicit-fraction) tuple. And this extends to handle hierarchies.
I have had this problem with two projects I've worked on in the last little while. For my example solution I have a "Form" that has many "Variables" assigned to it and the order of the variables on the form needs to be sortable. So I have implemented the following:
models.py
class Form(models.Model):
FormName = models.CharField(verbose_name="Form Name:", max_length=40)
VariableOrder = models.CommaSeparatedIntegerField(default="[]", editable=False)
def __unicode__(self):
return "%s" % (self.FormName)
class Variable(models.Model):
FormID = models.ForeignKey(Form, default=0, editable=False, related_name="Variable")
VarName = models.CharField(max_length=32, verbose_name="Name of variable in the database:")
def __unicode__(self):
return "%s" % self.VarName
The key from above is the VariableOrder CommaSeparatedIntegerField is where we are going to store the order of the Variables on the Form, and we are going to be using it as a python list, which is why the default is [].
For the template I render my Variables in an that we are going to make drag and drop sortable (the list elements I actually use have a ton more CSS related styling and information about the Variable).
<ul id="sortable">
{% for Variable in VarList %}
<li id="{{ Variable.id }}">{{ Variable }}</li>
{% endfor %}
</ul>
Now we are going to make the list drag and drop for the changing of order. For this to work you need to have the AJAX CSRF snippet from Django site in the head
$(function() {
$("#sortable" ).sortable({
placeholder: "ui-state-highlight",
update: function(event, ui){
$.ajax({
type:"POST",
url:"{% url builder.views.variableorder %}",
data: {Order: JSON.stringify($('#sortable').sortable('toArray')) },
success: function(data){
// Do stuff here - I don't do anything.
}
});
}
});
$( "#sortable" ).disableSelection();
});
The important part above is that "update" calls the function every time there is a position change of any of the variables, which sends the AJAX. toArray on sortable along with the JSON stringify gets us sending the top to bottom id's of each variable, which is used by the view as follows. Note: I keep the active Form object as a session variable, but in another case you would just need to call the Form object you were wanting to change the order of.
def variableorder(request):
if request.is_ajax():
Order = request.POST['Order']
updateOrder = request.session['FormID']
updateOrder.VariableOrder = newOrder
updateOrder.save()
request.session['FormID'] = Form.objects.get(id=updateOrder.id)
return HttpResponse("Order changed.")
else:
pass
The key of all of this is that you can use this CommaSeparatedIntegerField as a list by evaluating the string. For example:
Adding a Variable:
aForm = Form.objects.get(id=1)
currentOrder = aForm.VariableOrder
currentOrder = eval(currentOrder)
newVar = Variable(stuff in here)
newVar.save()
currentOrder.append(newVar.id)
aForm.VariableOrder = currentOrder
aForm.save()
Removing a Variable:
aForm = Form.objects.get(id=1)
currentOrder = aForm.VariableOrder
currentOrder = eval(currentOrder)
# Variable ID that we want to delete = 3
currentOrder.remove(3)
aForm.VariableOrder = currentOrder
aForm.save()
Rendering the Variables in Order:
aForm = Form.objects.get(id=1)
currentOrder = aForm.VariableOrder
currentOrder = eval(currentOrder)
VarList = []
for i in currentOrder:
VarList.append(Variable.objects.get(id=i))
This is a rough first draft of what I am going to use, but it is working well for me. The obvious first improvement being the evaluation to python list being a method in the class. eg.
def getVarOrder(self):
return eval(self.VariableOrder)
and then just call Form.getVarOrder() when want to manipulate the list. In any case hopefully this helps out.
JD
I've run into this so many times that I've settled on managing these dynamically in the BL or UI, and then just persisting the ordering to a purpose-built column once the user is happy. SQL is just intentially designed not to handle orderings, and it always fights back.
This is a late answer to the question, but I just wanted to chime in and point out that B-Trees are a great data structure for this sort of thing, especially if your access patterns don't require you to retrieve the entire list at once.
http://en.wikipedia.org/wiki/B-tree