namespace _zeitbild.repository.calendar { /** */ type type_dispersal = { core_row : Record< string, any >; access_attributed_rows : Array< Record< string, any > >; }; /** */ var _core_store : ( null | lib_plankton.storage.type_store< _zeitbild.type_calendar_id, Record, {}, lib_plankton.storage.type_sql_table_autokey_search_term, Record > ) = null; /** */ var _access_attributed_chest : ( null | lib_plankton.storage.type_chest< Array, Record, lib_plankton.database.type_description_create_table, lib_plankton.storage.sql_table_common.type_sql_table_common_search_term, Record > ) = null; /** */ function get_core_store( ) : lib_plankton.storage.type_store< _zeitbild.type_calendar_id, Record, {}, lib_plankton.storage.type_sql_table_autokey_search_term, Record > { if (_core_store === null) { _core_store = lib_plankton.storage.sql_table_autokey_store( { "database_implementation": _zeitbild.database.get_implementation(), "table_name": "calendars", "key_name": "id", } ); } else { // do nothing } return _core_store; } /** */ function get_access_attributed_chest( ) : lib_plankton.storage.type_chest< Array, Record, lib_plankton.database.type_description_create_table, lib_plankton.storage.sql_table_common.type_sql_table_common_search_term, Record > { if (_access_attributed_chest === null) { _access_attributed_chest = lib_plankton.storage.sql_table_common.chest( { "database_implementation": _zeitbild.database.get_implementation(), "table_name": "calendar_access_attributed", "key_names": ["calendar_id","user_id"], } ); } else { // do nothing } return _access_attributed_chest; } /** */ function encode_access_level( access_level : _zeitbild.enum_access_level ) : int { return ( [ _zeitbild.enum_access_level.none, _zeitbild.enum_access_level.view, _zeitbild.enum_access_level.edit, _zeitbild.enum_access_level.admin, ].indexOf(access_level) ); } /** */ function decode_access_level( access_level_encoded : int ) : _zeitbild.enum_access_level { return ( [ _zeitbild.enum_access_level.none, _zeitbild.enum_access_level.view, _zeitbild.enum_access_level.edit, _zeitbild.enum_access_level.admin, ][access_level_encoded] ); } /** */ function encode( object : _zeitbild.type_calendar_object ) : type_dispersal { return { "core_row": { "name": object.name, "access_public": object.access.public, "access_level_default": encode_access_level(object.access.default_level), "resource_id": object.resource_id, }, "access_attributed_rows": ( lib_plankton.map.dump(object.access.attributed) .map( ({"key": user_id, "value": level}) => ({ // "calendar_id": calendar_id, "user_id": user_id, "level": encode_access_level(level), }) ) ), }; } /** */ function decode( dispersal : type_dispersal ) : _zeitbild.type_calendar_object { return { "name": dispersal.core_row["name"], "access": { "public": dispersal.core_row["access_public"], "default_level": decode_access_level(dispersal.core_row["access_level_default"]), "attributed": lib_plankton.map.hashmap.implementation_map( lib_plankton.map.hashmap.make<_zeitbild.type_user_id, _zeitbild.enum_access_level>( x => x.toFixed(0), { "pairs": ( dispersal.access_attributed_rows .map( (access_attributed_row) => ({ // "calendar_id": access_attributed_row["calendar_id"], "key": access_attributed_row["preview"]["user_id"], "value": decode_access_level(access_attributed_row["preview"]["level"]), }) ) ), } ) ), }, "resource_id": dispersal.core_row["resource_id"], }; } /** */ export function read( id : _zeitbild.type_calendar_id ) : Promise<_zeitbild.type_calendar_object> { return ( get_core_store().read(id) .then( (core_row) => ( get_access_attributed_chest().search( { "expression": "(calendar_id = $calendar_id)", "arguments": { "calendar_id": id, } } ) .then( (access_attributed_rows) => Promise.resolve( { "core_row": core_row, "access_attributed_rows": access_attributed_rows, } ) ) .then( (dispersal) => Promise.resolve<_zeitbild.type_calendar_object>( decode(dispersal) ) ) ) ) ); } /** */ export async function create( calendar_object : _zeitbild.type_calendar_object ) : Promise<_zeitbild.type_calendar_id> { const dispersal : type_dispersal = encode(calendar_object); const core_store = get_core_store(); const calendar_id : _zeitbild.type_calendar_id = await core_store.create( dispersal.core_row ); for await (const access_attributed_row of dispersal.access_attributed_rows) { get_access_attributed_chest().write( [calendar_id, access_attributed_row["user_id"]], {"level": access_attributed_row["level"]} ); } await lib_plankton.cache.clear(_zeitbild.cache_regular); return Promise.resolve<_zeitbild.type_calendar_id>(calendar_id); } /** */ export async function update( calendar_id : _zeitbild.type_calendar_id, calendar_object : _zeitbild.type_calendar_object ) : Promise { const dispersal : type_dispersal = encode(calendar_object); // core { const core_store = get_core_store(); await core_store.update( calendar_id, dispersal.core_row ); } // attributed access { const access_attributed_chest = get_access_attributed_chest(); const hits : Array> = await access_attributed_chest.search( { "expression": "(calendar_id = $calendar_id)", "arguments": { "calendar_id": calendar_id, } } ); const contrast = lib_plankton.list.contrast< Record, Record >( hits, hit => hit["user_id"], dispersal.access_attributed_rows, row => row["user_id"] ); // delete for await (const entry of contrast.only_left) { await access_attributed_chest.delete( [calendar_id, entry.left["user_id"]] ); } // update for await (const entry of contrast.both) { await access_attributed_chest.write( [calendar_id, entry.right["user_id"]], {"level": entry.right["level"]} ); } // create for await (const entry of contrast.only_right) { await access_attributed_chest.write( [calendar_id, entry.right["user_id"]], {"level": entry.right["level"]} ); } } await lib_plankton.cache.clear(_zeitbild.cache_regular); return Promise.resolve(undefined); } /** * @todo remove events from resource? */ export async function delete_( calendar_id : _zeitbild.type_calendar_id ) : Promise { await lib_plankton.cache.clear(_zeitbild.cache_regular); const core_store = get_core_store(); const access_attributed_chest = get_access_attributed_chest(); // attributed access { const hits : Array> = await access_attributed_chest.search( { "expression": "(calendar_id = $calendar_id)", "arguments": { "calendar_id": calendar_id, } } ); for await (const hit of hits) { await access_attributed_chest.delete( [calendar_id, hit["user_id"]] ); } } // core { await core_store.delete( calendar_id ); } return Promise.resolve(undefined); } /** */ type type_overview_entry = { id : _zeitbild.type_calendar_id; name : string; access_level : _zeitbild.enum_access_level; } /** * @todo caching */ export async function overview( user_id : (null | _zeitbild.type_user_id) ) : Promise< Array< type_overview_entry > > { return lib_plankton.cache.get_complex>( _zeitbild.cache_regular, "calendar_overview", { "user_id": user_id, }, null, () => ( lib_plankton.file.read("sql/calendar_overview.sql") .then( (template) => _zeitbild.database.get_implementation().query_free_get( { "template": template, "arguments": { "user_id": user_id, } } ) ) .then( (rows) => Promise.resolve( lib_plankton.call.convey( rows, [ (x : Array>) => x.map( (row : Record) => ({ "id": row["id"], "name": row["name"], /** * @todo unite with _zeitbild.service.calendar.get_access_level */ "access_level": decode_access_level( Math.max( (row["access_public"] ? 1 : 0), ( (user_id === null) ? 0 : (row["access_level_attributed"] ?? row["access_level_default"]) ) ) ), }) ), (x : Array) => x.filter( (row) => ( ! _zeitbild.value_object.access_level.order( row.access_level, _zeitbild.enum_access_level.none ) ) ), (x : Array) => lib_plankton.list.sorted( x, { "compare_element": lib_plankton.order.order_lexicographic_pair_wrapped( row => row.access_level, row => row.id, { "order_first": (a, b) => _zeitbild.value_object.access_level.order(b, a), "order_second": (a, b) => (a <= b) } ), } ), ] ) ) ) ) ); } }