Skip to content

Commit

Permalink
Adjust sync code for series metadata (#1160)
Browse files Browse the repository at this point in the history
This repurposes the code from the events migration, since series
metadata is using the same format. With this, extended metadata and date
of creation is now harvested and stored in db series entries.

Note: This is only the backend part. We don't display any metadata for
series yet (so technically `changelog:user` is incorrect, but it isn't
really a `dev` change either).
  • Loading branch information
LukasKalbertodt committed Apr 23, 2024
2 parents 91fc1e4 + 1386a53 commit 366f9a9
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 3 deletions.
17 changes: 15 additions & 2 deletions backend/src/api/model/series.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use chrono::{DateTime, Utc};
use juniper::{graphql_object, GraphQLObject, GraphQLInputObject};
use postgres_types::ToSql;

Expand All @@ -12,7 +13,7 @@ use crate::{
},
Node,
},
db::{types::{SeriesState as State, Key}, util::impl_from_db},
db::{types::{ExtraMetadata, Key, SeriesState as State}, util::impl_from_db},
prelude::*,
};

Expand All @@ -22,6 +23,8 @@ pub(crate) struct Series {
opencast_id: String,
synced_data: Option<SyncedSeriesData>,
title: String,
created: Option<DateTime<Utc>>,
metadata: Option<ExtraMetadata>,
}

#[derive(GraphQLObject)]
Expand All @@ -32,13 +35,15 @@ struct SyncedSeriesData {
impl_from_db!(
Series,
select: {
series.{ id, opencast_id, state, title, description },
series.{ id, opencast_id, state, title, description, created, metadata },
},
|row| {
Series {
key: row.id(),
opencast_id: row.opencast_id(),
title: row.title(),
created: row.created(),
metadata: row.metadata(),
synced_data: (State::Ready == row.state()).then(
|| SyncedSeriesData {
description: row.description(),
Expand Down Expand Up @@ -109,6 +114,14 @@ impl Series {
&self.title
}

fn created(&self) -> &Option<DateTime<Utc>> {
&self.created
}

fn metadata(&self) -> &Option<ExtraMetadata> {
&self.metadata
}

fn synced_data(&self) -> &Option<SyncedSeriesData> {
&self.synced_data
}
Expand Down
1 change: 1 addition & 0 deletions backend/src/db/migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,4 +363,5 @@ static MIGRATIONS: Lazy<BTreeMap<u64, Migration>> = include_migrations![
28: "user-index-queue-triggers",
29: "extend-series-block",
30: "realm-permissions",
31: "series-metadata",
];
68 changes: 68 additions & 0 deletions backend/src/db/migrations/31-series-metadata.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
-- Adds `metadata` and `created` fields to `series`. Also adjusts the
-- `check_metadata_format` function from `events` to be usable in both
-- contexts, and adds new triggers.

alter table series
add column created timestamp with time zone,
add column metadata jsonb;

drop trigger check_metadata_format_on_insert on events;
drop function check_metadata_format;

-- The following function makes sure that the extra JSON metadata is always in a
-- predefined format. It is identical to the function defined in `05-events.sql`,
-- with the addition of a mandatory argument to declare which table is checked.
-- This can be either `events` or `series`, but can in theory be any table whose
-- entries include a `metadata` field.
create or replace function check_metadata_format() returns trigger as $$
declare
col text := tg_argv[0] || '.metadata';
namespace record;
field record;
element jsonb;
begin
if jsonb_typeof(new.metadata) <> 'object' then
raise exception '% is %, but should be a JSON object', col, jsonb_typeof(new.metadata);
end if;

for namespace in select * from jsonb_each(new.metadata) loop
if jsonb_typeof(namespace.value) <> 'object' then
raise exception '%: type of top level field "%" is %, but should be object',
col,
namespace.key,
jsonb_typeof(namespace.value);
end if;

for field in select * from jsonb_each(namespace.value) loop
if jsonb_typeof(field.value) <> 'array' then
raise exception '%: type of field "%.%" is %, but should be array',
col,
namespace.key,
field.key,
jsonb_typeof(field.value);
end if;

for element in select * from jsonb_array_elements(field.value) loop
if jsonb_typeof(element) <> 'string' then
raise exception '%: found non-string element "%" in "%.%", but that field should be a string array',
col,
element,
namespace.key,
field.key;
end if;
end loop;
end loop;
end loop;
return new;
end;
$$ language plpgsql;

create trigger check_event_metadata_format_on_upsert
before insert or update on events
for each row
execute procedure check_metadata_format('events');

create trigger check_series_metadata_format_on_upsert
before insert or update on series
for each row
execute procedure check_metadata_format('series');
12 changes: 11 additions & 1 deletion backend/src/sync/harvest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,15 @@ async fn store_in_db(
removed_events += 1;
}

HarvestItem::Series { id: opencast_id, title, description, updated, acl } => {
HarvestItem::Series {
id: opencast_id,
title,
description,
updated,
acl,
created,
metadata
} => {
// We first simply upsert the series.
let new_id = upsert(db, "series", "opencast_id", &[
("opencast_id", &opencast_id),
Expand All @@ -225,6 +233,8 @@ async fn store_in_db(
("read_roles", &acl.read),
("write_roles", &acl.write),
("updated", &updated),
("created", &created),
("metadata", &metadata),
]).await?;

// But now we have to fix the foreign key for any events that
Expand Down
3 changes: 3 additions & 0 deletions backend/src/sync/harvest/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ pub(crate) enum HarvestItem {
acl: Acl,
#[serde(with = "chrono::serde::ts_milliseconds")]
updated: DateTime<Utc>,
#[serde(with = "chrono::serde::ts_milliseconds")]
created: DateTime<Utc>,
metadata: ExtraMetadata,
},

#[serde(rename_all = "camelCase")]
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ type Series {
id: ID!
opencastId: String!
title: String!
created: DateTimeUtc
metadata: ExtraMetadata
syncedData: SyncedSeriesData
hostRealms: [Realm!]!
events(order: EventSortOrder = {column: "CREATED", direction: "DESCENDING"}): [AuthorizedEvent!]!
Expand Down

0 comments on commit 366f9a9

Please sign in to comment.