@ken-e/dataform-youtube 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +3 -0
- package/README.md +4 -0
- package/eslint.config.js +11 -0
- package/includes/column_descriptions.js +95 -0
- package/includes/constants.js +5 -0
- package/includes/definitions/sources/stg_ytc_annotation.js +91 -0
- package/includes/definitions/sources/stg_ytc_basic.js +109 -0
- package/includes/definitions/sources/stg_ytc_cards.js +89 -0
- package/includes/definitions/sources/stg_ytc_combined.js +97 -0
- package/includes/definitions/sources/stg_ytc_demographics.js +84 -0
- package/includes/definitions/sources/stg_ytc_device_os.js +90 -0
- package/includes/definitions/sources/stg_ytc_end_screens.js +69 -0
- package/includes/definitions/sources/stg_ytc_list_basic.js +91 -0
- package/includes/definitions/sources/stg_ytc_list_combined.js +92 -0
- package/includes/definitions/sources/stg_ytc_list_device_os.js +90 -0
- package/includes/definitions/sources/stg_ytc_list_playback.js +89 -0
- package/includes/definitions/sources/stg_ytc_list_province.js +91 -0
- package/includes/definitions/sources/stg_ytc_list_traffic_source.js +89 -0
- package/includes/definitions/sources/stg_ytc_lu_annotation_type.js +37 -0
- package/includes/definitions/sources/stg_ytc_lu_card_type.js +35 -0
- package/includes/definitions/sources/stg_ytc_lu_device_types.js +33 -0
- package/includes/definitions/sources/stg_ytc_lu_end_screen_element_type.js +36 -0
- package/includes/definitions/sources/stg_ytc_lu_operating_systems.js +57 -0
- package/includes/definitions/sources/stg_ytc_lu_playback_location.js +34 -0
- package/includes/definitions/sources/stg_ytc_lu_sharing_services.js +94 -0
- package/includes/definitions/sources/stg_ytc_lu_traffic_sources.js +50 -0
- package/includes/definitions/sources/stg_ytc_playback.js +90 -0
- package/includes/definitions/sources/stg_ytc_province.js +103 -0
- package/includes/definitions/sources/stg_ytc_share_platform.js +82 -0
- package/includes/definitions/sources/stg_ytc_subtitles.js +89 -0
- package/includes/definitions/sources/stg_ytc_traffic_source.js +107 -0
- package/includes/definitions/ytc_annotation.js +65 -0
- package/includes/definitions/ytc_basic.js +74 -0
- package/includes/definitions/ytc_cards.js +66 -0
- package/includes/definitions/ytc_combined.js +113 -0
- package/includes/definitions/ytc_demographics.js +69 -0
- package/includes/definitions/ytc_demographics_views.js +80 -0
- package/includes/definitions/ytc_device_os.js +80 -0
- package/includes/definitions/ytc_end_screens.js +65 -0
- package/includes/definitions/ytc_list_basic.js +84 -0
- package/includes/definitions/ytc_list_combined.js +97 -0
- package/includes/definitions/ytc_list_device_os.js +90 -0
- package/includes/definitions/ytc_list_playback.js +86 -0
- package/includes/definitions/ytc_list_province.js +83 -0
- package/includes/definitions/ytc_list_traffic_source.js +91 -0
- package/includes/definitions/ytc_playback.js +73 -0
- package/includes/definitions/ytc_province.js +71 -0
- package/includes/definitions/ytc_share_platform.js +76 -0
- package/includes/definitions/ytc_subtitles.js +69 -0
- package/includes/definitions/ytc_traffic_source.js +73 -0
- package/includes/helpers.js +8 -0
- package/includes/project_variables.js +15 -0
- package/index.js +312 -0
- package/package.json +30 -0
- package/prettier.config.js +14 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2025 by KEN-E, LLC
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
module.exports = (config) => {
|
|
6
|
+
// eslint-disable-next-line no-undef
|
|
7
|
+
return publish("stg_ytc_traffic_source", {
|
|
8
|
+
type: "incremental",
|
|
9
|
+
database: config.target.database,
|
|
10
|
+
schema: config.datasetStaging,
|
|
11
|
+
protected: config.protected,
|
|
12
|
+
tags: ["youtube", "source", "staging", "daily"],
|
|
13
|
+
bigquery: {
|
|
14
|
+
partitionBy: "interaction_date",
|
|
15
|
+
clusterBy: ["video_id", "traffic_source_type"],
|
|
16
|
+
},
|
|
17
|
+
assertions: {
|
|
18
|
+
// make sure rows have unique dimensions
|
|
19
|
+
uniqueKeys: [
|
|
20
|
+
[
|
|
21
|
+
"interaction_date",
|
|
22
|
+
"channel_id",
|
|
23
|
+
"video_id",
|
|
24
|
+
"live_or_on_demand",
|
|
25
|
+
"subscribed_status",
|
|
26
|
+
"country_code",
|
|
27
|
+
"traffic_source_type",
|
|
28
|
+
"traffic_source_detail",
|
|
29
|
+
],
|
|
30
|
+
],
|
|
31
|
+
// make sure source partition and data dates match
|
|
32
|
+
rowConditions: ["interaction_date = source_partition_date"],
|
|
33
|
+
},
|
|
34
|
+
description: "Staging table for YouTube Channel Traffic Source data",
|
|
35
|
+
assertions: {
|
|
36
|
+
// make sure rows have unique dimensions
|
|
37
|
+
uniqueKeys: [
|
|
38
|
+
[
|
|
39
|
+
"interaction_date",
|
|
40
|
+
"channel_id",
|
|
41
|
+
"video_id",
|
|
42
|
+
"live_or_on_demand",
|
|
43
|
+
"subscribed_status",
|
|
44
|
+
"country_code",
|
|
45
|
+
"traffic_source_type",
|
|
46
|
+
"traffic_source_detail",
|
|
47
|
+
],
|
|
48
|
+
],
|
|
49
|
+
// make sure source partition and data dates match
|
|
50
|
+
rowConditions: ["interaction_date = source_partition_date"],
|
|
51
|
+
},
|
|
52
|
+
description: "Staging table for YouTube Channel Traffic Source data",
|
|
53
|
+
})
|
|
54
|
+
.preOps(
|
|
55
|
+
(ctx) => `
|
|
56
|
+
declare source_date_checkpoint default (
|
|
57
|
+
select date("${config.startDate}")
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
--Set the incremental update checkpoint based on current max partition value minus lookback.
|
|
61
|
+
set source_date_checkpoint = (
|
|
62
|
+
${ctx.when(
|
|
63
|
+
ctx.incremental(),
|
|
64
|
+
`select
|
|
65
|
+
least(
|
|
66
|
+
(select date_sub(current_date(), interval ${config.daysBack} day)),
|
|
67
|
+
(select date_sub(max(source_partition_date), interval ${config.daysBack} day) from ${ctx.self()})
|
|
68
|
+
)`,
|
|
69
|
+
`select date("${config.startDate}")`,
|
|
70
|
+
)}
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
${ctx.when(
|
|
74
|
+
ctx.incremental(),
|
|
75
|
+
`delete ${ctx.self()} where source_partition_date > source_date_checkpoint`,
|
|
76
|
+
)}
|
|
77
|
+
`,
|
|
78
|
+
)
|
|
79
|
+
.query((ctx) =>
|
|
80
|
+
config.sources
|
|
81
|
+
.map((t) => {
|
|
82
|
+
return `
|
|
83
|
+
select
|
|
84
|
+
_PARTITIONDATE as source_partition_date,
|
|
85
|
+
parse_date('%Y%m%d', date) as interaction_date,
|
|
86
|
+
"${t.schema}" as site_nm,
|
|
87
|
+
current_timestamp() as updated_at,
|
|
88
|
+
channel_id,
|
|
89
|
+
video_id,
|
|
90
|
+
live_or_on_demand,
|
|
91
|
+
subscribed_status,
|
|
92
|
+
country_code,
|
|
93
|
+
traffic_source_type,
|
|
94
|
+
traffic_source_detail,
|
|
95
|
+
views,
|
|
96
|
+
watch_time_minutes,
|
|
97
|
+
average_view_duration_seconds,
|
|
98
|
+
average_view_duration_percentage,
|
|
99
|
+
red_views,
|
|
100
|
+
red_watch_time_minutes
|
|
101
|
+
from ${ctx.ref(t.database, t.schema, "p_channel_traffic_source_a2_" + t.suffix)}
|
|
102
|
+
where _PARTITIONDATE > source_date_checkpoint
|
|
103
|
+
`;
|
|
104
|
+
})
|
|
105
|
+
.join(" union all "),
|
|
106
|
+
);
|
|
107
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2025 by KEN-E, LLC
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const column_descriptions = require("../column_descriptions");
|
|
6
|
+
|
|
7
|
+
module.exports = (config) => {
|
|
8
|
+
// eslint-disable-next-line no-undef
|
|
9
|
+
return publish("ytc_annotation", {
|
|
10
|
+
type: "incremental",
|
|
11
|
+
schema: config.datasetIntermediate,
|
|
12
|
+
tags: ["youtube", "output", "daily"],
|
|
13
|
+
bigquery: {
|
|
14
|
+
partitionBy: "interaction_date",
|
|
15
|
+
clusterBy: ["video_id", "annotation_type"],
|
|
16
|
+
},
|
|
17
|
+
columns: column_descriptions.column_descriptions,
|
|
18
|
+
description: "YT Channel Annotation Report Table - Intermediate",
|
|
19
|
+
})
|
|
20
|
+
.preOps(
|
|
21
|
+
(ctx) => `
|
|
22
|
+
declare interaction_date_checkpoint default (
|
|
23
|
+
select date("${config.startDate}")
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
--Set the incremental update checkpoint based on current max partition value minus lookback.
|
|
27
|
+
set interaction_date_checkpoint = (
|
|
28
|
+
${ctx.when(
|
|
29
|
+
ctx.incremental(),
|
|
30
|
+
`select
|
|
31
|
+
least(
|
|
32
|
+
(select date_sub(current_date(), interval ${config.daysBack} day)),
|
|
33
|
+
(select date_sub(max(interaction_date), interval ${config.daysBack} day) from ${ctx.self()})
|
|
34
|
+
)`,
|
|
35
|
+
`select date("${config.startDate}")`,
|
|
36
|
+
)}
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
${ctx.when(
|
|
40
|
+
ctx.incremental(),
|
|
41
|
+
`delete ${ctx.self()} where interaction_date > interaction_date_checkpoint`,
|
|
42
|
+
)}
|
|
43
|
+
`,
|
|
44
|
+
)
|
|
45
|
+
.query(
|
|
46
|
+
(ctx) => `
|
|
47
|
+
|
|
48
|
+
select
|
|
49
|
+
stg.*,
|
|
50
|
+
annot.annotation_type_name,
|
|
51
|
+
ifnull(titles.video_title, stg.video_id) as video_title
|
|
52
|
+
from ${ctx.ref("stg_ytc_annotation")} as stg
|
|
53
|
+
left join ${ctx.ref("stg_ytc_lu_annotation_type")} as annot
|
|
54
|
+
using (annotation_type)
|
|
55
|
+
left join ${ctx.ref(
|
|
56
|
+
config.titlesProject,
|
|
57
|
+
config.titlesDataset,
|
|
58
|
+
config.titlesTable,
|
|
59
|
+
)} as titles
|
|
60
|
+
using (video_id)
|
|
61
|
+
where interaction_date > interaction_date_checkpoint
|
|
62
|
+
|
|
63
|
+
`,
|
|
64
|
+
);
|
|
65
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2025 by KEN-E, LLC
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const column_descriptions = require("../column_descriptions");
|
|
6
|
+
|
|
7
|
+
module.exports = (config) => {
|
|
8
|
+
// eslint-disable-next-line no-undef
|
|
9
|
+
return publish("ytc_basic", {
|
|
10
|
+
type: "incremental",
|
|
11
|
+
schema: config.datasetIntermediate,
|
|
12
|
+
tags: ["youtube", "output", "daily"],
|
|
13
|
+
bigquery: {
|
|
14
|
+
partitionBy: "interaction_date",
|
|
15
|
+
clusterBy: ["video_id"],
|
|
16
|
+
},
|
|
17
|
+
columns: column_descriptions.column_descriptions,
|
|
18
|
+
description: "YT Channel Basic Report Table - Intermediate",
|
|
19
|
+
})
|
|
20
|
+
.preOps(
|
|
21
|
+
(ctx) => `
|
|
22
|
+
-- Calculate date checkpoint for incremental updates.
|
|
23
|
+
|
|
24
|
+
declare interaction_date_checkpoint default (
|
|
25
|
+
select date("${config.startDate}")
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
--Set the incremental update checkpoint based on current max partition value minus lookback.
|
|
29
|
+
set interaction_date_checkpoint = (
|
|
30
|
+
${ctx.when(
|
|
31
|
+
ctx.incremental(),
|
|
32
|
+
`select
|
|
33
|
+
least(
|
|
34
|
+
(select date_sub(current_date(), interval ${config.daysBack} day)),
|
|
35
|
+
(select date_sub(max(interaction_date), interval ${config.daysBack} day) from ${ctx.self()})
|
|
36
|
+
)`,
|
|
37
|
+
`select date("${config.startDate}")`,
|
|
38
|
+
)}
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
${ctx.when(
|
|
42
|
+
ctx.incremental(),
|
|
43
|
+
`delete ${ctx.self()} where interaction_date > interaction_date_checkpoint`,
|
|
44
|
+
)}
|
|
45
|
+
`,
|
|
46
|
+
)
|
|
47
|
+
.query(
|
|
48
|
+
(ctx) => `
|
|
49
|
+
|
|
50
|
+
-- determine max possible viewing seconds per row so that percent viewed can be calculated downstream
|
|
51
|
+
with int_ex_titles as (
|
|
52
|
+
select
|
|
53
|
+
* except (source_partition_date),
|
|
54
|
+
views * safe_divide(average_view_duration_seconds, average_view_duration_percentage) as row_max_duration_seconds,
|
|
55
|
+
subscribers_gained - subscribers_lost as subscribers_net,
|
|
56
|
+
from ${ctx.ref("stg_ytc_basic")}
|
|
57
|
+
where interaction_date > interaction_date_checkpoint
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
select
|
|
61
|
+
int_ex_titles.*,
|
|
62
|
+
ifnull(titles.video_title, int_ex_titles.video_id) as video_title
|
|
63
|
+
from int_ex_titles
|
|
64
|
+
left join ${ctx.ref(
|
|
65
|
+
config.titlesProject,
|
|
66
|
+
config.titlesDataset,
|
|
67
|
+
config.titlesTable,
|
|
68
|
+
)} as titles
|
|
69
|
+
using
|
|
70
|
+
(video_id)
|
|
71
|
+
|
|
72
|
+
`,
|
|
73
|
+
);
|
|
74
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2025 by KEN-E, LLC
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const column_descriptions = require("../column_descriptions");
|
|
6
|
+
|
|
7
|
+
module.exports = (config) => {
|
|
8
|
+
// eslint-disable-next-line no-undef
|
|
9
|
+
return publish("ytc_cards", {
|
|
10
|
+
type: "incremental",
|
|
11
|
+
schema: config.datasetIntermediate,
|
|
12
|
+
tags: ["youtube", "output", "daily"],
|
|
13
|
+
bigquery: {
|
|
14
|
+
partitionBy: "interaction_date",
|
|
15
|
+
clusterBy: ["video_id", "card_type"],
|
|
16
|
+
},
|
|
17
|
+
columns: column_descriptions.column_descriptions,
|
|
18
|
+
description: "YT Channel Cards Report Table - Intermediate",
|
|
19
|
+
})
|
|
20
|
+
.preOps(
|
|
21
|
+
(ctx) => `
|
|
22
|
+
declare interaction_date_checkpoint default (
|
|
23
|
+
select date("${config.startDate}")
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
--Set the incremental update checkpoint based on current max partition value minus lookback.
|
|
27
|
+
set interaction_date_checkpoint = (
|
|
28
|
+
${ctx.when(
|
|
29
|
+
ctx.incremental(),
|
|
30
|
+
`select
|
|
31
|
+
least(
|
|
32
|
+
(select date_sub(current_date(), interval ${config.daysBack} day)),
|
|
33
|
+
(select date_sub(max(interaction_date), interval ${config.daysBack} day) from ${ctx.self()})
|
|
34
|
+
)`,
|
|
35
|
+
`select date("${config.startDate}")`,
|
|
36
|
+
)}
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
${ctx.when(
|
|
40
|
+
ctx.incremental(),
|
|
41
|
+
`delete ${ctx.self()} where interaction_date > interaction_date_checkpoint`,
|
|
42
|
+
)}
|
|
43
|
+
`,
|
|
44
|
+
)
|
|
45
|
+
.query(
|
|
46
|
+
(ctx) => `
|
|
47
|
+
|
|
48
|
+
select
|
|
49
|
+
stg.* except (source_partition_date),
|
|
50
|
+
ct.card_type_name,
|
|
51
|
+
ifnull(titles.video_title, stg.video_id) as video_title
|
|
52
|
+
from ${ctx.ref("stg_ytc_cards")} as stg
|
|
53
|
+
left join ${ctx.ref("stg_ytc_lu_card_type")} as ct
|
|
54
|
+
using (card_type)
|
|
55
|
+
left join ${ctx.ref(
|
|
56
|
+
config.titlesProject,
|
|
57
|
+
config.titlesDataset,
|
|
58
|
+
config.titlesTable,
|
|
59
|
+
)} as titles
|
|
60
|
+
using (video_id)
|
|
61
|
+
where interaction_date > interaction_date_checkpoint
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
`,
|
|
65
|
+
);
|
|
66
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2025 by KEN-E, LLC
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const column_descriptions = require("../column_descriptions");
|
|
6
|
+
|
|
7
|
+
module.exports = (config) => {
|
|
8
|
+
// eslint-disable-next-line no-undef
|
|
9
|
+
return publish("ytc_combined", {
|
|
10
|
+
type: "incremental",
|
|
11
|
+
schema: config.datasetIntermediate,
|
|
12
|
+
tags: ["youtube", "output", "daily"],
|
|
13
|
+
bigquery: {
|
|
14
|
+
partitionBy: "interaction_date",
|
|
15
|
+
clusterBy: ["video_id"],
|
|
16
|
+
},
|
|
17
|
+
columns: column_descriptions.column_descriptions,
|
|
18
|
+
description: "YT Channel Combined Report Table - Intermediate",
|
|
19
|
+
})
|
|
20
|
+
.preOps(
|
|
21
|
+
(ctx) => `
|
|
22
|
+
-- Calculate date checkpoint for incremental updates.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
declare interaction_date_checkpoint default (
|
|
26
|
+
select date("${config.startDate}")
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
--Set the incremental update checkpoint based on current max partition value minus lookback.
|
|
30
|
+
set interaction_date_checkpoint = (
|
|
31
|
+
${ctx.when(
|
|
32
|
+
ctx.incremental(),
|
|
33
|
+
`select
|
|
34
|
+
least(
|
|
35
|
+
(select date_sub(current_date(), interval ${config.daysBack} day)),
|
|
36
|
+
(select date_sub(max(interaction_date), interval ${config.daysBack} day) from ${ctx.self()})
|
|
37
|
+
)`,
|
|
38
|
+
`select date("${config.startDate}")`,
|
|
39
|
+
)}
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
${ctx.when(
|
|
43
|
+
ctx.incremental(),
|
|
44
|
+
`delete ${ctx.self()} where interaction_date > interaction_date_checkpoint`,
|
|
45
|
+
)}
|
|
46
|
+
`,
|
|
47
|
+
)
|
|
48
|
+
.query(
|
|
49
|
+
(ctx) => `
|
|
50
|
+
|
|
51
|
+
with int_ex_titles as (
|
|
52
|
+
select
|
|
53
|
+
* except (source_partition_date),
|
|
54
|
+
views * safe_divide(average_view_duration_seconds, average_view_duration_percentage) as row_max_duration_seconds,
|
|
55
|
+
from ${ctx.ref("stg_ytc_combined")}
|
|
56
|
+
where interaction_date > interaction_date_checkpoint
|
|
57
|
+
),
|
|
58
|
+
|
|
59
|
+
int_with_titles as (
|
|
60
|
+
select
|
|
61
|
+
int_ex_titles.*,
|
|
62
|
+
ifnull(titles.video_title, int_ex_titles.video_id) as video_title
|
|
63
|
+
from int_ex_titles
|
|
64
|
+
left join ${ctx.ref(
|
|
65
|
+
config.titlesProject,
|
|
66
|
+
config.titlesDataset,
|
|
67
|
+
config.titlesTable,
|
|
68
|
+
)} as titles
|
|
69
|
+
using
|
|
70
|
+
(video_id)
|
|
71
|
+
),
|
|
72
|
+
|
|
73
|
+
int_with_playback_location as (
|
|
74
|
+
select
|
|
75
|
+
int_with_titles.*,
|
|
76
|
+
playback_location.playback_location_name
|
|
77
|
+
from int_with_titles
|
|
78
|
+
left join ${ctx.ref("stg_ytc_lu_playback_location")} as playback_location
|
|
79
|
+
using
|
|
80
|
+
(playback_location_type)
|
|
81
|
+
),
|
|
82
|
+
|
|
83
|
+
int_with_device_type as (
|
|
84
|
+
select
|
|
85
|
+
int_with_playback_location.*,
|
|
86
|
+
device_types.device_name
|
|
87
|
+
from int_with_playback_location
|
|
88
|
+
left join ${ctx.ref("stg_ytc_lu_device_types")} as device_types
|
|
89
|
+
using
|
|
90
|
+
(device_type)
|
|
91
|
+
),
|
|
92
|
+
|
|
93
|
+
int_with_traffic_source as (
|
|
94
|
+
select
|
|
95
|
+
int_with_device_type.*,
|
|
96
|
+
traffic_sources.traffic_source_name
|
|
97
|
+
from int_with_device_type
|
|
98
|
+
left join ${ctx.ref("stg_ytc_lu_traffic_sources")} as traffic_sources
|
|
99
|
+
using
|
|
100
|
+
(traffic_source_type)
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
select
|
|
104
|
+
int_with_traffic_source.*,
|
|
105
|
+
operating_systems.operating_system_name
|
|
106
|
+
from int_with_traffic_source
|
|
107
|
+
left join ${ctx.ref("stg_ytc_lu_operating_systems")} as operating_systems
|
|
108
|
+
using
|
|
109
|
+
(operating_system)
|
|
110
|
+
|
|
111
|
+
`,
|
|
112
|
+
);
|
|
113
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2025 by KEN-E, LLC
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const column_descriptions = require("../column_descriptions");
|
|
6
|
+
|
|
7
|
+
module.exports = (config) => {
|
|
8
|
+
// eslint-disable-next-line no-undef
|
|
9
|
+
return publish("ytc_demographics", {
|
|
10
|
+
type: "incremental",
|
|
11
|
+
schema: config.datasetIntermediate,
|
|
12
|
+
tags: ["youtube", "output", "daily"],
|
|
13
|
+
bigquery: {
|
|
14
|
+
partitionBy: "interaction_date",
|
|
15
|
+
clusterBy: ["video_id", "age_group", "gender"],
|
|
16
|
+
},
|
|
17
|
+
columns: column_descriptions.column_descriptions,
|
|
18
|
+
description: "YT Channel Demographics Report Table - Intermediate",
|
|
19
|
+
})
|
|
20
|
+
.preOps(
|
|
21
|
+
(ctx) => `
|
|
22
|
+
declare interaction_date_checkpoint default (
|
|
23
|
+
select date("${config.startDate}")
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
--Set the incremental update checkpoint based on current max partition value minus lookback.
|
|
27
|
+
set interaction_date_checkpoint = (
|
|
28
|
+
${ctx.when(
|
|
29
|
+
ctx.incremental(),
|
|
30
|
+
`select
|
|
31
|
+
least(
|
|
32
|
+
(select date_sub(current_date(), interval ${config.daysBack} day)),
|
|
33
|
+
(select date_sub(max(interaction_date), interval ${config.daysBack} day) from ${ctx.self()})
|
|
34
|
+
)`,
|
|
35
|
+
`select date("${config.startDate}")`,
|
|
36
|
+
)}
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
${ctx.when(
|
|
40
|
+
ctx.incremental(),
|
|
41
|
+
`delete ${ctx.self()} where interaction_date > interaction_date_checkpoint`,
|
|
42
|
+
)}
|
|
43
|
+
`,
|
|
44
|
+
)
|
|
45
|
+
.query(
|
|
46
|
+
(ctx) => `
|
|
47
|
+
|
|
48
|
+
-- determine max possible viewing seconds per row so that percent viewed can be calculated downstream
|
|
49
|
+
with int_ex_titles as (
|
|
50
|
+
select
|
|
51
|
+
* except (source_partition_date)
|
|
52
|
+
from ${ctx.ref("stg_ytc_demographics")}
|
|
53
|
+
where interaction_date > interaction_date_checkpoint
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
select
|
|
57
|
+
int_ex_titles.*,
|
|
58
|
+
ifnull(titles.video_title, int_ex_titles.video_id) as video_title
|
|
59
|
+
from int_ex_titles
|
|
60
|
+
left join ${ctx.ref(
|
|
61
|
+
config.titlesProject,
|
|
62
|
+
config.titlesDataset,
|
|
63
|
+
config.titlesTable,
|
|
64
|
+
)} as titles
|
|
65
|
+
using (video_id)
|
|
66
|
+
|
|
67
|
+
`,
|
|
68
|
+
);
|
|
69
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2025 by KEN-E, LLC
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const column_descriptions = require("../column_descriptions");
|
|
6
|
+
|
|
7
|
+
module.exports = (config) => {
|
|
8
|
+
// eslint-disable-next-line no-undef
|
|
9
|
+
return publish("ytc_demographics_views", {
|
|
10
|
+
type: "incremental",
|
|
11
|
+
schema: config.datasetIntermediate,
|
|
12
|
+
tags: ["youtube", "output", "daily"],
|
|
13
|
+
bigquery: {
|
|
14
|
+
partitionBy: "interaction_date",
|
|
15
|
+
clusterBy: ["video_id", "age_group", "gender"],
|
|
16
|
+
},
|
|
17
|
+
columns: column_descriptions.column_descriptions,
|
|
18
|
+
description: "YT Channel Demographics Report Table - Intermediate",
|
|
19
|
+
})
|
|
20
|
+
.preOps(
|
|
21
|
+
(ctx) => `
|
|
22
|
+
declare interaction_date_checkpoint default (
|
|
23
|
+
select date("${config.startDate}")
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
--Set the incremental update checkpoint based on current max partition value minus lookback.
|
|
27
|
+
set interaction_date_checkpoint = (
|
|
28
|
+
${ctx.when(
|
|
29
|
+
ctx.incremental(),
|
|
30
|
+
`select
|
|
31
|
+
least(
|
|
32
|
+
(select date_sub(current_date(), interval ${config.daysBack} day)),
|
|
33
|
+
(select date_sub(max(interaction_date), interval ${config.daysBack} day) from ${ctx.self()})
|
|
34
|
+
)`,
|
|
35
|
+
`select date("${config.startDate}")`,
|
|
36
|
+
)}
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
${ctx.when(
|
|
40
|
+
ctx.incremental(),
|
|
41
|
+
`delete ${ctx.self()} where interaction_date > interaction_date_checkpoint`,
|
|
42
|
+
)}
|
|
43
|
+
`,
|
|
44
|
+
)
|
|
45
|
+
.query(
|
|
46
|
+
(ctx) => `
|
|
47
|
+
|
|
48
|
+
-- determine max possible viewing seconds per row so that percent viewed can be calculated downstream
|
|
49
|
+
with int_ex_titles as (
|
|
50
|
+
select
|
|
51
|
+
stg.* except (source_partition_date),
|
|
52
|
+
ytc_basic.views * stg.views_percentage/100 as views_with_demographics,
|
|
53
|
+
ytc_basic.views,
|
|
54
|
+
from ${ctx.ref("stg_ytc_demographics")} as stg
|
|
55
|
+
left join ${ctx.ref("ytc_basic")} as ytc_basic
|
|
56
|
+
using (
|
|
57
|
+
interaction_date,
|
|
58
|
+
channel_id,
|
|
59
|
+
video_id,
|
|
60
|
+
live_or_on_demand,
|
|
61
|
+
subscribed_status,
|
|
62
|
+
country_code
|
|
63
|
+
)
|
|
64
|
+
where interaction_date > interaction_date_checkpoint
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
select
|
|
68
|
+
int_ex_titles.*,
|
|
69
|
+
ifnull(titles.video_title, int_ex_titles.video_id) as video_title
|
|
70
|
+
from int_ex_titles
|
|
71
|
+
left join ${ctx.ref(
|
|
72
|
+
config.titlesProject,
|
|
73
|
+
config.titlesDataset,
|
|
74
|
+
config.titlesTable,
|
|
75
|
+
)} as titles
|
|
76
|
+
using (video_id)
|
|
77
|
+
|
|
78
|
+
`,
|
|
79
|
+
);
|
|
80
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This model has been prepared as part of the MARKETING PROPELLER project.
|
|
3
|
+
* Copyright (C) 2024 by DiveTeam, LLC
|
|
4
|
+
*
|
|
5
|
+
* Marketing Propeller models are not officially maintained, and are distributed on an
|
|
6
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const column_descriptions = require("../column_descriptions");
|
|
10
|
+
|
|
11
|
+
module.exports = (config) => {
|
|
12
|
+
// eslint-disable-next-line no-undef
|
|
13
|
+
return publish("ytc_device_os", {
|
|
14
|
+
type: "incremental",
|
|
15
|
+
schema: config.datasetIntermediate,
|
|
16
|
+
tags: ["youtube", "output", "daily"],
|
|
17
|
+
bigquery: {
|
|
18
|
+
partitionBy: "interaction_date",
|
|
19
|
+
clusterBy: ["video_id", "device_type", "operating_system"],
|
|
20
|
+
},
|
|
21
|
+
columns: column_descriptions.column_descriptions,
|
|
22
|
+
description: "YT Channel Device and OS Report Table - Intermediate",
|
|
23
|
+
})
|
|
24
|
+
.preOps(
|
|
25
|
+
(ctx) => `
|
|
26
|
+
declare interaction_date_checkpoint default (
|
|
27
|
+
select date("${config.startDate}")
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
--Set the incremental update checkpoint based on current max partition value minus lookback.
|
|
31
|
+
set interaction_date_checkpoint = (
|
|
32
|
+
${ctx.when(
|
|
33
|
+
ctx.incremental(),
|
|
34
|
+
`select
|
|
35
|
+
least(
|
|
36
|
+
(select date_sub(current_date(), interval ${config.daysBack} day)),
|
|
37
|
+
(select date_sub(max(interaction_date), interval ${config.daysBack} day) from ${ctx.self()})
|
|
38
|
+
)`,
|
|
39
|
+
`select date("${config.startDate}")`,
|
|
40
|
+
)}
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
${ctx.when(
|
|
44
|
+
ctx.incremental(),
|
|
45
|
+
`delete ${ctx.self()} where interaction_date > interaction_date_checkpoint`,
|
|
46
|
+
)}
|
|
47
|
+
`,
|
|
48
|
+
)
|
|
49
|
+
.query(
|
|
50
|
+
(ctx) => `
|
|
51
|
+
|
|
52
|
+
-- determine max possible viewing seconds per row so that percent viewed can be calculated downstream
|
|
53
|
+
with int_ex_titles as (
|
|
54
|
+
select
|
|
55
|
+
* except (source_partition_date),
|
|
56
|
+
views * safe_divide(average_view_duration_seconds, average_view_duration_percentage) as row_max_duration_seconds
|
|
57
|
+
from ${ctx.ref("stg_ytc_device_os")}
|
|
58
|
+
where interaction_date > interaction_date_checkpoint
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
select
|
|
62
|
+
int_ex_titles.*,
|
|
63
|
+
dt.device_name,
|
|
64
|
+
os.operating_system_name,
|
|
65
|
+
ifnull(titles.video_title, int_ex_titles.video_id) as video_title
|
|
66
|
+
from int_ex_titles
|
|
67
|
+
left join ${ctx.ref("stg_ytc_lu_device_types")} as dt
|
|
68
|
+
using (device_type)
|
|
69
|
+
left join ${ctx.ref("stg_ytc_lu_operating_systems")} as os
|
|
70
|
+
using (operating_system)
|
|
71
|
+
left join ${ctx.ref(
|
|
72
|
+
config.titlesProject,
|
|
73
|
+
config.titlesDataset,
|
|
74
|
+
config.titlesTable,
|
|
75
|
+
)} as titles
|
|
76
|
+
using (video_id)
|
|
77
|
+
|
|
78
|
+
`,
|
|
79
|
+
);
|
|
80
|
+
};
|