Skip to content

Commit 79acd2d

Browse files
job-mapping rename job_versions_io_mapping to job_io_mapping
Signed-off-by: Pawel Leszczynski <leszczynski.pawel@gmail.com>
1 parent b7e40f8 commit 79acd2d

10 files changed

Lines changed: 120 additions & 50 deletions

File tree

api/src/main/java/marquez/db/DbRetention.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ CREATE OR REPLACE FUNCTION delete_datasets_older_than_x_days()
338338
BEGIN
339339
CREATE TEMPORARY TABLE used_datasets_as_io_in_x_days AS (
340340
SELECT dataset_uuid
341-
FROM job_versions_io_mapping AS jvio INNER JOIN job_versions AS jv
341+
FROM job_io_mapping AS jvio INNER JOIN job_versions AS jv
342342
ON jvio.job_version_uuid = jv.uuid
343343
WHERE jv.created_at >= CURRENT_TIMESTAMP - INTERVAL '${retentionDays} days'
344344
);
@@ -621,7 +621,7 @@ CREATE OR REPLACE FUNCTION estimate_number_of_rows_older_than_x_days(retention_q
621621
"""
622622
CREATE TEMPORARY TABLE used_datasets_as_input_in_x_days AS (
623623
SELECT dataset_uuid
624-
FROM job_versions_io_mapping AS jvio INNER JOIN job_versions AS jv
624+
FROM job_io_mapping AS jvio INNER JOIN job_versions AS jv
625625
ON jvio.job_version_uuid = jv.uuid
626626
WHERE jv.created_at >= CURRENT_TIMESTAMP - INTERVAL '${retentionDays} days'
627627
AND jvio.io_type = 'INPUT'

api/src/main/java/marquez/db/JobVersionDao.java

Lines changed: 64 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ WITH job_version_io AS (
6969
JSON_AGG(json_build_object('namespace', ds.namespace_name,
7070
'name', ds.name))
7171
FILTER (WHERE io.io_type = 'OUTPUT') AS output_datasets
72-
FROM job_versions_io_mapping io
72+
FROM job_io_mapping io
7373
INNER JOIN job_versions jv ON jv.uuid = io.job_version_uuid
7474
INNER JOIN datasets_view ds ON ds.uuid = io.dataset_uuid
7575
INNER JOIN jobs_view j ON j.uuid=jv.job_uuid
@@ -192,40 +192,67 @@ ExtendedJobVersionRow upsertJobVersion(
192192
String namespaceName);
193193

194194
/**
195-
* Used to link an input dataset to a given job version.
195+
* Used to upsert an input or output dataset to a given job version.
196196
*
197197
* @param jobVersionUuid The unique ID of the job version.
198-
* @param inputDatasetUuid The unique ID of the input dataset.
198+
* @param datasetUuid The unique ID of the output dataset
199+
* @param ioType The {@link IoType} of the dataset.
200+
* @param jobUuid The unique ID of the job.
199201
*/
200-
default void upsertInputDatasetFor(UUID jobVersionUuid, UUID inputDatasetUuid) {
201-
upsertInputOrOutputDatasetFor(jobVersionUuid, inputDatasetUuid, IoType.INPUT);
202-
}
202+
@SqlUpdate(
203+
"""
204+
INSERT INTO job_io_mapping (
205+
job_version_uuid, dataset_uuid, io_type, job_uuid, is_job_version_current)
206+
VALUES (:jobVersionUuid, :datasetUuid, :ioType, :jobUuid, TRUE)
207+
ON CONFLICT (job_version_uuid, dataset_uuid, io_type, job_uuid) DO UPDATE SET is_job_version_current = TRUE
208+
""")
209+
void upsertCurrentInputOrOutputDatasetFor(
210+
UUID jobVersionUuid, UUID datasetUuid, UUID jobUuid, IoType ioType);
211+
212+
@SqlUpdate(
213+
"""
214+
UPDATE job_io_mapping
215+
SET is_job_version_current = FALSE
216+
WHERE (job_uuid = :jobUuid OR symlink_target_job_uuid = :jobUuid)
217+
AND job_version_uuid != :jobVersionUuid
218+
AND io_type = :ioType
219+
AND is_job_version_current = TRUE;
220+
""")
221+
void markVersionIOMappingNotCurrent(UUID jobVersionUuid, UUID jobUuid, IoType ioType);
222+
223+
@SqlUpdate(
224+
"""
225+
UPDATE job_io_mapping
226+
SET is_job_version_current = FALSE
227+
WHERE (job_uuid = :jobUuid OR symlink_target_job_uuid = :jobUuid)
228+
AND io_type = :ioType
229+
AND is_job_version_current = TRUE;
230+
""")
231+
void markVersionIOMappingNotCurrent(UUID jobUuid, IoType ioType);
203232

204233
/**
205-
* Used to link an output dataset to a given job version.
234+
* Used to link an input dataset to a given job version.
206235
*
207-
* @param jobVersionUuid The unique ID of the job version.
208-
* @param outputDatasetUuid The unique ID of the output dataset.
236+
* @param inputDatasetUuid The unique ID of the input dataset.
237+
* @param jobUuid The unique ID of the job.
209238
*/
210-
default void upsertOutputDatasetFor(UUID jobVersionUuid, UUID outputDatasetUuid) {
211-
upsertInputOrOutputDatasetFor(jobVersionUuid, outputDatasetUuid, IoType.OUTPUT);
239+
default void upsertInputDatasetFor(UUID jobVersionUuid, UUID inputDatasetUuid, UUID jobUuid) {
240+
markVersionIOMappingNotCurrent(jobVersionUuid, jobUuid, IoType.INPUT);
241+
upsertCurrentInputOrOutputDatasetFor(jobVersionUuid, inputDatasetUuid, jobUuid, IoType.INPUT);
242+
// TODO: include this in test -> check if jobUuid is set
212243
}
213244

214245
/**
215-
* Used to upsert an input or output dataset to a given job version.
246+
* Used to link an output dataset to a given job version.
216247
*
217-
* @param jobVersionUuid The unique ID of the job version.
218-
* @param datasetUuid The unique ID of the output dataset
219-
* @param ioType The {@link IoType} of the dataset.
248+
* @param outputDatasetUuid The unique ID of the output dataset.
249+
* @param jobUuid The unique ID of the job.
220250
*/
221-
@SqlUpdate(
222-
"""
223-
INSERT INTO job_versions_io_mapping (
224-
job_version_uuid, dataset_uuid, io_type)
225-
VALUES (:jobVersionUuid, :datasetUuid, :ioType)
226-
ON CONFLICT DO NOTHING
227-
""")
228-
void upsertInputOrOutputDatasetFor(UUID jobVersionUuid, UUID datasetUuid, IoType ioType);
251+
default void upsertOutputDatasetFor(UUID jobVersionUuid, UUID outputDatasetUuid, UUID jobUuid) {
252+
markVersionIOMappingNotCurrent(jobVersionUuid, jobUuid, IoType.OUTPUT);
253+
upsertCurrentInputOrOutputDatasetFor(jobVersionUuid, outputDatasetUuid, jobUuid, IoType.OUTPUT);
254+
// TODO: include this in test -> check if jobUuid is set
255+
}
229256

230257
/**
231258
* Returns the input datasets to a given job version.
@@ -256,7 +283,7 @@ default List<UUID> findOutputDatasetsFor(UUID jobVersionUuid) {
256283
@SqlQuery(
257284
"""
258285
SELECT dataset_uuid
259-
FROM job_versions_io_mapping
286+
FROM job_io_mapping
260287
WHERE job_version_uuid = :jobVersionUuid
261288
AND io_type = :ioType
262289
""")
@@ -265,7 +292,7 @@ default List<UUID> findOutputDatasetsFor(UUID jobVersionUuid) {
265292
@SqlQuery(
266293
"""
267294
SELECT d.namespace_name, d.name, io.io_type
268-
FROM job_versions_io_mapping io
295+
FROM job_io_mapping io
269296
INNER JOIN jobs_view j ON j.current_version_uuid = io.job_version_uuid
270297
INNER JOIN datasets_view d on d.uuid = io.dataset_uuid
271298
WHERE j.name = :jobName AND j.namespace_name=:jobNamespace
@@ -366,14 +393,18 @@ default BagOfJobVersionInfo upsertRunlessJobVersion(
366393
inputs.forEach(
367394
i -> {
368395
jobVersionDao.upsertInputDatasetFor(
369-
jobVersionRow.getUuid(), i.getDatasetVersionRow().getDatasetUuid());
396+
jobVersionRow.getUuid(),
397+
i.getDatasetVersionRow().getDatasetUuid(),
398+
jobVersionRow.getJobUuid());
370399
});
371400

372401
// Link the output datasets to the job version.
373402
outputs.forEach(
374403
o -> {
375404
jobVersionDao.upsertOutputDatasetFor(
376-
jobVersionRow.getUuid(), o.getDatasetVersionRow().getDatasetUuid());
405+
jobVersionRow.getUuid(),
406+
o.getDatasetVersionRow().getDatasetUuid(),
407+
jobVersionRow.getJobUuid());
377408
});
378409

379410
jobDao.updateVersionFor(jobRow.getUuid(), jobRow.getCreatedAt(), jobVersionRow.getUuid());
@@ -468,14 +499,18 @@ default BagOfJobVersionInfo upsertJobVersionOnRunTransition(
468499
jobVersionInputs.forEach(
469500
jobVersionInput -> {
470501
jobVersionDao.upsertInputDatasetFor(
471-
jobVersionRow.getUuid(), jobVersionInput.getDatasetUuid());
502+
jobVersionRow.getUuid(),
503+
jobVersionInput.getDatasetUuid(),
504+
jobVersionRow.getJobUuid());
472505
});
473506

474507
// Link the output datasets to the job version.
475508
jobVersionOutputs.forEach(
476509
jobVersionOutput -> {
477510
jobVersionDao.upsertOutputDatasetFor(
478-
jobVersionRow.getUuid(), jobVersionOutput.getDatasetUuid());
511+
jobVersionRow.getUuid(),
512+
jobVersionOutput.getDatasetUuid(),
513+
jobVersionRow.getJobUuid());
479514
});
480515

481516
// Link the job version to the run.

api/src/main/java/marquez/db/LineageDao.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ job_io AS (
5353
SELECT j.job_uuid,
5454
ARRAY_AGG(DISTINCT io.dataset_uuid) FILTER (WHERE io_type='INPUT') AS inputs,
5555
ARRAY_AGG(DISTINCT io.dataset_uuid) FILTER (WHERE io_type='OUTPUT') AS outputs
56-
FROM job_versions_io_mapping io
56+
FROM job_io_mapping io
5757
INNER JOIN job_current_version j ON io.job_version_uuid=j.job_version_uuid
5858
GROUP BY j.job_uuid
5959
),
@@ -99,7 +99,7 @@ WHERE ds.uuid IN (<dsUuids>)""")
9999
"""
100100
SELECT j.uuid FROM jobs j
101101
INNER JOIN job_versions jv ON jv.job_uuid = j.uuid
102-
INNER JOIN job_versions_io_mapping io ON io.job_version_uuid = jv.uuid
102+
INNER JOIN job_io_mapping io ON io.job_version_uuid = jv.uuid
103103
INNER JOIN datasets_view ds ON ds.uuid = io.dataset_uuid
104104
WHERE ds.name = :datasetName AND ds.namespace_name = :namespaceName
105105
ORDER BY io_type DESC, jv.created_at DESC

api/src/main/java/marquez/db/OpenLineageDao.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import marquez.common.models.SourceType;
3434
import marquez.db.DatasetFieldDao.DatasetFieldMapping;
3535
import marquez.db.JobVersionDao.BagOfJobVersionInfo;
36+
import marquez.db.JobVersionDao.IoType;
3637
import marquez.db.RunDao.RunUpsert;
3738
import marquez.db.RunDao.RunUpsert.RunUpsertBuilder;
3839
import marquez.db.mappers.LineageEventMapper;
@@ -370,6 +371,9 @@ default UpdateLineageRow updateBaseMarquezModel(LineageEvent event, ObjectMapper
370371
insertDatasetFacets(daos, dataset, record, runUuid, event.getEventType(), now);
371372
insertInputDatasetFacets(daos, dataset, record, runUuid, event.getEventType(), now);
372373
}
374+
} else {
375+
// mark job_io_mapping as non-current
376+
daos.getJobVersionDao().markVersionIOMappingNotCurrent(job.getUuid(), IoType.INPUT);
373377
}
374378
bag.setInputs(Optional.ofNullable(datasetInputs));
375379

@@ -383,6 +387,9 @@ default UpdateLineageRow updateBaseMarquezModel(LineageEvent event, ObjectMapper
383387
insertDatasetFacets(daos, dataset, record, runUuid, event.getEventType(), now);
384388
insertOutputDatasetFacets(daos, dataset, record, runUuid, event.getEventType(), now);
385389
}
390+
} else {
391+
// mark job_io_mapping as non-current
392+
daos.getJobVersionDao().markVersionIOMappingNotCurrent(job.getUuid(), IoType.OUTPUT);
386393
}
387394

388395
bag.setOutputs(Optional.ofNullable(datasetOutputs));

api/src/main/java/marquez/graphql/GraphqlDaos.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,14 @@ List<RowMap<String, Object>> getDistinctJobVersionsByDatasetVersionOutput(
109109
List<RowMap<String, Object>> getDatasetsByNamespace(UUID namespaceUuid);
110110

111111
@SqlQuery(
112-
"SELECT d.* from datasets_view d inner join job_versions_io_mapping m on m.dataset_uuid = d.uuid where m.job_version_uuid = :jobVersionUuid and io_type = :ioType")
112+
"SELECT d.* from datasets_view d inner join job_io_mapping m on m.dataset_uuid = d.uuid where m.job_version_uuid = :jobVersionUuid and io_type = :ioType")
113113
List<RowMap<String, Object>> getIOMappingByJobVersion(UUID jobVersionUuid, IoType ioType);
114114

115115
@SqlQuery(
116116
"SELECT jv.uuid, jv.created_at, jv.updated_at, jv.job_uuid, jv.version, jv.location, "
117117
+ " jv.latest_run_uuid, j.namespace_uuid, j.namespace_name, "
118118
+ " j.name AS job_name "
119-
+ " FROM job_versions_io_mapping m "
119+
+ " FROM job_io_mapping m "
120120
+ " inner join job_versions jv "
121121
+ " on m.dataset_uuid = jv.uuid"
122122
+ " inner join jobs_view j ON j.uuid=jv.job_uuid "
@@ -196,14 +196,14 @@ WITH RECURSIVE search_graph(job_name, namespace_name, depth, path, cycle) AS (
196196
(
197197
select j.name AS job_name, j.namespace_name, j.name as jx
198198
from jobs_view j
199-
inner join job_versions_io_mapping io_in on io_in.job_version_uuid = j.current_version_uuid and io_in.io_type = 'INPUT'
200-
inner join job_versions_io_mapping io_out on io_out.dataset_uuid = io_in.dataset_uuid and io_out.io_type = 'OUTPUT'
199+
inner join job_io_mapping io_in on io_in.job_version_uuid = j.current_version_uuid and io_in.io_type = 'INPUT'
200+
inner join job_io_mapping io_out on io_out.dataset_uuid = io_in.dataset_uuid and io_out.io_type = 'OUTPUT'
201201
inner join job_versions jv on jv.uuid = io_out.job_version_uuid
202202
UNION ALL
203203
select j.name AS job_name, jv.namespace_name, j.name as jx
204204
from jobs_view j
205-
inner join job_versions_io_mapping io_out on io_out.job_version_uuid = j.current_version_uuid and io_out.io_type = 'OUTPUT'
206-
inner join job_versions_io_mapping io_in on io_in.dataset_uuid = io_out.dataset_uuid and io_in.io_type = 'INPUT'
205+
inner join job_io_mapping io_out on io_out.job_version_uuid = j.current_version_uuid and io_out.io_type = 'OUTPUT'
206+
inner join job_io_mapping io_in on io_in.dataset_uuid = io_out.dataset_uuid and io_in.io_type = 'INPUT'
207207
inner join job_versions jv on jv.uuid = io_in.job_version_uuid
208208
) l where l.jx = sg.job_name and NOT cycle
209209
)
@@ -214,21 +214,21 @@ WITH RECURSIVE search_graph(job_name, namespace_name, depth, path, cycle) AS (
214214
-- input datasets
215215
left outer join (
216216
select io_out.job_version_uuid, jsonb_agg((SELECT x FROM (SELECT ds_in.name, ds_in.namespace_name as namespace, o.out_agg as "inEdges", i.in_agg as "outEdges") AS x)) as agg
217-
from job_versions_io_mapping io_out
217+
from job_io_mapping io_out
218218
inner join datasets_view ds_in on ds_in.uuid = io_out.dataset_uuid
219219
-- output jobs for each input dataset
220220
left outer join (
221221
select io_of_in.dataset_uuid, jsonb_agg((select x from (select j_of_in.name, j_of_in.namespace_name as namespace) as x)) as in_agg
222222
from jobs_view j_of_in
223-
left outer join job_versions_io_mapping io_of_in on io_of_in.job_version_uuid = j_of_in.current_version_uuid
223+
left outer join job_io_mapping io_of_in on io_of_in.job_version_uuid = j_of_in.current_version_uuid
224224
and io_of_in.io_type = 'INPUT'
225225
group by io_of_in.dataset_uuid
226226
) i on i.dataset_uuid = io_out.dataset_uuid
227227
-- input jobs for each input dataset
228228
left outer join (
229229
select io_of_out.dataset_uuid, jsonb_agg((select x from (select j_of_out.name, j_of_out.namespace_name as namespace) as x)) as out_agg
230230
from jobs_view j_of_out
231-
left outer join job_versions_io_mapping io_of_out
231+
left outer join job_io_mapping io_of_out
232232
on io_of_out.job_version_uuid = j_of_out.current_version_uuid
233233
and io_of_out.io_type = 'OUTPUT'
234234
group by io_of_out.dataset_uuid
@@ -240,21 +240,21 @@ select io_of_out.dataset_uuid, jsonb_agg((select x from (select j_of_out.name, j
240240
--output datasets
241241
left outer join(
242242
select io_out.job_version_uuid, jsonb_agg((SELECT x FROM (SELECT ds_in.name, ds_in.namespace_name as namespace, o.out_agg as "inEdges", i.in_agg as "outEdges") AS x)) as agg
243-
from job_versions_io_mapping io_out
243+
from job_io_mapping io_out
244244
inner join datasets_view ds_in on ds_in.uuid = io_out.dataset_uuid
245245
-- output jobs for each output dataset
246246
left outer join (
247247
select io_of_in.dataset_uuid, jsonb_agg((select x from (select j_of_in.name, j_of_in.namespace_name as namespace) as x)) as in_agg
248248
from jobs_view j_of_in
249-
left outer join job_versions_io_mapping io_of_in on io_of_in.job_version_uuid = j_of_in.current_version_uuid
249+
left outer join job_io_mapping io_of_in on io_of_in.job_version_uuid = j_of_in.current_version_uuid
250250
and io_of_in.io_type = 'INPUT'
251251
group by io_of_in.dataset_uuid
252252
) i on i.dataset_uuid = io_out.dataset_uuid
253253
-- input jobs for each output dataset
254254
left outer join (
255255
select io_of_out.dataset_uuid, jsonb_agg((select x from (select j_of_out.name, j_of_out.namespace_name as namespace) as x)) as out_agg
256256
from jobs_view j_of_out
257-
left outer join job_versions_io_mapping io_of_out
257+
left outer join job_io_mapping io_of_out
258258
on io_of_out.job_version_uuid = j_of_out.current_version_uuid
259259
and io_of_out.io_type = 'OUTPUT'
260260
group by io_of_out.dataset_uuid

api/src/main/resources/marquez/db/migration/R__1_Jobs_view_and_rewrite_function.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ BEGIN
111111
LEFT JOIN aliases a ON a.link_target_uuid = j.uuid
112112
) j
113113
WHERE jobs.uuid=j.uuid;
114+
UPDATE job_io_mapping
115+
SET symlink_target_job_uuid=j.symlink_target_uuid
116+
FROM jobs j
117+
WHERE job_io_mapping.job_uuid=j.uuid AND j.uuid = NEW.uuid;
114118
END IF;
115119
SELECT * INTO inserted_job FROM jobs_view
116120
WHERE uuid=job_uuid OR (new_symlink_target_uuid IS NOT NULL AND uuid=new_symlink_target_uuid);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
ALTER TABLE job_versions_io_mapping ADD COLUMN job_uuid uuid REFERENCES jobs(uuid) ON DELETE CASCADE;
2+
ALTER TABLE job_versions_io_mapping ADD COLUMN symlink_target_job_uuid uuid REFERENCES jobs(uuid) ON DELETE CASCADE;
3+
ALTER TABLE job_versions_io_mapping ADD COLUMN is_job_version_current boolean DEFAULT FALSE;
4+
5+
-- To add job_uuid to the unique constraint, we first drop the primary key, then recreate it; note given that job_version_uuid can be NULL, we need to check that job_version_uuid != NULL before inserting (duplicate columns otherwise)
6+
ALTER TABLE job_versions_io_mapping DROP CONSTRAINT job_versions_io_mapping_pkey;
7+
8+
ALTER TABLE job_versions_io_mapping RENAME TO job_io_mapping;
9+
ALTER TABLE job_io_mapping ALTER COLUMN job_version_uuid DROP NOT NULL;
10+
11+
-- TODO: create index for lineage query and update
12+
CREATE INDEX job_io_mapping_job_uuid ON job_io_mapping (job_uuid);
13+
14+
ALTER TABLE job_io_mapping ADD CONSTRAINT job_io_mapping_mapping_pkey UNIQUE (job_version_uuid, dataset_uuid, io_type, job_uuid);
15+
16+
17+
-- TODO: add a test which verifies correctness for UNIQUE <- adds multiple rows to job_io_mapping
18+
19+
-- TODO: take care of is_current
20+
-- TODO: take care of symlink_job_uuid

api/src/test/java/marquez/api/JdbiUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public static void cleanDatabase(Jdbi jdbi) {
2828
handle.execute("DELETE FROM run_facets");
2929
handle.execute("DELETE FROM runs");
3030
handle.execute("DELETE FROM run_args");
31-
handle.execute("DELETE FROM job_versions_io_mapping");
31+
handle.execute("DELETE FROM job_io_mapping");
3232
handle.execute("DELETE FROM job_versions");
3333
handle.execute("DELETE FROM jobs_fqn");
3434
handle.execute("DELETE FROM jobs");

api/src/test/java/marquez/db/JobVersionDaoTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,8 @@ public void testGetJobVersion() {
190190
.orElseThrow(
191191
() -> new IllegalStateException("Can't find test dataset " + ds.getName()));
192192

193-
jobVersionDao.upsertInputDatasetFor(jobVersionRow.getUuid(), dataset.getUuid());
193+
jobVersionDao.upsertInputDatasetFor(
194+
jobVersionRow.getUuid(), dataset.getUuid(), jobVersionRow.getJobUuid());
194195
}
195196
for (DatasetId ds : jobMeta.getOutputs()) {
196197
DatasetRow dataset =
@@ -199,7 +200,8 @@ public void testGetJobVersion() {
199200
.orElseThrow(
200201
() -> new IllegalStateException("Can't find test dataset " + ds.getName()));
201202

202-
jobVersionDao.upsertOutputDatasetFor(jobVersionRow.getUuid(), dataset.getUuid());
203+
jobVersionDao.upsertOutputDatasetFor(
204+
jobVersionRow.getUuid(), dataset.getUuid(), jobVersionRow.getJobUuid());
203205
}
204206
Optional<JobVersion> jobVersion =
205207
jobVersionDao.findJobVersion(namespaceRow.getName(), jobRow.getName(), version.getValue());

0 commit comments

Comments
 (0)