dataform-ads-toolkit
v1.0.0
Published
Shared Dataform utilities and a cross-channel canonical ad-reporting contract for paid-media (facebook, linkedin, dv360, ...) Dataform projects.
Readme
dataform-ads-toolkit
Shared JavaScript utilities and a cross-channel canonical ad-reporting contract for Dataform projects that model paid-media data (Facebook, LinkedIn, DV360, SA360, Snapchat, Pinterest, Reddit, …).
The idea: keep one independent Dataform repo per ad platform, but factor the handful of pieces that are identical across all of them into this package, consumed via package.json — so a change is made once and versioned, instead of copy-pasted into every repo.
What lives here vs. in each repo. Per-channel field definitions differ by platform and stay in each repo. This package holds only what is truly shared: the canonical contract and the generic builders/mechanics.
Install
npm install dataform-ads-toolkitThen add it to a Dataform repo's package.json (e.g. "dataform-ads-toolkit": "^1.0.0"); Dataform installs declared npm dependencies during compilation, so require("dataform-ads-toolkit") works from any includes/ or definitions/*.sqlx file.
Modules
const toolkit = require("dataform-ads-toolkit");toolkit.canonical — the cross-channel contract
The agreed 16-column schema every <channel>_ad_report_canonical view exposes so a unified repo can UNION ALL them.
adReportCanonical— ordered column list[{ name, type, description }].adReportCanonicalColumnDocs()—{name: description}map for a model'sconfig { columns }.adReportCanonicalSelectList()— contract-ordered, comma-separated column list for an explicitSELECT.canonicalContractAssertionSql({ database, schema, table })— full assertion query that diffs a view's live columns against the contract (parameterized by location, so each channel's assertion is a one-liner).
toolkit.docs — column-doc builder mechanics
compose(...groups)— merge field groups into one column map.omit(obj, keys)— drop keys when a rollup table has fewer columns.
toolkit.latest — slowly-changing-dimension dedup
latestRecordSql({ source, partitionBy, orderBy, alias })— theROW_NUMBER() … AS rnbody for a Fivetran*_historylatest-record view.
toolkit.isolation — client-data isolation
clientIsolation({ column, values })— returns a matchingWHEREfilter androwConditionfrom one definition, so a client-specific table's filter and its guardrail assertion can never drift.sqlList(values)— SQL list literal (quotes strings, leaves numbers bare for id-based isolation).
Usage examples
Canonical view (<channel>_ad_report_canonical.sqlx):
config {
type: "view",
columns: require("dataform-ads-toolkit").canonical.adReportCanonicalColumnDocs()
}
SELECT 'facebook' AS channel, ... FROM ${ref("ad_report")}Contract assertion (assert_<channel>_canonical_contract.sqlx):
config { type: "assertion", dependencies: ["facebook_ad_report_canonical"] }
${require("dataform-ads-toolkit").canonical.canonicalContractAssertionSql({
database: "your-project", schema: "your_dataset", table: "facebook_ad_report_canonical"
})}Client isolation (a client-scoped table):
js {
const CLIENT = require("dataform-ads-toolkit").isolation.clientIsolation({
column: "Account_Name",
values: require("../includes/constants.js").CLIENT_ACCOUNT_NAMES
});
}
config { type: "table", assertions: { rowConditions: [ CLIENT.rowCondition ] } }
SELECT * FROM ${ref("...")} ${CLIENT.where}Versioning
The canonical contract is the high-stakes export: a column add/remove/rename is a breaking change for every consumer's UNION ALL. Bump the major version for any change to adReportCanonical's column set, and roll consumers forward one at a time (each guarded by its contract assertion). Consumers should pin a version range (e.g. ^1.0.0).
Development
npm test # node test/smoke.js — exercises every module