1+ import datetime
2+ import pathlib
3+
14import dlt
25import typer
3- from dlt .sources .rest_api import rest_api_source
6+ from dlt .destinations .impl .filesystem .factory import filesystem
7+ from dlt .sources .helpers .rest_client import RESTClient
8+ from dlt .sources .helpers .rest_client .paginators import JSONLinkPaginator
49
510from .settings import (
611 INSTITUTION_CODE ,
1217app = typer .Typer ()
1318
1419
15- def dlt_source (
16- year ,
17- resources ,
18- projects ,
19- persons ,
20- categories ,
21- funding_sources ,
22- base_url ,
23- institution_code ,
24- ):
25- if year is None :
26- log .info ("No year specified, syncing all available years." )
27- resource_params = {
28- "unit" : institution_code ,
29- }
30- else :
31- log .info (f"Syncing data for year: { year } " )
32- resource_params = {
33- "unit" : institution_code ,
34- "publicationYearSince" : year ,
35- "publicationYearBefore" : year + 1 ,
36- }
37- return rest_api_source (
38- {
39- "client" : {
40- "base_url" : base_url ,
41- "paginator" : {
42- "type" : "json_link" ,
43- "next_url_path" : "nextResults" ,
44- },
45- },
46- "resources" : list (
47- filter (
48- lambda r : r is not None ,
49- [
50- {
51- "name" : "resources" ,
52- "max_table_nesting" : 0 ,
53- "endpoint" : {
54- "path" : "search/resources" ,
55- "data_selector" : "hits" ,
56- "params" : {
57- ** resource_params ,
58- },
59- },
60- }
61- if resources
62- else None ,
63- {
64- "name" : "projects" ,
65- "max_table_nesting" : 0 ,
66- "endpoint" : {
67- "path" : f"cristin/organization/{ institution_code } /projects" , # noqa: E501
68- "data_selector" : "hits" ,
69- },
70- }
71- if projects
72- else None ,
73- {
74- "name" : "persons" ,
75- "max_table_nesting" : 0 ,
76- "endpoint" : {
77- "path" : f"cristin/organization/{ institution_code } /persons" , # noqa: E501
78- "data_selector" : "hits" ,
79- },
80- }
81- if persons
82- else None ,
83- {
84- "name" : "categories" ,
85- "max_table_nesting" : 0 ,
86- "endpoint" : {
87- "path" : "cristin/category/project" ,
88- "data_selector" : "hits" ,
89- },
90- }
91- if categories
92- else None ,
93- {
94- "name" : "funding_sources" ,
95- "max_table_nesting" : 0 ,
96- "endpoint" : {
97- "path" : "cristin/funding-sources" ,
98- "data_selector" : "hits" ,
99- },
100- }
101- if funding_sources
102- else None ,
103- ],
104- )
105- ),
106- }
107- )
20+ # {
21+ # "name": "projects",
22+ # "endpoint": {
23+ # "path": f"cristin/organization/{institution_code}/projects", # noqa: E501
24+ # "data_selector": "hits",
25+ # },
26+ # }
27+ # if projects
28+ # else None,
29+ # {
30+ # "name": "persons",
31+ # "endpoint": {
32+ # "path": f"cristin/organization/{institution_code}/persons", # noqa: E501
33+ # "data_selector": "hits",
34+ # },
35+ # }
36+ # if persons
37+ # else None,
38+ # {
39+ # "name": "categories",
40+ # "endpoint": {
41+ # "path": "cristin/category/project",
42+ # "data_selector": "hits",
43+ # },
44+ # }
45+ # if categories
46+ # else None,
47+ # {
48+ # "name": "funding_sources",
49+ # "endpoint": {
50+ # "path": "cristin/funding-sources",
51+ # "data_selector": "hits",
52+ # },
53+ # }
54+ # if funding_sources
55+ # else None,
10856
10957
11058@app .command ()
@@ -117,25 +65,49 @@ def run(
11765 base_url : str = NVA_BASE_URL ,
11866 duckdb_name : str = NVA_DUCKDB_NAME ,
11967 institution_code : str = INSTITUTION_CODE ,
120- year : int = None ,
12168):
69+ @dlt .source ()
70+ def nva ():
71+ client = RESTClient (
72+ base_url = base_url ,
73+ paginator = JSONLinkPaginator (next_url_path = "nextResults" ),
74+ data_selector = "hits" ,
75+ )
76+
77+ def get_resources ():
78+ for year in set (range (2025 , datetime .datetime .now ().year + 1 )):
79+ log .debug ("Fetching resources for year" , year = year )
80+ yield from client .paginate (
81+ "search/resources" ,
82+ method = "get" ,
83+ params = {
84+ "unit" : institution_code ,
85+ "publicationYearSince" : year ,
86+ "publicationYearBefore" : year + 1 ,
87+ },
88+ )
89+
90+ yield dlt .resource (
91+ get_resources (),
92+ name = "resources" ,
93+ write_disposition = "replace" ,
94+ max_table_nesting = 1 ,
95+ )
96+
12297 pipeline = dlt .pipeline (
12398 pipeline_name = duckdb_name ,
124- destination = "duckdb" ,
99+ destination = filesystem (
100+ bucket_url = "file://"
101+ + str (pathlib .Path (__name__ ).absolute ().parent / "data" ),
102+ layout = "{table_name}.{ext}" ,
103+ ),
125104 dataset_name = "main" ,
105+ progress = "log" ,
126106 )
127107
128- source = dlt_source (
129- year = year ,
130- resources = resources ,
131- projects = projects ,
132- persons = persons ,
133- categories = categories ,
134- funding_sources = funding_sources ,
135- base_url = base_url ,
136- institution_code = institution_code ,
108+ log .info (
109+ pipeline .run (nva (), write_disposition = "replace" , loader_file_format = "parquet" )
137110 )
138- log .info (pipeline .run (source ))
139111
140112
141113if __name__ == "__main__" :
0 commit comments