@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,71 @@
|
|
|
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_province", {
|
|
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 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
|
+
-- 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_province")}
|
|
54
|
+
where interaction_date > interaction_date_checkpoint
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
select
|
|
58
|
+
int_ex_titles.*,
|
|
59
|
+
ifnull(titles.video_title, int_ex_titles.video_id) as video_title
|
|
60
|
+
from int_ex_titles
|
|
61
|
+
left join ${ctx.ref(
|
|
62
|
+
config.titlesProject,
|
|
63
|
+
config.titlesDataset,
|
|
64
|
+
config.titlesTable,
|
|
65
|
+
)} as titles
|
|
66
|
+
using
|
|
67
|
+
(video_id)
|
|
68
|
+
|
|
69
|
+
`,
|
|
70
|
+
);
|
|
71
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
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_share_platform", {
|
|
14
|
+
type: "incremental",
|
|
15
|
+
schema: config.datasetIntermediate,
|
|
16
|
+
tags: ["youtube", "output", "daily"],
|
|
17
|
+
bigquery: {
|
|
18
|
+
partitionBy: "interaction_date",
|
|
19
|
+
clusterBy: ["video_id", "sharing_service"],
|
|
20
|
+
},
|
|
21
|
+
columns: column_descriptions.column_descriptions,
|
|
22
|
+
description: "YT Channel Share Platform 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
|
+
from ${ctx.ref("stg_ytc_share_platform")}
|
|
57
|
+
where interaction_date > interaction_date_checkpoint
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
select
|
|
61
|
+
int_ex_titles.*,
|
|
62
|
+
ss.sharing_service_name,
|
|
63
|
+
ifnull(titles.video_title, int_ex_titles.video_id) as video_title
|
|
64
|
+
from int_ex_titles
|
|
65
|
+
left join ${ctx.ref("stg_ytc_lu_sharing_services")} as ss
|
|
66
|
+
using (sharing_service)
|
|
67
|
+
left join ${ctx.ref(
|
|
68
|
+
config.titlesProject,
|
|
69
|
+
config.titlesDataset,
|
|
70
|
+
config.titlesTable,
|
|
71
|
+
)} as titles
|
|
72
|
+
using (video_id)
|
|
73
|
+
|
|
74
|
+
`,
|
|
75
|
+
);
|
|
76
|
+
};
|
|
@@ -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_subtitles", {
|
|
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 Subtitles 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_ex_titles as (
|
|
48
|
+
select
|
|
49
|
+
* except (source_partition_date),
|
|
50
|
+
views * safe_divide(average_view_duration_seconds, average_view_duration_percentage) as row_max_duration_seconds
|
|
51
|
+
from ${ctx.ref("stg_ytc_subtitles")}
|
|
52
|
+
where interaction_date > interaction_date_checkpoint
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
select
|
|
56
|
+
int_ex_titles.*,
|
|
57
|
+
ifnull(titles.video_title, int_ex_titles.video_id) as video_title
|
|
58
|
+
from int_ex_titles
|
|
59
|
+
left join ${ctx.ref(
|
|
60
|
+
config.titlesProject,
|
|
61
|
+
config.titlesDataset,
|
|
62
|
+
config.titlesTable,
|
|
63
|
+
)} as titles
|
|
64
|
+
using
|
|
65
|
+
(video_id)
|
|
66
|
+
|
|
67
|
+
`,
|
|
68
|
+
);
|
|
69
|
+
};
|
|
@@ -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_traffic_source", {
|
|
10
|
+
type: "incremental",
|
|
11
|
+
schema: config.datasetIntermediate,
|
|
12
|
+
tags: ["youtube", "output", "daily"],
|
|
13
|
+
bigquery: {
|
|
14
|
+
partitionBy: "interaction_date",
|
|
15
|
+
clusterBy: ["video_id", "traffic_source_type"],
|
|
16
|
+
},
|
|
17
|
+
columns: column_descriptions.column_descriptions,
|
|
18
|
+
description: "YT Channel Traffic Source 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_traffic_source")}
|
|
54
|
+
where interaction_date > interaction_date_checkpoint
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
select
|
|
58
|
+
int_ex_titles.*,
|
|
59
|
+
ts.traffic_source_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_traffic_sources")} as ts
|
|
63
|
+
using (traffic_source_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
|
+
};
|
package/index.js
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
const stg_ytc_lu_playback_location = require("./includes/definitions/sources/stg_ytc_lu_playback_location");
|
|
2
|
+
const stg_ytc_lu_traffic_sources = require("./includes/definitions/sources/stg_ytc_lu_traffic_sources");
|
|
3
|
+
const stg_ytc_province = require("./includes/definitions/sources/stg_ytc_province");
|
|
4
|
+
const stg_ytc_list_traffic_source = require("./includes/definitions/sources/stg_ytc_list_traffic_source");
|
|
5
|
+
const stg_ytc_cards = require("./includes/definitions/sources/stg_ytc_cards");
|
|
6
|
+
const stg_ytc_list_device_os = require("./includes/definitions/sources/stg_ytc_list_device_os");
|
|
7
|
+
const stg_ytc_annotation = require("./includes/definitions/sources/stg_ytc_annotation");
|
|
8
|
+
const stg_ytc_traffic_source = require("./includes/definitions/sources/stg_ytc_traffic_source");
|
|
9
|
+
const stg_ytc_lu_annotation_type = require("./includes/definitions/sources/stg_ytc_lu_annotation_type");
|
|
10
|
+
const stg_ytc_lu_sharing_services = require("./includes/definitions/sources/stg_ytc_lu_sharing_services");
|
|
11
|
+
const stg_ytc_lu_end_screen_element_type = require("./includes/definitions/sources/stg_ytc_lu_end_screen_element_type");
|
|
12
|
+
const stg_ytc_lu_device_types = require("./includes/definitions/sources/stg_ytc_lu_device_types");
|
|
13
|
+
const stg_ytc_playback = require("./includes/definitions/sources/stg_ytc_playback");
|
|
14
|
+
const stg_ytc_lu_operating_systems = require("./includes/definitions/sources/stg_ytc_lu_operating_systems");
|
|
15
|
+
const stg_ytc_end_screens = require("./includes/definitions/sources/stg_ytc_end_screens");
|
|
16
|
+
const stg_ytc_list_basic = require("./includes/definitions/sources/stg_ytc_list_basic");
|
|
17
|
+
const stg_ytc_demographics = require("./includes/definitions/sources/stg_ytc_demographics");
|
|
18
|
+
const stg_ytc_lu_card_type = require("./includes/definitions/sources/stg_ytc_lu_card_type");
|
|
19
|
+
const stg_ytc_list_province = require("./includes/definitions/sources/stg_ytc_list_province");
|
|
20
|
+
const stg_ytc_list_combined = require("./includes/definitions/sources/stg_ytc_list_combined");
|
|
21
|
+
const stg_ytc_basic = require("./includes/definitions/sources/stg_ytc_basic");
|
|
22
|
+
const stg_ytc_subtitles = require("./includes/definitions/sources/stg_ytc_subtitles");
|
|
23
|
+
const stg_ytc_combined = require("./includes/definitions/sources/stg_ytc_combined");
|
|
24
|
+
const stg_ytc_device_os = require("./includes/definitions/sources/stg_ytc_device_os");
|
|
25
|
+
const stg_ytc_share_platform = require("./includes/definitions/sources/stg_ytc_share_platform");
|
|
26
|
+
const stg_ytc_list_playback = require("./includes/definitions/sources/stg_ytc_list_playback");
|
|
27
|
+
const ytc_list_province = require("./includes/definitions/ytc_list_province");
|
|
28
|
+
const ytc_list_traffic_source = require("./includes/definitions/ytc_list_traffic_source");
|
|
29
|
+
const ytc_demographics = require("./includes/definitions/ytc_demographics");
|
|
30
|
+
const ytc_traffic_source = require("./includes/definitions/ytc_traffic_source");
|
|
31
|
+
const ytc_combined = require("./includes/definitions/ytc_combined");
|
|
32
|
+
const ytc_demographics_views = require("./includes/definitions/ytc_demographics_views");
|
|
33
|
+
const ytc_list_basic = require("./includes/definitions/ytc_list_basic");
|
|
34
|
+
const ytc_list_combined = require("./includes/definitions/ytc_list_combined");
|
|
35
|
+
const ytc_cards = require("./includes/definitions/ytc_cards");
|
|
36
|
+
const ytc_share_platform = require("./includes/definitions/ytc_share_platform");
|
|
37
|
+
const ytc_playback = require("./includes/definitions/ytc_playback");
|
|
38
|
+
const ytc_list_device_os = require("./includes/definitions/ytc_list_device_os");
|
|
39
|
+
const ytc_device_os = require("./includes/definitions/ytc_device_os");
|
|
40
|
+
const ytc_end_screens = require("./includes/definitions/ytc_end_screens");
|
|
41
|
+
const ytc_annotation = require("./includes/definitions/ytc_annotation");
|
|
42
|
+
const ytc_province = require("./includes/definitions/ytc_province");
|
|
43
|
+
const ytc_subtitles = require("./includes/definitions/ytc_subtitles");
|
|
44
|
+
const ytc_basic = require("./includes/definitions/ytc_basic");
|
|
45
|
+
const ytc_list_playback = require("./includes/definitions/ytc_list_playback");
|
|
46
|
+
/**
|
|
47
|
+
* Processes data sources configuration.
|
|
48
|
+
*
|
|
49
|
+
* @param {Object} config - Configuration object.
|
|
50
|
+
* @param {Array<Object>} config.sources - An array of data source definitions.
|
|
51
|
+
* @param {string} config.sources[].schema - The schema name for the source.
|
|
52
|
+
* @param {string} config.sources[].database - The database name for the source.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* const config = {
|
|
56
|
+
* sources: [
|
|
57
|
+
* { schema: "schema1", suffix: "11111", database: "db1" },
|
|
58
|
+
* { schema: "schema2", suffix: "22222", database: "db2" },
|
|
59
|
+
* { schema: "schema3", suffix: "33333", database: "db1" }
|
|
60
|
+
* ],
|
|
61
|
+
* start_date: "2025-10-01",
|
|
62
|
+
* days_back: 10
|
|
63
|
+
* };
|
|
64
|
+
* myFunction(config);
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
module.exports = (config) => {
|
|
68
|
+
if (!config.sources || !config.sources.length) {
|
|
69
|
+
throw new Error("Missing config.sources");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!config.target) {
|
|
73
|
+
throw new Error("Missing target");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!config.target.database) {
|
|
77
|
+
throw new Error("Missing target database");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// TODO: add defaults for your config options
|
|
81
|
+
config = {
|
|
82
|
+
sourceTableSuffix: "_drpg",
|
|
83
|
+
daysBack: "7",
|
|
84
|
+
startDate: "2024-09-01",
|
|
85
|
+
titlesProject: "youtube-research-440316",
|
|
86
|
+
titlesDataset: "yt_channel_development",
|
|
87
|
+
titlesTable: "video_titles",
|
|
88
|
+
playlistTable: "playlist_titles",
|
|
89
|
+
...config,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
config.target = {
|
|
93
|
+
stagingSchema: "propeller_dataform_template",
|
|
94
|
+
outputSchema: "propeller_dataform_template",
|
|
95
|
+
protected: false,
|
|
96
|
+
...config.target,
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
config.sources.map((s) => {
|
|
100
|
+
declare({
|
|
101
|
+
database: s.database,
|
|
102
|
+
schema: s.schema,
|
|
103
|
+
name: "p_channel_basic_a2_" + s.suffix,
|
|
104
|
+
description:
|
|
105
|
+
"This report provides user activity statistics related to a channel and its videos.",
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
declare({
|
|
109
|
+
database: s.database,
|
|
110
|
+
schema: s.schema,
|
|
111
|
+
name: "p_channel_combined_a2_" + s.suffix,
|
|
112
|
+
description:
|
|
113
|
+
"This report provides user activity statistics related to a channel and its videos.",
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
declare({
|
|
117
|
+
database: s.database,
|
|
118
|
+
schema: s.schema,
|
|
119
|
+
name: "p_channel_province_a2_" + s.suffix,
|
|
120
|
+
description:
|
|
121
|
+
"This report provides user activity statistics for U.S. states and the District of Columbia.",
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
declare({
|
|
125
|
+
database: s.database,
|
|
126
|
+
schema: s.schema,
|
|
127
|
+
name: "p_channel_playback_location_a2_" + s.suffix,
|
|
128
|
+
description:
|
|
129
|
+
"This report provides statistics related to the type of page or application where video playbacks occurred.",
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
declare({
|
|
133
|
+
database: s.database,
|
|
134
|
+
schema: s.schema,
|
|
135
|
+
name: "p_channel_traffic_source_a2_" + s.suffix,
|
|
136
|
+
description:
|
|
137
|
+
"This report aggregates viewing statistics based on the manner in which viewers reached the channel's video content.",
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
declare({
|
|
141
|
+
database: s.database,
|
|
142
|
+
schema: s.schema,
|
|
143
|
+
name: "p_channel_device_os_a2_" + s.suffix,
|
|
144
|
+
description:
|
|
145
|
+
"This report aggregates video viewing statistics based on viewers' operating systems and device types.",
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
declare({
|
|
149
|
+
database: s.database,
|
|
150
|
+
schema: s.schema,
|
|
151
|
+
name: "p_channel_demographics_a1_" + s.suffix,
|
|
152
|
+
description:
|
|
153
|
+
"This report aggregates viewing statistics based on viewers' age group and gender.",
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
declare({
|
|
157
|
+
database: s.database,
|
|
158
|
+
schema: s.schema,
|
|
159
|
+
name: "p_channel_sharing_service_a1_" + s.suffix,
|
|
160
|
+
description:
|
|
161
|
+
"This report provides statistics showing how frequently the channel's videos were shared on different social platforms.",
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
declare({
|
|
165
|
+
database: s.database,
|
|
166
|
+
schema: s.schema,
|
|
167
|
+
name: "p_channel_annotations_a1_" + s.suffix,
|
|
168
|
+
description:
|
|
169
|
+
"This report provides statistics for annotations that display during a channel's videos.",
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
declare({
|
|
173
|
+
database: s.database,
|
|
174
|
+
schema: s.schema,
|
|
175
|
+
name: "p_channel_cards_a1_" + s.suffix,
|
|
176
|
+
description:
|
|
177
|
+
"This report provides impressions and click-through statistics for cards that display during a channel's videos.",
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
declare({
|
|
181
|
+
database: s.database,
|
|
182
|
+
schema: s.schema,
|
|
183
|
+
name: "p_channel_end_screens_a1_" + s.suffix,
|
|
184
|
+
description:
|
|
185
|
+
"This report provides impressions and click-through statistics for end screen elements that display during a channel's videos.",
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
declare({
|
|
189
|
+
database: s.database,
|
|
190
|
+
schema: s.schema,
|
|
191
|
+
name: "p_channel_subtitles_a2_" + s.suffix,
|
|
192
|
+
description:
|
|
193
|
+
"This report provides statistics about the closed caption language usage during video views.",
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
declare({
|
|
197
|
+
database: s.database,
|
|
198
|
+
schema: s.schema,
|
|
199
|
+
name: "p_playlist_basic_a1_" + s.suffix,
|
|
200
|
+
description:
|
|
201
|
+
"This report provides statistics related to users' interactions with a channel's playlists.",
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
declare({
|
|
205
|
+
database: s.database,
|
|
206
|
+
schema: s.schema,
|
|
207
|
+
name: "p_playlist_device_os_a1_" + s.suffix,
|
|
208
|
+
description:
|
|
209
|
+
"This report aggregates playlist viewing statistics based on viewers' operating systems and device types.",
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
declare({
|
|
213
|
+
database: s.database,
|
|
214
|
+
schema: s.schema,
|
|
215
|
+
name: "p_playlist_province_a1_" + s.suffix,
|
|
216
|
+
description:
|
|
217
|
+
"This report provides user activity statistics related to users' interactions with a channel's playlists for U.S. states and the District of Columbia.",
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
declare({
|
|
221
|
+
database: s.database,
|
|
222
|
+
schema: s.schema,
|
|
223
|
+
name: "p_playlist_playback_location_a1_" + s.suffix,
|
|
224
|
+
description:
|
|
225
|
+
"This report provides statistics related to the type of page or application where playlist playbacks occurred.",
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
declare({
|
|
229
|
+
database: s.database,
|
|
230
|
+
schema: s.schema,
|
|
231
|
+
name: "p_playlist_traffic_source_a1_" + s.suffix,
|
|
232
|
+
description:
|
|
233
|
+
"This report aggregates viewing statistics based on the manner in which viewers reached a channel's playlist videos.",
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
declare({
|
|
237
|
+
database: s.database,
|
|
238
|
+
schema: s.schema,
|
|
239
|
+
name: "p_playlist_combined_a1_" + s.suffix,
|
|
240
|
+
description:
|
|
241
|
+
"This report provides fine-grained playlist statistics by combining dimensions used in the playback location, traffic source, and device/OS reports.",
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
declare({
|
|
245
|
+
database: config.titlesProject,
|
|
246
|
+
schema: config.titlesDataset,
|
|
247
|
+
name: config.titlesTable,
|
|
248
|
+
description:
|
|
249
|
+
"This table stores video titles retirieved from the data API.",
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
declare({
|
|
253
|
+
database: config.titlesProject,
|
|
254
|
+
schema: config.titlesDataset,
|
|
255
|
+
name: config.playlistTable,
|
|
256
|
+
description:
|
|
257
|
+
"This table stores playlist titles retirieved from the data API.",
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Conditionally add models
|
|
262
|
+
let result = {
|
|
263
|
+
stg_ytc_lu_playback_location: stg_ytc_lu_playback_location(config),
|
|
264
|
+
stg_ytc_lu_traffic_sources: stg_ytc_lu_traffic_sources(config),
|
|
265
|
+
stg_ytc_province: stg_ytc_province(config),
|
|
266
|
+
stg_ytc_list_traffic_source: stg_ytc_list_traffic_source(config),
|
|
267
|
+
stg_ytc_cards: stg_ytc_cards(config),
|
|
268
|
+
stg_ytc_list_device_os: stg_ytc_list_device_os(config),
|
|
269
|
+
stg_ytc_annotation: stg_ytc_annotation(config),
|
|
270
|
+
stg_ytc_traffic_source: stg_ytc_traffic_source(config),
|
|
271
|
+
stg_ytc_lu_annotation_type: stg_ytc_lu_annotation_type(config),
|
|
272
|
+
stg_ytc_lu_sharing_services: stg_ytc_lu_sharing_services(config),
|
|
273
|
+
stg_ytc_lu_end_screen_element_type:
|
|
274
|
+
stg_ytc_lu_end_screen_element_type(config),
|
|
275
|
+
stg_ytc_lu_device_types: stg_ytc_lu_device_types(config),
|
|
276
|
+
stg_ytc_playback: stg_ytc_playback(config),
|
|
277
|
+
stg_ytc_lu_operating_systems: stg_ytc_lu_operating_systems(config),
|
|
278
|
+
stg_ytc_end_screens: stg_ytc_end_screens(config),
|
|
279
|
+
stg_ytc_list_basic: stg_ytc_list_basic(config),
|
|
280
|
+
stg_ytc_demographics: stg_ytc_demographics(config),
|
|
281
|
+
stg_ytc_lu_card_type: stg_ytc_lu_card_type(config),
|
|
282
|
+
stg_ytc_list_province: stg_ytc_list_province(config),
|
|
283
|
+
stg_ytc_list_combined: stg_ytc_list_combined(config),
|
|
284
|
+
stg_ytc_basic: stg_ytc_basic(config),
|
|
285
|
+
stg_ytc_subtitles: stg_ytc_subtitles(config),
|
|
286
|
+
stg_ytc_combined: stg_ytc_combined(config),
|
|
287
|
+
stg_ytc_device_os: stg_ytc_device_os(config),
|
|
288
|
+
stg_ytc_share_platform: stg_ytc_share_platform(config),
|
|
289
|
+
stg_ytc_list_playback: stg_ytc_list_playback(config),
|
|
290
|
+
ytc_list_province: ytc_list_province(config),
|
|
291
|
+
ytc_list_traffic_source: ytc_list_traffic_source(config),
|
|
292
|
+
ytc_demographics: ytc_demographics(config),
|
|
293
|
+
ytc_traffic_source: ytc_traffic_source(config),
|
|
294
|
+
ytc_combined: ytc_combined(config),
|
|
295
|
+
ytc_demographics_views: ytc_demographics_views(config),
|
|
296
|
+
ytc_list_basic: ytc_list_basic(config),
|
|
297
|
+
ytc_list_combined: ytc_list_combined(config),
|
|
298
|
+
ytc_cards: ytc_cards(config),
|
|
299
|
+
ytc_share_platform: ytc_share_platform(config),
|
|
300
|
+
ytc_playback: ytc_playback(config),
|
|
301
|
+
ytc_list_device_os: ytc_list_device_os(config),
|
|
302
|
+
ytc_device_os: ytc_device_os(config),
|
|
303
|
+
ytc_end_screens: ytc_end_screens(config),
|
|
304
|
+
ytc_annotation: ytc_annotation(config),
|
|
305
|
+
ytc_province: ytc_province(config),
|
|
306
|
+
ytc_subtitles: ytc_subtitles(config),
|
|
307
|
+
ytc_basic: ytc_basic(config),
|
|
308
|
+
ytc_list_playback: ytc_list_playback(config),
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
return result;
|
|
312
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ken-e/dataform-youtube",
|
|
3
|
+
"dependencies": {
|
|
4
|
+
"@dataform/core": "3.0.9",
|
|
5
|
+
"@ken-e/dataform-helpers": "latest"
|
|
6
|
+
},
|
|
7
|
+
"devDependencies": {
|
|
8
|
+
"@eslint/js": "^9.18.0",
|
|
9
|
+
"eslint": "^9.18.0",
|
|
10
|
+
"eslint-config-prettier": "^10.0.1",
|
|
11
|
+
"globals": "^15.14.0",
|
|
12
|
+
"prettier": "3.4.2"
|
|
13
|
+
},
|
|
14
|
+
"version": "0.0.2",
|
|
15
|
+
"description": "TODO",
|
|
16
|
+
"main": "index.js",
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/KEN-E-AI/dataform-youtube.git"
|
|
23
|
+
},
|
|
24
|
+
"author": "",
|
|
25
|
+
"license": "UNLICENSED",
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/KEN-E-AI/dataform-youtube/issues"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://github.com/KEN-E-AI/dataform-youtube#readme"
|
|
30
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// prettier.config.js, .prettierrc.js, prettier.config.mjs, or .prettierrc.mjs
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @see https://prettier.io/docs/en/configuration.html
|
|
5
|
+
* @type {import("prettier").Config}
|
|
6
|
+
*/
|
|
7
|
+
const config = {
|
|
8
|
+
trailingComma: "es5",
|
|
9
|
+
tabWidth: 4,
|
|
10
|
+
semi: true,
|
|
11
|
+
singleQuote: true,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
module.exports = [config];
|