@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,33 @@
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_lu_device_types", {
8
+ type: "table",
9
+ database: config.target.database,
10
+ schema: config.datasetOutput,
11
+ protected: config.protected,
12
+ tags: ["youtube", "lookup", "device"],
13
+ description:
14
+ "Lookup table for device types and their descriptions from YouTube Analytics API.",
15
+ }).query(
16
+ (ctx) =>
17
+ `
18
+
19
+ select
20
+ cast(device_type as int) as device_type,
21
+ device as device_name
22
+ from unnest([
23
+ struct(100 as device_type, "Unknown" as device),
24
+ struct(101 as device_type, "Computer" as device),
25
+ struct(102 as device_type, "TV" as device),
26
+ struct(103 as device_type, "Game console" as device),
27
+ struct(104 as device_type, "Mobile phone" as device),
28
+ struct(105 as device_type, "Tablet" as device)
29
+ ]) as device_types
30
+
31
+ `,
32
+ );
33
+ };
@@ -0,0 +1,36 @@
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_lu_end_screen_element_type", {
8
+ type: "table",
9
+ database: config.target.database,
10
+ schema: config.datasetOutput,
11
+ protected: config.protected,
12
+ tags: ["youtube", "lookup", "end_screen_element_type"],
13
+ description: "Lookup table for YouTube end screen element types.",
14
+ }).query(
15
+ (ctx) =>
16
+ `
17
+
18
+ select
19
+ cast(element_type as int) as end_screen_element_type,
20
+ element_type_name as end_screen_element_type_name
21
+ from unnest([
22
+ struct(501 as element_type, "Video" as element_type_name),
23
+ struct(502 as element_type, "Playlist" as element_type_name),
24
+ struct(503 as element_type, "Website" as element_type_name),
25
+ struct(504 as element_type, "Channel" as element_type_name),
26
+ struct(505 as element_type, "Subscribe" as element_type_name),
27
+ struct(506 as element_type, "Associated" as element_type_name),
28
+ struct(507 as element_type, "Crowdfunding" as element_type_name),
29
+ struct(508 as element_type, "Merchandise" as element_type_name),
30
+ struct(509 as element_type, "Recent upload" as element_type_name),
31
+ struct(510 as element_type, "Best for viewer" as element_type_name)
32
+ ]) as element_types
33
+
34
+ `,
35
+ );
36
+ };
@@ -0,0 +1,57 @@
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_lu_operating_systems", {
8
+ type: "table",
9
+ database: config.target.database,
10
+ schema: config.datasetOutput,
11
+ protected: config.protected,
12
+ tags: ["youtube", "lookup", "operating_system"],
13
+ description:
14
+ "Lookup table for operating system types and their names from YouTube Analytics API.",
15
+ }).query(
16
+ (ctx) =>
17
+ `
18
+
19
+ select
20
+ cast(operating_system as int) as operating_system,
21
+ operating_system_name
22
+ from unnest([
23
+ struct(1 as operating_system, "Other" as operating_system_name),
24
+ struct(2 as operating_system, "Windows" as operating_system_name),
25
+ struct(3 as operating_system, "Windows Mobile" as operating_system_name),
26
+ struct(4 as operating_system, "Android" as operating_system_name),
27
+ struct(5 as operating_system, "iOS" as operating_system_name),
28
+ struct(6 as operating_system, "Symbian" as operating_system_name),
29
+ struct(7 as operating_system, "Blackberry" as operating_system_name),
30
+ struct(9 as operating_system, "Macintosh" as operating_system_name),
31
+ struct(10 as operating_system, "PlayStation" as operating_system_name),
32
+ struct(11 as operating_system, "Bada" as operating_system_name),
33
+ struct(12 as operating_system, "WebOS" as operating_system_name),
34
+ struct(13 as operating_system, "Linux" as operating_system_name),
35
+ struct(14 as operating_system, "Hiptop" as operating_system_name),
36
+ struct(15 as operating_system, "MeeGo" as operating_system_name),
37
+ struct(16 as operating_system, "Wii" as operating_system_name),
38
+ struct(17 as operating_system, "Xbox" as operating_system_name),
39
+ struct(18 as operating_system, "PlayStation Vita" as operating_system_name),
40
+ struct(19 as operating_system, "Smart TV" as operating_system_name),
41
+ struct(20 as operating_system, "Nintendo 3DS" as operating_system_name),
42
+ struct(21 as operating_system, "Chromecast" as operating_system_name),
43
+ struct(22 as operating_system, "Tizen" as operating_system_name),
44
+ struct(23 as operating_system, "Firefox" as operating_system_name),
45
+ struct(24 as operating_system, "RealMedia" as operating_system_name),
46
+ struct(25 as operating_system, "KaiOS" as operating_system_name),
47
+ struct(26 as operating_system, "Roku" as operating_system_name),
48
+ struct(27 as operating_system, "Nintendo Switch" as operating_system_name),
49
+ struct(28 as operating_system, "Apple tvOS" as operating_system_name),
50
+ struct(29 as operating_system, "Fire OS" as operating_system_name),
51
+ struct(30 as operating_system, "ChromeOS" as operating_system_name),
52
+ struct(31 as operating_system, "Vidaa" as operating_system_name)
53
+ ]) as operating_systems
54
+
55
+ `,
56
+ );
57
+ };
@@ -0,0 +1,34 @@
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_lu_playback_location", {
8
+ type: "table",
9
+ database: config.target.database,
10
+ schema: config.datasetOutput,
11
+ protected: config.protected,
12
+ tags: ["youtube", "lookup", "playback_location"],
13
+ description:
14
+ "Lookup table for playback location types and their descriptions.",
15
+ }).query(
16
+ (ctx) =>
17
+ `
18
+
19
+ select
20
+ cast(playback_location_type as int) as playback_location_type,
21
+ playback_location as playback_location_name
22
+ from unnest([
23
+ struct(0 as playback_location_type, "YT Watch page or App" as playback_location),
24
+ struct(1 as playback_location_type, "Embed" as playback_location),
25
+ struct(2 as playback_location_type, "YT Channel" as playback_location),
26
+ struct(5 as playback_location_type, "Not Classified" as playback_location),
27
+ struct(7 as playback_location_type, "YT Home Subscription Browse" as playback_location),
28
+ struct(8 as playback_location_type, "YT Search Result" as playback_location),
29
+ struct(10 as playback_location_type, "YT Shorts Feed" as playback_location)
30
+ ]) as playback_locations
31
+
32
+ `,
33
+ );
34
+ };
@@ -0,0 +1,94 @@
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_lu_sharing_services", {
8
+ type: "table",
9
+ database: config.target.database,
10
+ schema: config.datasetOutput,
11
+ protected: config.protected,
12
+ tags: ["youtube", "lookup", "sharing_service"],
13
+ description:
14
+ "Lookup table for sharing service types and their descriptions from YouTube Analytics API.",
15
+ }).query(
16
+ (ctx) =>
17
+ `
18
+
19
+ select
20
+ cast(sharing_service as int) as sharing_service,
21
+ sharing_service_name
22
+ from unnest([
23
+ struct(0 as sharing_service, 'Unknown' as sharing_service_name),
24
+ struct(1 as sharing_service, 'Digg' as sharing_service_name),
25
+ struct(4 as sharing_service, 'Reddit' as sharing_service_name),
26
+ struct(5 as sharing_service, 'StumbleUpon' as sharing_service_name),
27
+ struct(6 as sharing_service, 'Mixi' as sharing_service_name),
28
+ struct(7 as sharing_service, 'Yahoo! Japan' as sharing_service_name),
29
+ struct(8 as sharing_service, 'Goo' as sharing_service_name),
30
+ struct(9 as sharing_service, 'Ameba' as sharing_service_name),
31
+ struct(10 as sharing_service, 'Facebook' as sharing_service_name),
32
+ struct(11 as sharing_service, 'Myspace' as sharing_service_name),
33
+ struct(12 as sharing_service, 'NUjij' as sharing_service_name),
34
+ struct(18 as sharing_service, 'Tuenti' as sharing_service_name),
35
+ struct(20 as sharing_service, 'Menéame' as sharing_service_name),
36
+ struct(21 as sharing_service, 'Wykop' as sharing_service_name),
37
+ struct(22 as sharing_service, 'Skyrock' as sharing_service_name),
38
+ struct(25 as sharing_service, 'Fotka' as sharing_service_name),
39
+ struct(28 as sharing_service, 'Hi5' as sharing_service_name),
40
+ struct(31 as sharing_service, 'Twitter' as sharing_service_name),
41
+ struct(32 as sharing_service, 'Cyworld' as sharing_service_name),
42
+ struct(34 as sharing_service, 'Blogger' as sharing_service_name),
43
+ struct(36 as sharing_service, 'VKontakte' as sharing_service_name),
44
+ struct(37 as sharing_service, 'Rakuten' as sharing_service_name),
45
+ struct(38 as sharing_service, 'LiveJournal' as sharing_service_name),
46
+ struct(39 as sharing_service, 'Odnoklassniki' as sharing_service_name),
47
+ struct(40 as sharing_service, 'Tumblr' as sharing_service_name),
48
+ struct(42 as sharing_service, 'LinkedIn' as sharing_service_name),
49
+ struct(43 as sharing_service, 'Google+' as sharing_service_name),
50
+ struct(44 as sharing_service, 'Weibo' as sharing_service_name),
51
+ struct(45 as sharing_service, 'Pinterest' as sharing_service_name),
52
+ struct(46 as sharing_service, 'Email' as sharing_service_name),
53
+ struct(47 as sharing_service, 'Facebook Messenger' as sharing_service_name),
54
+ struct(49 as sharing_service, 'WhatsApp' as sharing_service_name),
55
+ struct(50 as sharing_service, 'Hangouts' as sharing_service_name),
56
+ struct(51 as sharing_service, 'Gmail' as sharing_service_name),
57
+ struct(52 as sharing_service, 'Kakao Talk' as sharing_service_name),
58
+ struct(53 as sharing_service, 'Other' as sharing_service_name),
59
+ struct(55 as sharing_service, 'Copy to Clipboard' as sharing_service_name),
60
+ struct(59 as sharing_service, 'Embed' as sharing_service_name),
61
+ struct(60 as sharing_service, 'Text message' as sharing_service_name),
62
+ struct(61 as sharing_service, 'Android messaging' as sharing_service_name),
63
+ struct(62 as sharing_service, 'Verizon messages' as sharing_service_name),
64
+ struct(63 as sharing_service, 'HTC text message' as sharing_service_name),
65
+ struct(64 as sharing_service, 'Sony Conversations' as sharing_service_name),
66
+ struct(65 as sharing_service, 'Go SMS' as sharing_service_name),
67
+ struct(66 as sharing_service, 'LGE Email' as sharing_service_name),
68
+ struct(67 as sharing_service, 'Line' as sharing_service_name),
69
+ struct(68 as sharing_service, 'Viber' as sharing_service_name),
70
+ struct(69 as sharing_service, 'Kik' as sharing_service_name),
71
+ struct(70 as sharing_service, 'Skype' as sharing_service_name),
72
+ struct(71 as sharing_service, 'Blackberry Messenger' as sharing_service_name),
73
+ struct(72 as sharing_service, 'WeChat' as sharing_service_name),
74
+ struct(73 as sharing_service, 'KAKAO Story' as sharing_service_name),
75
+ struct(74 as sharing_service, 'Dropbox' as sharing_service_name),
76
+ struct(75 as sharing_service, 'Telegram' as sharing_service_name),
77
+ struct(76 as sharing_service, 'Facebook Pages' as sharing_service_name),
78
+ struct(77 as sharing_service, 'GroupMe' as sharing_service_name),
79
+ struct(78 as sharing_service, 'Android Email' as sharing_service_name),
80
+ struct(79 as sharing_service, 'Motorola Messaging' as sharing_service_name),
81
+ struct(80 as sharing_service, 'Nearby Share' as sharing_service_name),
82
+ struct(81 as sharing_service, 'Naver' as sharing_service_name),
83
+ struct(82 as sharing_service, 'iOS System Activity Dialog' as sharing_service_name),
84
+ struct(83 as sharing_service, 'Google Inbox' as sharing_service_name),
85
+ struct(84 as sharing_service, 'Android Messenger' as sharing_service_name),
86
+ struct(85 as sharing_service, 'YouTube Music' as sharing_service_name),
87
+ struct(86 as sharing_service, 'YouTube Gaming' as sharing_service_name),
88
+ struct(87 as sharing_service, 'YouTube Kids' as sharing_service_name),
89
+ struct(88 as sharing_service, 'YouTube TV' as sharing_service_name)
90
+ ]) as sharing_services
91
+
92
+ `,
93
+ );
94
+ };
@@ -0,0 +1,50 @@
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_lu_traffic_sources", {
8
+ type: "table",
9
+ database: config.target.database,
10
+ schema: config.datasetOutput,
11
+ protected: config.protected,
12
+ tags: ["youtube", "lookup", "traffic_source"],
13
+ description:
14
+ "Lookup table for traffic source types and their descriptions from YouTube Analytics API.",
15
+ }).query(
16
+ (ctx) =>
17
+ `
18
+
19
+ select
20
+ cast(traffic_source_type as int) as traffic_source_type,
21
+ traffic_source as traffic_source_name
22
+ from unnest([
23
+ struct(0 as traffic_source_type, "Direct or unknown" as traffic_source),
24
+ struct(1 as traffic_source_type, "YouTube advertising" as traffic_source),
25
+ struct(3 as traffic_source_type, "Browse features" as traffic_source),
26
+ struct(4 as traffic_source_type, "YouTube channels" as traffic_source),
27
+ struct(5 as traffic_source_type, "YouTube search" as traffic_source),
28
+ struct(7 as traffic_source_type, "Suggested videos" as traffic_source),
29
+ struct(8 as traffic_source_type, "Other YouTube features" as traffic_source),
30
+ struct(9 as traffic_source_type, "External" as traffic_source),
31
+ struct(11 as traffic_source_type, "Video cards and annotations" as traffic_source),
32
+ struct(14 as traffic_source_type, "Playlists" as traffic_source),
33
+ struct(17 as traffic_source_type, "Notifications" as traffic_source),
34
+ struct(18 as traffic_source_type, "Playlist pages" as traffic_source),
35
+ struct(19 as traffic_source_type, "Programming from claimed content" as traffic_source),
36
+ struct(20 as traffic_source_type, "Interactive video endscreen" as traffic_source),
37
+ struct(23 as traffic_source_type, "Stories" as traffic_source),
38
+ struct(24 as traffic_source_type, "Shorts" as traffic_source),
39
+ struct(25 as traffic_source_type, "Product Pages" as traffic_source),
40
+ struct(26 as traffic_source_type, "Hashtag Pages" as traffic_source),
41
+ struct(27 as traffic_source_type, "Sound Pages" as traffic_source),
42
+ struct(28 as traffic_source_type, "Live redirect" as traffic_source),
43
+ struct(30 as traffic_source_type, "Remixed video" as traffic_source),
44
+ struct(31 as traffic_source_type, "Vertical live feed" as traffic_source),
45
+ struct(32 as traffic_source_type, "Related video" as traffic_source)
46
+ ]) as traffic_sources
47
+
48
+ `,
49
+ );
50
+ };
@@ -0,0 +1,90 @@
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_playback", {
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", "playback_location_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
+ "playback_location_type",
28
+ "playback_location_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 Playback Location data",
35
+ })
36
+ .preOps(
37
+ (ctx) => `
38
+ declare source_date_checkpoint default (
39
+ select date("${config.startDate}")
40
+ );
41
+
42
+ --Set the incremental update checkpoint based on current max partition value minus lookback.
43
+ set source_date_checkpoint = (
44
+ ${ctx.when(
45
+ ctx.incremental(),
46
+ `select
47
+ least(
48
+ (select date_sub(current_date(), interval ${config.daysBack} day)),
49
+ (select date_sub(max(source_partition_date), interval ${config.daysBack} day) from ${ctx.self()})
50
+ )`,
51
+ `select date("${config.startDate}")`,
52
+ )}
53
+ );
54
+
55
+ ${ctx.when(
56
+ ctx.incremental(),
57
+ `delete ${ctx.self()} where source_partition_date > source_date_checkpoint`,
58
+ )}
59
+ `,
60
+ )
61
+ .query((ctx) =>
62
+ config.sources
63
+ .map((t) => {
64
+ return `
65
+
66
+ select
67
+ _PARTITIONDATE as source_partition_date,
68
+ parse_date('%Y%m%d', date) as interaction_date,
69
+ "${t.schema}" as site_nm,
70
+ current_timestamp() as updated_at,
71
+ channel_id,
72
+ video_id,
73
+ live_or_on_demand,
74
+ subscribed_status,
75
+ country_code,
76
+ playback_location_type,
77
+ playback_location_detail,
78
+ views,
79
+ watch_time_minutes,
80
+ average_view_duration_seconds,
81
+ average_view_duration_percentage,
82
+ red_views,
83
+ red_watch_time_minutes
84
+ from ${ctx.ref(t.database, t.schema, "p_channel_playback_location_a2_" + t.suffix)}
85
+ where _PARTITIONDATE > source_date_checkpoint
86
+ `;
87
+ })
88
+ .join(" union all "),
89
+ );
90
+ };
@@ -0,0 +1,103 @@
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("stg_ytc_province", {
10
+ type: "incremental",
11
+ database: config.target.database,
12
+ schema: config.datasetStaging,
13
+ protected: config.protected,
14
+ tags: ["youtube", "source", "staging", "daily"],
15
+ bigquery: {
16
+ partitionBy: "interaction_date",
17
+ clusterBy: ["video_id"],
18
+ },
19
+ assertions: {
20
+ // make sure rows have unique dimensions
21
+ uniqueKeys: [
22
+ [
23
+ "interaction_date",
24
+ "channel_id",
25
+ "video_id",
26
+ "live_or_on_demand",
27
+ "subscribed_status",
28
+ "country_code",
29
+ "province_code",
30
+ ],
31
+ ],
32
+ // make sure source partition and data dates match
33
+ rowConditions: ["interaction_date = source_partition_date"],
34
+ },
35
+ columns: column_descriptions.column_descriptions,
36
+ description: "YT Channel Province Report Table - Staging",
37
+ })
38
+ .preOps(
39
+ (ctx) => `
40
+ declare source_date_checkpoint default (
41
+ select date("${config.startDate}")
42
+ );
43
+
44
+ --Set the incremental update checkpoint based on current max partition value minus lookback.
45
+ set source_date_checkpoint = (
46
+ ${ctx.when(
47
+ ctx.incremental(),
48
+ `select
49
+ least(
50
+ (select date_sub(current_date(), interval ${config.daysBack} day)),
51
+ (select date_sub(max(source_partition_date), interval ${config.daysBack} day) from ${ctx.self()})
52
+ )`,
53
+ `select date("${config.startDate}")`,
54
+ )}
55
+ );
56
+
57
+ ${ctx.when(
58
+ ctx.incremental(),
59
+ `delete ${ctx.self()} where source_partition_date > source_date_checkpoint`,
60
+ )}
61
+ `,
62
+ )
63
+ .query((ctx) =>
64
+ config.sources
65
+ .map((t) => {
66
+ return `
67
+ select
68
+ _PARTITIONDATE as source_partition_date,
69
+ parse_date('%Y%m%d',date) as interaction_date,
70
+ "${t.schema}" as site_nm,
71
+ current_timestamp() as updated_at,
72
+ channel_id,
73
+ video_id,
74
+ live_or_on_demand,
75
+ subscribed_status,
76
+ country_code,
77
+ province_code,
78
+ views,
79
+ watch_time_minutes,
80
+ average_view_duration_seconds,
81
+ average_view_duration_percentage,
82
+ annotation_click_through_rate,
83
+ annotation_close_rate,
84
+ annotation_impressions,
85
+ annotation_clickable_impressions,
86
+ annotation_closable_impressions,
87
+ annotation_clicks,
88
+ annotation_closes,
89
+ card_click_rate,
90
+ card_teaser_click_rate,
91
+ card_impressions,
92
+ card_teaser_impressions,
93
+ card_clicks,
94
+ card_teaser_clicks,
95
+ red_views,
96
+ red_watch_time_minutes
97
+ from ${ctx.ref(t.database, t.schema, "p_channel_province_a2_" + t.suffix)}
98
+ where _PARTITIONDATE > source_date_checkpoint
99
+ `;
100
+ })
101
+ .join(" union all "),
102
+ );
103
+ };
@@ -0,0 +1,82 @@
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_share_platform", {
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", "sharing_service"],
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
+ "sharing_service",
28
+ ],
29
+ ],
30
+ // make sure source partition and data dates match
31
+ rowConditions: ["interaction_date = source_partition_date"],
32
+ },
33
+ description: "Staging table for YouTube Channel Share Platform data",
34
+ })
35
+ .preOps(
36
+ (ctx) => `
37
+ declare source_date_checkpoint default (
38
+ select date("${config.startDate}")
39
+ );
40
+
41
+ --Set the incremental update checkpoint based on current max partition value minus lookback.
42
+ set source_date_checkpoint = (
43
+ ${ctx.when(
44
+ ctx.incremental(),
45
+ `select
46
+ least(
47
+ (select date_sub(current_date(), interval ${config.daysBack} day)),
48
+ (select date_sub(max(source_partition_date), interval ${config.daysBack} day) from ${ctx.self()})
49
+ )`,
50
+ `select date("${config.startDate}")`,
51
+ )}
52
+ );
53
+
54
+ ${ctx.when(
55
+ ctx.incremental(),
56
+ `delete ${ctx.self()} where source_partition_date > source_date_checkpoint`,
57
+ )}
58
+ `,
59
+ )
60
+ .query((ctx) =>
61
+ config.sources
62
+ .map((t) => {
63
+ return `
64
+ select
65
+ _PARTITIONDATE as source_partition_date,
66
+ parse_date('%Y%m%d', date) as interaction_date,
67
+ "${t.schema}" as site_nm,
68
+ current_timestamp() as updated_at,
69
+ channel_id,
70
+ video_id,
71
+ live_or_on_demand,
72
+ subscribed_status,
73
+ country_code,
74
+ cast(sharing_service as int) as sharing_service,
75
+ shares
76
+ from ${ctx.ref(t.database, t.schema, "p_channel_sharing_service_a1_" + t.suffix)}
77
+ where _PARTITIONDATE > source_date_checkpoint
78
+ `;
79
+ })
80
+ .join(" union all "),
81
+ );
82
+ };
@@ -0,0 +1,89 @@
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("stg_ytc_subtitles", {
10
+ type: "incremental",
11
+ database: config.target.database,
12
+ schema: config.datasetStaging,
13
+ protected: config.protected,
14
+ tags: ["youtube", "source", "staging", "daily"],
15
+ bigquery: {
16
+ partitionBy: "interaction_date",
17
+ clusterBy: ["video_id"],
18
+ },
19
+ assertions: {
20
+ uniqueKeys: [
21
+ [
22
+ "interaction_date",
23
+ "channel_id",
24
+ "video_id",
25
+ "live_or_on_demand",
26
+ "subscribed_status",
27
+ "country_code",
28
+ "subtitle_language",
29
+ "subtitle_language_autotranslated",
30
+ ],
31
+ ],
32
+ rowConditions: ["interaction_date = source_partition_date"],
33
+ },
34
+ columns: column_descriptions.column_descriptions,
35
+ description: "YT Channel Subtitles Report Table - Staging",
36
+ })
37
+ .preOps(
38
+ (ctx) => `
39
+ declare source_date_checkpoint default (
40
+ select date("${config.startDate}")
41
+ );
42
+
43
+ set source_date_checkpoint = (
44
+ ${ctx.when(
45
+ ctx.incremental(),
46
+ `select
47
+ least(
48
+ (select date_sub(current_date(), interval ${config.daysBack} day)),
49
+ (select date_sub(max(source_partition_date), interval ${config.daysBack} day) from ${ctx.self()})
50
+ )`,
51
+ `select date("${config.startDate}")`,
52
+ )}
53
+ );
54
+
55
+ ${ctx.when(
56
+ ctx.incremental(),
57
+ `delete ${ctx.self()} where source_partition_date > source_date_checkpoint`,
58
+ )}
59
+ `,
60
+ )
61
+ .query((ctx) =>
62
+ config.sources
63
+ .map((t) => {
64
+ return `
65
+ select
66
+ _PARTITIONDATE as source_partition_date,
67
+ parse_date('%Y%m%d',date) as interaction_date,
68
+ "${t.schema}" as site_nm,
69
+ current_timestamp() as updated_at,
70
+ channel_id,
71
+ video_id,
72
+ live_or_on_demand,
73
+ subscribed_status,
74
+ country_code,
75
+ subtitle_language,
76
+ subtitle_language_autotranslated,
77
+ views,
78
+ watch_time_minutes,
79
+ average_view_duration_seconds,
80
+ average_view_duration_percentage,
81
+ red_views,
82
+ red_watch_time_minutes
83
+ from ${ctx.ref(t.database, t.schema, "p_channel_subtitles_a2_" + t.suffix)}
84
+ where _PARTITIONDATE > source_date_checkpoint
85
+ `;
86
+ })
87
+ .join(" union all "),
88
+ );
89
+ };