@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.
Files changed (55) hide show
  1. package/.vscode/settings.json +3 -0
  2. package/README.md +4 -0
  3. package/eslint.config.js +11 -0
  4. package/includes/column_descriptions.js +95 -0
  5. package/includes/constants.js +5 -0
  6. package/includes/definitions/sources/stg_ytc_annotation.js +91 -0
  7. package/includes/definitions/sources/stg_ytc_basic.js +109 -0
  8. package/includes/definitions/sources/stg_ytc_cards.js +89 -0
  9. package/includes/definitions/sources/stg_ytc_combined.js +97 -0
  10. package/includes/definitions/sources/stg_ytc_demographics.js +84 -0
  11. package/includes/definitions/sources/stg_ytc_device_os.js +90 -0
  12. package/includes/definitions/sources/stg_ytc_end_screens.js +69 -0
  13. package/includes/definitions/sources/stg_ytc_list_basic.js +91 -0
  14. package/includes/definitions/sources/stg_ytc_list_combined.js +92 -0
  15. package/includes/definitions/sources/stg_ytc_list_device_os.js +90 -0
  16. package/includes/definitions/sources/stg_ytc_list_playback.js +89 -0
  17. package/includes/definitions/sources/stg_ytc_list_province.js +91 -0
  18. package/includes/definitions/sources/stg_ytc_list_traffic_source.js +89 -0
  19. package/includes/definitions/sources/stg_ytc_lu_annotation_type.js +37 -0
  20. package/includes/definitions/sources/stg_ytc_lu_card_type.js +35 -0
  21. package/includes/definitions/sources/stg_ytc_lu_device_types.js +33 -0
  22. package/includes/definitions/sources/stg_ytc_lu_end_screen_element_type.js +36 -0
  23. package/includes/definitions/sources/stg_ytc_lu_operating_systems.js +57 -0
  24. package/includes/definitions/sources/stg_ytc_lu_playback_location.js +34 -0
  25. package/includes/definitions/sources/stg_ytc_lu_sharing_services.js +94 -0
  26. package/includes/definitions/sources/stg_ytc_lu_traffic_sources.js +50 -0
  27. package/includes/definitions/sources/stg_ytc_playback.js +90 -0
  28. package/includes/definitions/sources/stg_ytc_province.js +103 -0
  29. package/includes/definitions/sources/stg_ytc_share_platform.js +82 -0
  30. package/includes/definitions/sources/stg_ytc_subtitles.js +89 -0
  31. package/includes/definitions/sources/stg_ytc_traffic_source.js +107 -0
  32. package/includes/definitions/ytc_annotation.js +65 -0
  33. package/includes/definitions/ytc_basic.js +74 -0
  34. package/includes/definitions/ytc_cards.js +66 -0
  35. package/includes/definitions/ytc_combined.js +113 -0
  36. package/includes/definitions/ytc_demographics.js +69 -0
  37. package/includes/definitions/ytc_demographics_views.js +80 -0
  38. package/includes/definitions/ytc_device_os.js +80 -0
  39. package/includes/definitions/ytc_end_screens.js +65 -0
  40. package/includes/definitions/ytc_list_basic.js +84 -0
  41. package/includes/definitions/ytc_list_combined.js +97 -0
  42. package/includes/definitions/ytc_list_device_os.js +90 -0
  43. package/includes/definitions/ytc_list_playback.js +86 -0
  44. package/includes/definitions/ytc_list_province.js +83 -0
  45. package/includes/definitions/ytc_list_traffic_source.js +91 -0
  46. package/includes/definitions/ytc_playback.js +73 -0
  47. package/includes/definitions/ytc_province.js +71 -0
  48. package/includes/definitions/ytc_share_platform.js +76 -0
  49. package/includes/definitions/ytc_subtitles.js +69 -0
  50. package/includes/definitions/ytc_traffic_source.js +73 -0
  51. package/includes/helpers.js +8 -0
  52. package/includes/project_variables.js +15 -0
  53. package/index.js +312 -0
  54. package/package.json +30 -0
  55. package/prettier.config.js +14 -0
@@ -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_end_screens", {
10
+ type: "incremental",
11
+ schema: config.datasetIntermediate,
12
+ tags: ["youtube", "output", "daily"],
13
+ bigquery: {
14
+ partitionBy: "interaction_date",
15
+ clusterBy: ["video_id", "end_screen_element_type"],
16
+ },
17
+ columns: column_descriptions.column_descriptions,
18
+ description: "YT Channel End Screen 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
+ et.end_screen_element_type_name,
51
+ ifnull(titles.video_title, stg.video_id) as video_title
52
+ from ${ctx.ref("stg_ytc_end_screens")} as stg
53
+ left join ${ctx.ref("stg_ytc_lu_end_screen_element_type")} as et
54
+ using (end_screen_element_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,84 @@
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_list_basic", {
10
+ type: "incremental",
11
+ schema: config.datasetIntermediate,
12
+ tags: ["youtube", "output", "daily"],
13
+ bigquery: {
14
+ partitionBy: "interaction_date",
15
+ clusterBy: ["playlist_id", "video_id"],
16
+ },
17
+ columns: column_descriptions.column_descriptions,
18
+ description: "YT Channel Playlist Basic 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
+ playlist_saves_added - playlist_saves_removed as playlist_saves_net
53
+ from ${ctx.ref("stg_ytc_list_basic")}
54
+ where interaction_date > interaction_date_checkpoint
55
+ ),
56
+
57
+ int_with_video_titles as (
58
+ select
59
+ int_ex_titles.*,
60
+ ifnull(titles.video_title, int_ex_titles.video_id) as video_title
61
+ from int_ex_titles
62
+ left join ${ctx.ref(
63
+ config.titlesProject,
64
+ config.titlesDataset,
65
+ config.titlesTable,
66
+ )} as titles
67
+ using (video_id)
68
+ )
69
+
70
+ select
71
+ int_with_video_titles.*,
72
+ ifnull(playlists.playlist_title, int_with_video_titles.playlist_id) as playlist_title
73
+ from int_with_video_titles
74
+ left join ${ctx.ref(
75
+ config.titlesProject,
76
+ config.titlesDataset,
77
+ config.playlistTable,
78
+ )} as playlists
79
+ using (playlist_id)
80
+
81
+
82
+ `,
83
+ );
84
+ };
@@ -0,0 +1,97 @@
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_list_combined", {
10
+ type: "incremental",
11
+ schema: config.datasetIntermediate,
12
+ tags: ["youtube", "output", "daily"],
13
+ bigquery: {
14
+ partitionBy: "interaction_date",
15
+ clusterBy: ["playlist_id", "video_id"],
16
+ },
17
+ columns: column_descriptions.column_descriptions,
18
+ description: "YT Channel Playlist Combined Report Table - Intermediate",
19
+ })
20
+ .preOps(
21
+ (ctx) => `
22
+ declare interaction_date_checkpoint default (
23
+ select date("${config.startDate}")
24
+ );
25
+
26
+ set interaction_date_checkpoint = (
27
+ ${ctx.when(
28
+ ctx.incremental(),
29
+ `select
30
+ least(
31
+ (select date_sub(current_date(), interval ${config.daysBack} day)),
32
+ (select date_sub(max(interaction_date), interval ${config.daysBack} day) from ${ctx.self()})
33
+ )`,
34
+ `select date("${config.startDate}")`,
35
+ )}
36
+ );
37
+
38
+ ${ctx.when(
39
+ ctx.incremental(),
40
+ `delete ${ctx.self()} where interaction_date > interaction_date_checkpoint`,
41
+ )}
42
+ `,
43
+ )
44
+ .query(
45
+ (ctx) => `
46
+
47
+ with int_with_lookup_names as (
48
+ select
49
+ base.* except(source_partition_date, device_type, operating_system, playback_location_type, traffic_source_type),
50
+ base.device_type,
51
+ base.operating_system,
52
+ base.playback_location_type,
53
+ base.traffic_source_type,
54
+ dt.device_name,
55
+ os.operating_system_name,
56
+ pl.playback_location_name,
57
+ ts.traffic_source_name,
58
+ playlist_saves_added - playlist_saves_removed as playlist_saves_net,
59
+ from ${ctx.ref("stg_ytc_list_combined")} as base
60
+ left join ${ctx.ref("stg_ytc_lu_device_types")} as dt
61
+ using (device_type)
62
+ left join ${ctx.ref("stg_ytc_lu_operating_systems")} as os
63
+ using (operating_system)
64
+ left join ${ctx.ref("stg_ytc_lu_playback_location")} as pl
65
+ using (playback_location_type)
66
+ left join ${ctx.ref("stg_ytc_lu_traffic_sources")} as ts
67
+ using (traffic_source_type)
68
+ where interaction_date > interaction_date_checkpoint
69
+ ),
70
+
71
+ int_with_video_titles as (
72
+ select
73
+ int_with_lookup_names.*,
74
+ ifnull(titles.video_title, int_with_lookup_names.video_id) as video_title
75
+ from int_with_lookup_names
76
+ left join ${ctx.ref(
77
+ config.titlesProject,
78
+ config.titlesDataset,
79
+ config.titlesTable,
80
+ )} as titles
81
+ using (video_id)
82
+ )
83
+
84
+ select
85
+ int_with_video_titles.*,
86
+ ifnull(playlists.playlist_title, int_with_video_titles.playlist_id) as playlist_title
87
+ from int_with_video_titles
88
+ left join ${ctx.ref(
89
+ config.titlesProject,
90
+ config.titlesDataset,
91
+ config.playlistTable,
92
+ )} as playlists
93
+ using (playlist_id)
94
+
95
+ `,
96
+ );
97
+ };
@@ -0,0 +1,90 @@
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_list_device_os", {
10
+ type: "incremental",
11
+ schema: config.datasetIntermediate,
12
+ tags: ["youtube", "output", "daily"],
13
+ bigquery: {
14
+ partitionBy: "interaction_date",
15
+ clusterBy: ["playlist_id", "video_id", "device_type", "operating_system"],
16
+ },
17
+ columns: column_descriptions.column_descriptions,
18
+ description:
19
+ "YT Channel Playlist Device and OS Report Table - Intermediate",
20
+ })
21
+ .preOps(
22
+ (ctx) => `
23
+ declare interaction_date_checkpoint default (
24
+ select date("${config.startDate}")
25
+ );
26
+
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
+ with int_with_device_os_names as (
49
+ select
50
+ base.* except(source_partition_date, device_type, operating_system),
51
+ base.device_type,
52
+ base.operating_system,
53
+ dt.device_name,
54
+ os.operating_system_name,
55
+ playlist_saves_added - playlist_saves_removed as playlist_saves_net
56
+ from ${ctx.ref("stg_ytc_list_device_os")} as base
57
+ left join ${ctx.ref("stg_ytc_lu_device_types")} as dt
58
+ using (device_type)
59
+ left join ${ctx.ref("stg_ytc_lu_operating_systems")} as os
60
+ using (operating_system)
61
+ where interaction_date > interaction_date_checkpoint
62
+ ),
63
+
64
+ int_with_video_titles as (
65
+ select
66
+ int_with_device_os_names.*,
67
+ ifnull(titles.video_title, int_with_device_os_names.video_id) as video_title
68
+ from int_with_device_os_names
69
+ left join ${ctx.ref(
70
+ config.titlesProject,
71
+ config.titlesDataset,
72
+ config.titlesTable,
73
+ )} as titles
74
+ using (video_id)
75
+ )
76
+
77
+ select
78
+ int_with_video_titles.*,
79
+ ifnull(playlists.playlist_title, int_with_video_titles.playlist_id) as playlist_title
80
+ from int_with_video_titles
81
+ left join ${ctx.ref(
82
+ config.titlesProject,
83
+ config.titlesDataset,
84
+ config.playlistTable,
85
+ )} as playlists
86
+ using (playlist_id)
87
+
88
+ `,
89
+ );
90
+ };
@@ -0,0 +1,86 @@
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_list_playback", {
10
+ type: "incremental",
11
+ schema: config.datasetIntermediate,
12
+ tags: ["youtube", "output", "daily"],
13
+ bigquery: {
14
+ partitionBy: "interaction_date",
15
+ clusterBy: ["playlist_id", "video_id", "playback_location_type"],
16
+ },
17
+ columns: column_descriptions.column_descriptions,
18
+ description:
19
+ "YT Channel Playlist Playback Location Report Table - Intermediate",
20
+ })
21
+ .preOps(
22
+ (ctx) => `
23
+ declare interaction_date_checkpoint default (
24
+ select date("${config.startDate}")
25
+ );
26
+
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
+ with int_with_playback_names as (
49
+ select
50
+ base.* except(source_partition_date, playback_location_type),
51
+ base.playback_location_type,
52
+ pl.playback_location_name,
53
+ playlist_saves_added - playlist_saves_removed as playlist_saves_net
54
+ from ${ctx.ref("stg_ytc_list_playback")} as base
55
+ left join ${ctx.ref("stg_ytc_lu_playback_location")} as pl
56
+ using (playback_location_type)
57
+ where interaction_date > interaction_date_checkpoint
58
+ ),
59
+
60
+ int_with_video_titles as (
61
+ select
62
+ int_with_playback_names.*,
63
+ ifnull(titles.video_title, int_with_playback_names.video_id) as video_title
64
+ from int_with_playback_names
65
+ left join ${ctx.ref(
66
+ config.titlesProject,
67
+ config.titlesDataset,
68
+ config.titlesTable,
69
+ )} as titles
70
+ using (video_id)
71
+ )
72
+
73
+ select
74
+ int_with_video_titles.*,
75
+ ifnull(playlists.playlist_title, int_with_video_titles.playlist_id) as playlist_title
76
+ from int_with_video_titles
77
+ left join ${ctx.ref(
78
+ config.titlesProject,
79
+ config.titlesDataset,
80
+ config.playlistTable,
81
+ )} as playlists
82
+ using (playlist_id)
83
+
84
+ `,
85
+ );
86
+ };
@@ -0,0 +1,83 @@
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_list_province", {
10
+ type: "incremental",
11
+ schema: config.datasetIntermediate,
12
+ tags: ["youtube", "output", "daily"],
13
+ bigquery: {
14
+ partitionBy: "interaction_date",
15
+ clusterBy: ["playlist_id", "video_id"],
16
+ },
17
+ columns: column_descriptions.column_descriptions,
18
+ description: "YT Channel Playlist Province 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
+ -- Add calculated fields and join with title tables
49
+ with int_ex_titles as (
50
+ select
51
+ * except (source_partition_date),
52
+ playlist_saves_added - playlist_saves_removed as playlist_saves_net
53
+ from ${ctx.ref("stg_ytc_list_province")}
54
+ where interaction_date > interaction_date_checkpoint
55
+ ),
56
+
57
+ int_with_video_titles as (
58
+ select
59
+ int_ex_titles.*,
60
+ ifnull(titles.video_title, int_ex_titles.video_id) as video_title
61
+ from int_ex_titles
62
+ left join ${ctx.ref(
63
+ config.titlesProject,
64
+ config.titlesDataset,
65
+ config.titlesTable,
66
+ )} as titles
67
+ using (video_id)
68
+ )
69
+
70
+ select
71
+ int_with_video_titles.*,
72
+ ifnull(playlists.playlist_title, int_with_video_titles.playlist_id) as playlist_title
73
+ from int_with_video_titles
74
+ left join ${ctx.ref(
75
+ config.titlesProject,
76
+ config.titlesDataset,
77
+ config.playlistTable,
78
+ )} as playlists
79
+ using (playlist_id)
80
+
81
+ `,
82
+ );
83
+ };
@@ -0,0 +1,91 @@
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_list_traffic_source", {
10
+ type: "incremental",
11
+ schema: config.datasetIntermediate,
12
+ tags: ["youtube", "output", "daily"],
13
+ bigquery: {
14
+ partitionBy: "interaction_date",
15
+ clusterBy: ["playlist_id", "video_id", "traffic_source_type"],
16
+ },
17
+ columns: column_descriptions.column_descriptions,
18
+ description:
19
+ "YT Channel Playlist Traffic Source Report Table - Intermediate",
20
+ })
21
+ .preOps(
22
+ (ctx) => `
23
+ declare interaction_date_checkpoint default (
24
+ select date("${config.startDate}")
25
+ );
26
+
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
+ with int_ex_titles as (
49
+ select
50
+ * except (source_partition_date),
51
+ playlist_saves_added - playlist_saves_removed as playlist_saves_net
52
+ from ${ctx.ref("stg_ytc_list_traffic_source")}
53
+ where interaction_date > interaction_date_checkpoint
54
+ ),
55
+
56
+ int_with_traffic_source as (
57
+ select
58
+ int_ex_titles.*,
59
+ ts.traffic_source_name
60
+ from int_ex_titles
61
+ left join ${ctx.ref("stg_ytc_lu_traffic_sources")} as ts
62
+ using (traffic_source_type)
63
+ ),
64
+
65
+ int_with_video_titles as (
66
+ select
67
+ int_with_traffic_source.*,
68
+ ifnull(titles.video_title, int_with_traffic_source.video_id) as video_title
69
+ from int_with_traffic_source
70
+ left join ${ctx.ref(
71
+ config.titlesProject,
72
+ config.titlesDataset,
73
+ config.titlesTable,
74
+ )} as titles
75
+ using (video_id)
76
+ )
77
+
78
+ select
79
+ int_with_video_titles.*,
80
+ ifnull(playlists.playlist_title, int_with_video_titles.playlist_id) as playlist_title
81
+ from int_with_video_titles
82
+ left join ${ctx.ref(
83
+ config.titlesProject,
84
+ config.titlesDataset,
85
+ config.playlistTable,
86
+ )} as playlists
87
+ using (playlist_id)
88
+
89
+ `,
90
+ );
91
+ };
@@ -0,0 +1,73 @@
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_playback", {
10
+ type: "incremental",
11
+ schema: config.datasetIntermediate,
12
+ tags: ["youtube", "output", "daily"],
13
+ bigquery: {
14
+ partitionBy: "interaction_date",
15
+ clusterBy: ["video_id", "playback_location_type"],
16
+ },
17
+ columns: column_descriptions.column_descriptions,
18
+ description: "YT Channel Playback Location 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
+ views * safe_divide(average_view_duration_seconds, average_view_duration_percentage) as row_max_duration_seconds
53
+ from ${ctx.ref("stg_ytc_playback")}
54
+ where interaction_date > interaction_date_checkpoint
55
+ )
56
+
57
+ select
58
+ int_ex_titles.*,
59
+ pl.playback_location_name,
60
+ ifnull(titles.video_title, int_ex_titles.video_id) as video_title
61
+ from int_ex_titles
62
+ left join ${ctx.ref("stg_ytc_lu_playback_location")} as pl
63
+ using (playback_location_type)
64
+ left join ${ctx.ref(
65
+ config.titlesProject,
66
+ config.titlesDataset,
67
+ config.titlesTable,
68
+ )} as titles
69
+ using (video_id)
70
+
71
+ `,
72
+ );
73
+ };