diff --git a/moped-database/metadata/tables.yaml b/moped-database/metadata/tables.yaml index 0559ad3973..977b5af849 100644 --- a/moped-database/metadata/tables.yaml +++ b/moped-database/metadata/tables.yaml @@ -1,3 +1,47 @@ +- table: + name: moped_project_types + schema: deprecated + object_relationships: + - name: moped_type + using: + foreign_key_constraint_on: project_type_id +- table: + name: moped_types + schema: deprecated + select_permissions: + - role: moped-admin + permission: + columns: + - type_name + - type_id + - active_type + - on_street + - sensitivity + - type_order + - date_added + filter: {} + - role: moped-editor + permission: + columns: + - type_name + - type_id + - active_type + - on_street + - sensitivity + - type_order + - date_added + filter: {} + - role: moped-viewer + permission: + columns: + - type_name + - type_id + - active_type + - on_street + - sensitivity + - type_order + - date_added + filter: {} - table: name: component_arcgis_online_view schema: public @@ -79,7 +123,6 @@ - substantial_completion_date - substantial_completion_date_estimated - task_order_names - - type_name - workgroup_contractors filter: {} comment: "" @@ -160,7 +203,6 @@ - substantial_completion_date - substantial_completion_date_estimated - task_order_names - - type_name - workgroup_contractors filter: {} comment: "" @@ -241,7 +283,6 @@ - substantial_completion_date - substantial_completion_date_estimated - task_order_names - - type_name - workgroup_contractors filter: {} comment: "" @@ -4312,7 +4353,7 @@ column: project_id table: name: moped_project_types - schema: public + schema: deprecated - name: moped_projects using: foreign_key_constraint_on: @@ -4787,138 +4828,6 @@ - project_role_name - role_order filter: {} -- table: - name: moped_project_types - schema: public - object_relationships: - - name: moped_type - using: - foreign_key_constraint_on: project_type_id - insert_permissions: - - role: moped-admin - permission: - check: {} - set: - created_by_user_id: x-hasura-user-db-id - updated_by_user_id: x-hasura-user-db-id - columns: - - is_deleted - - project_id - - project_type_id - - role: moped-editor - permission: - check: {} - set: - created_by_user_id: x-hasura-user-db-id - updated_by_user_id: x-hasura-user-db-id - columns: - - is_deleted - - project_id - - project_type_id - select_permissions: - - role: moped-admin - permission: - columns: - - created_at - - created_by_user_id - - id - - is_deleted - - project_id - - project_type_id - - updated_at - - updated_by_user_id - filter: {} - - role: moped-editor - permission: - columns: - - created_at - - created_by_user_id - - id - - is_deleted - - project_id - - project_type_id - - updated_at - - updated_by_user_id - filter: {} - - role: moped-viewer - permission: - columns: - - created_at - - created_by_user_id - - id - - is_deleted - - project_id - - project_type_id - - updated_at - - updated_by_user_id - filter: {} - update_permissions: - - role: moped-admin - permission: - columns: - - is_deleted - - project_id - - project_type_id - filter: {} - check: null - set: - updated_by_user_id: x-hasura-user-db-id - - role: moped-editor - permission: - columns: - - is_deleted - - project_id - - project_type_id - filter: {} - check: null - set: - updated_by_user_id: x-hasura-user-db-id - event_triggers: - - name: activity_log_moped_project_types - definition: - enable_manual: false - insert: - columns: '*' - update: - columns: '*' - retry_conf: - interval_sec: 10 - num_retries: 0 - timeout_sec: 60 - webhook_from_env: HASURA_ENDPOINT - headers: - - name: x-hasura-admin-secret - value_from_env: ACTIVITY_LOG_API_SECRET - request_transform: - body: - action: transform - template: |- - { - "query": "mutation InsertActivity($object: moped_activity_log_insert_input!) { insert_moped_activity_log_one(object: $object) { activity_id } }", - "variables": { - "object": { - "record_id": {{ $body.event.data.new.id }}, - "record_type": {{ $body.table.name }}, - "activity_id": {{ $body.id }}, - "record_project_id": {{ $body.event.data.new.project_id }}, - "record_data": {"event": {{ $body.event }}}, - "description": [{"newSchema": "true"}], - "operation_type": {{ $body.event.op }}, - "updated_by_user_id": {{ $session_variables?['x-hasura-user-db-id'] ?? 1}} - } - } - } - method: POST - query_params: {} - template_engine: Kriti - version: 2 - cleanup_config: - batch_size: 10000 - clean_invocation_logs: false - clear_older_than: 168 - paused: true - schedule: 0 0 * * * - timeout: 60 - table: name: moped_public_process_statuses schema: public @@ -5037,43 +4946,6 @@ - slug - is_deleted filter: {} -- table: - name: moped_types - schema: public - select_permissions: - - role: moped-admin - permission: - columns: - - type_name - - type_id - - active_type - - on_street - - sensitivity - - type_order - - date_added - filter: {} - - role: moped-editor - permission: - columns: - - type_name - - type_id - - active_type - - on_street - - sensitivity - - type_order - - date_added - filter: {} - - role: moped-viewer - permission: - columns: - - type_name - - type_id - - active_type - - on_street - - sensitivity - - type_order - - date_added - filter: {} - table: name: moped_user_events schema: public @@ -5612,7 +5484,6 @@ - task_order_names - task_order_names_short - task_orders - - type_name - updated_at - workgroup_contractors filter: {} @@ -5665,7 +5536,6 @@ - task_order_names - task_order_names_short - task_orders - - type_name - updated_at - workgroup_contractors filter: {} @@ -5718,7 +5588,6 @@ - task_order_names - task_order_names_short - task_orders - - type_name - updated_at - workgroup_contractors filter: {} diff --git a/moped-database/migrations/1737754622032_deprecate_type_tables/down.sql b/moped-database/migrations/1737754622032_deprecate_type_tables/down.sql new file mode 100644 index 0000000000..3ba427ec4c --- /dev/null +++ b/moped-database/migrations/1737754622032_deprecate_type_tables/down.sql @@ -0,0 +1,574 @@ +ALTER TABLE deprecated.moped_types +SET SCHEMA public; + +ALTER TABLE deprecated.moped_project_types +SET SCHEMA public; + +DROP SCHEMA IF EXISTS deprecated; + +-- Restore moped_types and moped_project_types in database views +DROP VIEW IF EXISTS exploded_component_arcgis_online_view; +DROP VIEW IF EXISTS component_arcgis_online_view; +DROP VIEW IF EXISTS project_list_view; + +CREATE OR REPLACE VIEW project_list_view AS WITH project_person_list_lookup AS ( + SELECT + mpp.project_id, + string_agg(DISTINCT concat(mu.first_name, ' ', mu.last_name, ':', mpr.project_role_name), ','::text) AS project_team_members + FROM moped_proj_personnel mpp + JOIN moped_users mu ON mpp.user_id = mu.user_id + JOIN moped_proj_personnel_roles mppr ON mpp.project_personnel_id = mppr.project_personnel_id + JOIN moped_project_roles mpr ON mppr.project_role_id = mpr.project_role_id + WHERE mpp.is_deleted = false AND mppr.is_deleted = false + GROUP BY mpp.project_id +), + +funding_sources_lookup AS ( + SELECT + mpf.project_id, + string_agg( + DISTINCT mfs.funding_source_name, ', '::text + ORDER BY mfs.funding_source_name + ) AS funding_source_name, + string_agg( + DISTINCT mfp.funding_program_name, ', '::text + ORDER BY mfp.funding_program_name + ) AS funding_program_names, + string_agg( + DISTINCT + CASE + WHEN mfs.funding_source_name IS NOT null AND mfp.funding_program_name IS NOT null THEN concat(mfs.funding_source_name, ' - ', mfp.funding_program_name) + WHEN mfs.funding_source_name IS NOT null THEN mfs.funding_source_name + WHEN mfp.funding_program_name IS NOT null THEN mfp.funding_program_name + ELSE null::text + END, ', '::text + ORDER BY ( + CASE + WHEN mfs.funding_source_name IS NOT null AND mfp.funding_program_name IS NOT null THEN concat(mfs.funding_source_name, ' - ', mfp.funding_program_name) + WHEN mfs.funding_source_name IS NOT null THEN mfs.funding_source_name + WHEN mfp.funding_program_name IS NOT null THEN mfp.funding_program_name + ELSE null::text + END + ) + ) AS funding_source_and_program_names + FROM moped_proj_funding mpf + LEFT JOIN moped_fund_sources mfs ON mpf.funding_source_id = mfs.funding_source_id + LEFT JOIN moped_fund_programs mfp ON mpf.funding_program_id = mfp.funding_program_id + WHERE mpf.is_deleted = false + GROUP BY mpf.project_id +), + +project_type_lookup AS ( + SELECT + mpt.project_id, + string_agg(mt.type_name, ', '::text) AS type_name + FROM moped_project_types mpt + LEFT JOIN moped_types mt ON mpt.project_type_id = mt.type_id AND mpt.is_deleted = false + GROUP BY mpt.project_id +), + +child_project_lookup AS ( + SELECT + jsonb_agg(children.project_id) AS children_project_ids, + children.parent_project_id AS parent_id + FROM moped_project children + JOIN moped_project parent ON children.parent_project_id = parent.project_id + WHERE children.is_deleted = false + GROUP BY children.parent_project_id +), + +work_activities AS ( + SELECT + mpwa.project_id, + string_agg(task_order_objects.task_order_object ->> 'display_name'::text, ', '::text) AS task_order_names, + string_agg(task_order_objects.task_order_object ->> 'task_order'::text, ', '::text) AS task_order_names_short, + jsonb_agg(DISTINCT task_order_objects.task_order_object) FILTER (WHERE task_order_objects.task_order_object IS NOT null) AS task_orders, + string_agg(DISTINCT mpwa.workgroup_contractor, ', '::text) AS workgroup_contractors, + string_agg(mpwa.contract_number, ', '::text) AS contract_numbers + FROM moped_proj_work_activity mpwa + LEFT JOIN LATERAL jsonb_array_elements(mpwa.task_orders) task_order_objects (task_order_object) ON true + WHERE 1 = 1 AND mpwa.is_deleted = false + GROUP BY mpwa.project_id +), + +moped_proj_components_subtypes AS ( + SELECT + mpc.project_id, + string_agg(DISTINCT mc.component_name_full, ', '::text) AS components + FROM moped_proj_components mpc + LEFT JOIN moped_components mc ON mpc.component_id = mc.component_id + WHERE mpc.is_deleted = false + GROUP BY mpc.project_id +), + +project_district_association AS ( + WITH project_council_district_map AS ( + SELECT DISTINCT + moped_project.project_id, + features_council_districts.council_district_id + FROM moped_project + LEFT JOIN moped_proj_components ON moped_project.project_id = moped_proj_components.project_id + LEFT JOIN features ON moped_proj_components.project_component_id = features.component_id + LEFT JOIN features_council_districts ON features.id = features_council_districts.feature_id + WHERE features.is_deleted IS false AND moped_proj_components.is_deleted IS false + ), + +parent_child_project_map AS ( + SELECT + parent_projects.project_id, + unnest(ARRAY[parent_projects.project_id] || array_agg(child_projects.project_id)) AS self_and_children_project_ids + FROM moped_project parent_projects + LEFT JOIN moped_project child_projects ON parent_projects.project_id = child_projects.parent_project_id + GROUP BY parent_projects.project_id + ORDER BY parent_projects.project_id + ) + + SELECT + projects.project_id, + array_agg(DISTINCT project_districts.council_district_id) FILTER (WHERE project_districts.council_district_id IS NOT null) AS project_council_districts, + array_agg(DISTINCT project_and_children_districts.council_district_id) FILTER (WHERE project_and_children_districts.council_district_id IS NOT null) AS project_and_child_project_council_districts + FROM parent_child_project_map projects + LEFT JOIN project_council_district_map project_and_children_districts ON projects.self_and_children_project_ids = project_and_children_districts.project_id + LEFT JOIN project_council_district_map project_districts ON projects.project_id = project_districts.project_id + GROUP BY projects.project_id +), + +min_confirmed_phase_dates AS ( + WITH min_dates AS ( + SELECT + phases.project_id, + min(phases.phase_start) AS min_date + FROM moped_proj_phases phases + LEFT JOIN moped_phases ON phases.phase_id = moped_phases.phase_id + WHERE true AND phases.phase_start IS NOT null AND phases.is_phase_start_confirmed = true AND moped_phases.phase_name_simple = 'Complete'::text AND phases.is_deleted = false + GROUP BY phases.project_id + UNION ALL + SELECT + phases.project_id, + min(phases.phase_end) AS min_date + FROM moped_proj_phases phases + LEFT JOIN moped_phases ON phases.phase_id = moped_phases.phase_id + WHERE true AND phases.phase_end IS NOT null AND phases.is_phase_end_confirmed = true AND moped_phases.phase_name_simple = 'Complete'::text AND phases.is_deleted = false + GROUP BY phases.project_id + ) + + SELECT + min_dates.project_id, + min(min_dates.min_date) AS min_phase_date + FROM min_dates + GROUP BY min_dates.project_id +), + +min_estimated_phase_dates AS ( + WITH min_dates AS ( + SELECT + phases.project_id, + min(phases.phase_start) AS min_date + FROM moped_proj_phases phases + LEFT JOIN moped_phases ON phases.phase_id = moped_phases.phase_id + WHERE true AND phases.phase_start IS NOT null AND phases.is_phase_start_confirmed = false AND moped_phases.phase_name_simple = 'Complete'::text AND phases.is_deleted = false + GROUP BY phases.project_id + UNION ALL + SELECT + phases.project_id, + min(phases.phase_end) AS min_date + FROM moped_proj_phases phases + LEFT JOIN moped_phases ON phases.phase_id = moped_phases.phase_id + WHERE true AND phases.phase_end IS NOT null AND phases.is_phase_end_confirmed = false AND moped_phases.phase_name_simple = 'Complete'::text AND phases.is_deleted = false + GROUP BY phases.project_id + ) + + SELECT + min_dates.project_id, + min(min_dates.min_date) AS min_phase_date + FROM min_dates + GROUP BY min_dates.project_id +), + +project_component_work_types AS ( + SELECT + mpc.project_id, + string_agg( + DISTINCT mwt.name, ', '::text + ORDER BY mwt.name + ) AS component_work_type_names + FROM moped_proj_components mpc + LEFT JOIN moped_proj_component_work_types mpcwt ON mpcwt.project_component_id = mpc.project_component_id + LEFT JOIN moped_work_types mwt ON mwt.id = mpcwt.work_type_id + WHERE true AND mpc.is_deleted = false AND mpcwt.is_deleted = false + GROUP BY mpc.project_id +) + +SELECT + mp.project_id, + mp.project_name_full, + mp.project_name, + mp.project_name_secondary, + mp.project_description, + mp.ecapris_subproject_id, + mp.project_website, + mp.date_added, + mp.is_deleted, + mp.updated_at, + current_phase.phase_name AS current_phase, + current_phase.phase_key AS current_phase_key, + current_phase.phase_name_simple AS current_phase_simple, + ppll.project_team_members, + me.entity_name AS project_sponsor, + mel.entity_name AS project_lead, + mpps.name AS public_process_status, + mp.interim_project_id, + mp.parent_project_id, + mp.knack_project_id, + 'https://mobility.austin.gov/moped/projects/'::text || mp.project_id::text AS project_url, + 'https://mobility.austin.gov/moped/projects/'::text || mp.parent_project_id::text AS parent_project_url, + proj_status_update.project_note AS project_status_update, + proj_status_update.date_created AS project_status_update_date_created, + work_activities.workgroup_contractors, + work_activities.contract_numbers, + work_activities.task_order_names, + work_activities.task_order_names_short, + work_activities.task_orders, + ( + SELECT moped_project.project_name_full + FROM moped_project + WHERE moped_project.project_id = mp.parent_project_id + ) AS parent_project_name, + cpl.children_project_ids, + string_agg(DISTINCT me2.entity_name, ', '::text) AS project_partners, + ( + SELECT json_agg(json_build_object('signal_id', feature_signals.signal_id, 'knack_id', feature_signals.knack_id, 'location_name', feature_signals.location_name, 'signal_type', feature_signals.signal_type, 'id', feature_signals.id)) AS json_agg + FROM moped_proj_components components + LEFT JOIN feature_signals ON components.project_component_id = feature_signals.component_id + WHERE true AND components.is_deleted = false AND components.project_id = mp.project_id AND feature_signals.signal_id IS NOT null AND feature_signals.is_deleted = false + ) AS project_feature, + fsl.funding_source_name, + fsl.funding_program_names, + fsl.funding_source_and_program_names, + ptl.type_name, + ( + SELECT min(phases.phase_start) AS min + FROM moped_proj_phases phases + WHERE true AND phases.project_id = mp.project_id AND phases.phase_id = 9 AND phases.is_deleted = false + ) AS construction_start_date, + mcpd.min_phase_date AS substantial_completion_date, + CASE + WHEN mcpd.min_phase_date IS NOT null THEN null::timestamp with time zone + ELSE mepd.min_phase_date + END AS substantial_completion_date_estimated, + ( + SELECT string_agg(concat(users.first_name, ' ', users.last_name), ', '::text) AS string_agg + FROM moped_proj_personnel mpp + JOIN moped_users users ON mpp.user_id = users.user_id + JOIN moped_proj_personnel_roles mppr ON mpp.project_personnel_id = mppr.project_personnel_id + JOIN moped_project_roles mpr ON mppr.project_role_id = mpr.project_role_id + WHERE 1 = 1 AND mpr.project_role_name = 'Inspector'::text AND mpp.is_deleted = false AND mppr.is_deleted = false AND mpp.project_id = mp.project_id + GROUP BY mpp.project_id + ) AS project_inspector, + ( + SELECT string_agg(concat(users.first_name, ' ', users.last_name), ', '::text) AS string_agg + FROM moped_proj_personnel mpp + JOIN moped_users users ON mpp.user_id = users.user_id + JOIN moped_proj_personnel_roles mppr ON mpp.project_personnel_id = mppr.project_personnel_id + JOIN moped_project_roles mpr ON mppr.project_role_id = mpr.project_role_id + WHERE 1 = 1 AND mpr.project_role_name = 'Designer'::text AND mpp.is_deleted = false AND mppr.is_deleted = false AND mpp.project_id = mp.project_id + GROUP BY mpp.project_id + ) AS project_designer, + ( + SELECT string_agg(tags.name, ', '::text) AS string_agg + FROM moped_proj_tags ptags + JOIN moped_tags tags ON ptags.tag_id = tags.id + WHERE 1 = 1 AND ptags.is_deleted = false AND ptags.project_id = mp.project_id + GROUP BY ptags.project_id + ) AS project_tags, + concat(added_by_user.first_name, ' ', added_by_user.last_name) AS added_by, + mpcs.components, + districts.project_council_districts, + districts.project_and_child_project_council_districts, + pcwt.component_work_type_names +FROM moped_project mp +LEFT JOIN project_person_list_lookup ppll ON mp.project_id = ppll.project_id +LEFT JOIN funding_sources_lookup fsl ON mp.project_id = fsl.project_id +LEFT JOIN project_type_lookup ptl ON mp.project_id = ptl.project_id +LEFT JOIN moped_entity me ON mp.project_sponsor = me.entity_id +LEFT JOIN moped_entity mel ON mp.project_lead_id = mel.entity_id +LEFT JOIN moped_proj_partners mpp2 ON mp.project_id = mpp2.project_id AND mpp2.is_deleted = false +LEFT JOIN moped_entity me2 ON mpp2.entity_id = me2.entity_id +LEFT JOIN work_activities ON mp.project_id = work_activities.project_id +LEFT JOIN moped_users added_by_user ON mp.added_by = added_by_user.user_id +LEFT JOIN current_phase_view current_phase ON mp.project_id = current_phase.project_id +LEFT JOIN moped_public_process_statuses mpps ON mp.public_process_status_id = mpps.id +LEFT JOIN child_project_lookup cpl ON mp.project_id = cpl.parent_id +LEFT JOIN moped_proj_components_subtypes mpcs ON mp.project_id = mpcs.project_id +LEFT JOIN project_district_association districts ON mp.project_id = districts.project_id +LEFT JOIN min_confirmed_phase_dates mcpd ON mp.project_id = mcpd.project_id +LEFT JOIN min_estimated_phase_dates mepd ON mp.project_id = mepd.project_id +LEFT JOIN project_component_work_types pcwt ON mp.project_id = pcwt.project_id +LEFT JOIN LATERAL ( + SELECT + mpn.project_note, + mpn.created_at AS date_created + FROM moped_proj_notes mpn + WHERE mpn.project_id = mp.project_id AND mpn.project_note_type = 2 AND mpn.is_deleted = false + ORDER BY mpn.created_at DESC + LIMIT 1 +) proj_status_update ON true +WHERE mp.is_deleted = false +GROUP BY mp.project_id, mp.project_name, mp.project_description, ppll.project_team_members, mp.ecapris_subproject_id, mp.date_added, mp.is_deleted, me.entity_name, mel.entity_name, mp.updated_at, mp.interim_project_id, mp.parent_project_id, mp.knack_project_id, current_phase.phase_name, current_phase.phase_key, current_phase.phase_name_simple, ptl.type_name, mpcs.components, fsl.funding_source_name, fsl.funding_program_names, fsl.funding_source_and_program_names, added_by_user.first_name, added_by_user.last_name, mpps.name, cpl.children_project_ids, proj_status_update.project_note, proj_status_update.date_created, work_activities.workgroup_contractors, work_activities.contract_numbers, work_activities.task_order_names, work_activities.task_order_names_short, work_activities.task_orders, districts.project_council_districts, districts.project_and_child_project_council_districts, mepd.min_phase_date, mcpd.min_phase_date, pcwt.component_work_type_names; + +CREATE OR REPLACE VIEW component_arcgis_online_view AS WITH work_types AS ( + SELECT + mpcwt.project_component_id, + string_agg(mwt.name, ', '::text) AS work_types + FROM moped_proj_component_work_types mpcwt + LEFT JOIN moped_work_types mwt ON mpcwt.work_type_id = mwt.id + WHERE mpcwt.is_deleted = false + GROUP BY mpcwt.project_component_id +), + +council_districts AS ( + SELECT + features.component_id AS project_component_id, + string_agg(DISTINCT features_council_districts.council_district_id::text, ', '::text) AS council_districts, + string_agg(DISTINCT lpad(features_council_districts.council_district_id::text, 2, '0'::text), ', '::text) AS council_districts_searchable + FROM features_council_districts + LEFT JOIN features ON features_council_districts.feature_id = features.id + WHERE features.is_deleted = false + GROUP BY features.component_id +), + +comp_geography AS ( + SELECT + feature_union.component_id AS project_component_id, + string_agg(DISTINCT feature_union.id::text, ', '::text) AS feature_ids, + st_asgeojson(st_multi(st_union(array_agg(feature_union.geography))))::json AS geometry, + st_asgeojson(st_multi(st_union(array_agg(feature_union.line_geography))))::json AS line_geometry, + string_agg(DISTINCT feature_union.signal_id::text, ', '::text) AS signal_ids, + sum(feature_union.length_feet) AS length_feet_total + FROM ( + SELECT + feature_signals.id, + feature_signals.component_id, + feature_signals.geography::geometry AS geography, + st_exteriorring(st_buffer(feature_signals.geography, 7::double precision)::geometry) AS line_geography, + feature_signals.signal_id, + null::integer AS length_feet + FROM feature_signals + WHERE feature_signals.is_deleted = false + UNION ALL + SELECT + feature_street_segments.id, + feature_street_segments.component_id, + feature_street_segments.geography::geometry AS geography, + feature_street_segments.geography::geometry AS line_geography, + null::integer AS signal_id, + feature_street_segments.length_feet + FROM feature_street_segments + WHERE feature_street_segments.is_deleted = false + UNION ALL + SELECT + feature_intersections.id, + feature_intersections.component_id, + feature_intersections.geography::geometry AS geography, + st_exteriorring(st_buffer(feature_intersections.geography, 7::double precision)::geometry) AS line_geography, + null::integer AS signal_id, + null::integer AS length_feet + FROM feature_intersections + WHERE feature_intersections.is_deleted = false + UNION ALL + SELECT + feature_drawn_points.id, + feature_drawn_points.component_id, + feature_drawn_points.geography::geometry AS geography, + st_exteriorring(st_buffer(feature_drawn_points.geography, 7::double precision)::geometry) AS line_geography, + null::integer AS signal_id, + null::integer AS length_feet + FROM feature_drawn_points + WHERE feature_drawn_points.is_deleted = false + UNION ALL + SELECT + feature_drawn_lines.id, + feature_drawn_lines.component_id, + feature_drawn_lines.geography::geometry AS geography, + feature_drawn_lines.geography::geometry AS line_geography, + null::integer AS signal_id, + feature_drawn_lines.length_feet + FROM feature_drawn_lines + WHERE feature_drawn_lines.is_deleted = false + UNION ALL + SELECT + feature_school_beacons.id, + feature_school_beacons.component_id, + feature_school_beacons.geography::geometry AS geography, + st_exteriorring(st_buffer(feature_school_beacons.geography, 7::double precision)::geometry) AS line_geography, + null::integer AS signal_id, + null::integer AS length_feet + FROM feature_school_beacons + WHERE feature_school_beacons.is_deleted = false + ) feature_union + GROUP BY feature_union.component_id +), + +subcomponents AS ( + SELECT + mpcs.project_component_id, + string_agg(ms.subcomponent_name, ', '::text) AS subcomponents + FROM moped_proj_components_subcomponents mpcs + LEFT JOIN moped_subcomponents ms ON mpcs.subcomponent_id = ms.subcomponent_id + WHERE mpcs.is_deleted = false + GROUP BY mpcs.project_component_id +), + +component_tags AS ( + SELECT + mpct.project_component_id, + string_agg((mct.type || ' - '::text) || mct.name, ', '::text) AS component_tags + FROM moped_proj_component_tags mpct + LEFT JOIN moped_component_tags mct ON mpct.component_tag_id = mct.id + WHERE mpct.is_deleted = false + GROUP BY mpct.project_component_id +), + +related_projects AS ( + SELECT + pmp.project_id, + concat_ws(', '::text, pmp.project_id, string_agg(cmp.project_id::text, ', '::text)) AS related_project_ids_with_self, + concat_ws(', '::text, lpad(pmp.project_id::text, 5, '0'::text), string_agg(lpad(cmp.project_id::text, 5, '0'::text), ', '::text)) AS related_project_ids_searchable_with_self + FROM moped_project pmp + LEFT JOIN moped_project cmp ON pmp.project_id = cmp.parent_project_id + WHERE cmp.is_deleted = false + GROUP BY pmp.project_id +), + +latest_public_meeting_date AS ( + SELECT + mpm.project_id, + coalesce(max(mpm.date_actual), max(mpm.date_estimate)) AS latest + FROM moped_proj_milestones mpm + WHERE mpm.milestone_id = 65 AND mpm.is_deleted = false + GROUP BY mpm.project_id +), + +earliest_active_or_construction_phase_date AS ( + SELECT + mpp.project_id, + min(mpp.phase_start) AS earliest + FROM moped_proj_phases mpp + LEFT JOIN moped_phases mp ON mpp.phase_id = mp.phase_id + WHERE (mp.phase_name_simple = any(ARRAY['Active'::text, 'Construction'::text])) AND mpp.is_deleted = false + GROUP BY mpp.project_id +) + +SELECT + mpc.project_id, + comp_geography.project_component_id, + comp_geography.feature_ids, + mpc.component_id, + comp_geography.geometry, + comp_geography.line_geometry, + comp_geography.signal_ids, + council_districts.council_districts, + council_districts.council_districts_searchable, + NOT coalesce(council_districts.council_districts IS null OR council_districts.council_districts = ''::text, false) AS is_within_city_limits, + comp_geography.length_feet_total, + round(comp_geography.length_feet_total::numeric / 5280::numeric, 2) AS length_miles_total, + mc.component_name, + mc.component_subtype, + mc.component_name_full, + 'placeholder text'::text AS component_categories, + CASE + WHEN mc.line_representation = true THEN 'Line'::text + ELSE 'Point'::text + END AS geometry_type, + subcomponents.subcomponents AS component_subcomponents, + work_types.work_types AS component_work_types, + component_tags.component_tags, + mpc.description AS component_description, + mpc.interim_project_component_id, + coalesce(mpc.completion_date, plv.substantial_completion_date) AS substantial_completion_date, + plv.substantial_completion_date_estimated, + mpc.srts_id, + mpc.location_description AS component_location_description, + plv.project_name, + plv.project_name_secondary, + plv.project_name_full, + plv.project_description, + plv.ecapris_subproject_id, + plv.project_website, + plv.updated_at AS project_updated_at, + mpc.phase_id AS component_phase_id, + mph.phase_name AS component_phase_name, + mph.phase_name_simple AS component_phase_name_simple, + current_phase.phase_id AS project_phase_id, + current_phase.phase_name AS project_phase_name, + current_phase.phase_name_simple AS project_phase_name_simple, + coalesce(mph.phase_name, current_phase.phase_name) AS current_phase_name, + coalesce(mph.phase_name_simple, current_phase.phase_name_simple) AS current_phase_name_simple, + plv.project_team_members, + plv.project_sponsor, + plv.project_lead, + plv.public_process_status, + plv.interim_project_id, + plv.project_partners, + plv.task_order_names, + plv.funding_source_and_program_names AS funding_sources, + plv.type_name, + plv.project_status_update, + plv.project_status_update_date_created, + to_char(timezone('US/Central'::text, plv.construction_start_date), 'YYYY-MM-DD'::text) AS construction_start_date, + plv.project_inspector, + plv.project_designer, + plv.project_tags, + plv.workgroup_contractors, + plv.contract_numbers, + plv.parent_project_id, + plv.parent_project_name, + plv.parent_project_url, + plv.parent_project_name AS parent_project_name_full, + rp.related_project_ids_with_self AS related_project_ids, + rp.related_project_ids_searchable_with_self AS related_project_ids_searchable, + plv.knack_project_id AS knack_data_tracker_project_record_id, + plv.project_url, + (plv.project_url || '?tab=map&project_component_id='::text) || mpc.project_component_id::text AS component_url, + get_project_development_status(lpmd.latest::timestamp with time zone, eaocpd.earliest, coalesce(mpc.completion_date, plv.substantial_completion_date), plv.substantial_completion_date_estimated, coalesce(mph.phase_name_simple, current_phase.phase_name_simple)) AS project_development_status, + project_development_status_date.result AS project_development_status_date, + to_char(project_development_status_date.result, 'YYYY'::text)::integer AS project_development_status_date_calendar_year, + to_char(project_development_status_date.result, 'FMMonth YYYY'::text) AS project_development_status_date_calendar_year_month, + to_char(project_development_status_date.result, 'YYYY-MM'::text) AS project_development_status_date_calendar_year_month_numeric, + date_part('quarter'::text, project_development_status_date.result)::text AS project_development_status_date_calendar_year_quarter, + CASE + WHEN date_part('quarter'::text, project_development_status_date.result) = 4::double precision THEN (to_char(project_development_status_date.result, 'YYYY'::text)::integer + 1)::text + ELSE to_char(project_development_status_date.result, 'YYYY'::text) + END AS project_development_status_date_fiscal_year, + CASE + WHEN date_part('quarter'::text, project_development_status_date.result) = 4::double precision THEN 1::double precision + ELSE date_part('quarter'::text, project_development_status_date.result) + 1::double precision + END::text AS project_development_status_date_fiscal_year_quarter, + plv.added_by AS project_added_by +FROM moped_proj_components mpc +LEFT JOIN comp_geography ON mpc.project_component_id = comp_geography.project_component_id +LEFT JOIN council_districts ON mpc.project_component_id = council_districts.project_component_id +LEFT JOIN subcomponents ON mpc.project_component_id = subcomponents.project_component_id +LEFT JOIN work_types ON mpc.project_component_id = work_types.project_component_id +LEFT JOIN component_tags ON mpc.project_component_id = component_tags.project_component_id +LEFT JOIN project_list_view plv ON mpc.project_id = plv.project_id +LEFT JOIN current_phase_view current_phase ON mpc.project_id = current_phase.project_id +LEFT JOIN moped_phases mph ON mpc.phase_id = mph.phase_id +LEFT JOIN moped_components mc ON mpc.component_id = mc.component_id +LEFT JOIN related_projects rp ON mpc.project_id = rp.project_id +LEFT JOIN latest_public_meeting_date lpmd ON mpc.project_id = lpmd.project_id +LEFT JOIN earliest_active_or_construction_phase_date eaocpd ON mpc.project_id = eaocpd.project_id +LEFT JOIN LATERAL (SELECT timezone('US/Central'::text, get_project_development_status_date(lpmd.latest::timestamp with time zone, eaocpd.earliest, coalesce(mpc.completion_date, plv.substantial_completion_date), plv.substantial_completion_date_estimated, coalesce(mph.phase_name_simple, current_phase.phase_name_simple))) AS result) project_development_status_date ON true +WHERE mpc.is_deleted = false AND plv.is_deleted = false; + +CREATE OR REPLACE VIEW exploded_component_arcgis_online_view AS SELECT + component_arcgis_online_view.project_id, + component_arcgis_online_view.project_component_id, + st_geometrytype(dump.geom) AS geometry_type, + dump.path[1] AS point_index, + component_arcgis_online_view.geometry AS original_geometry, + st_asgeojson(dump.geom) AS exploded_geometry, + component_arcgis_online_view.project_updated_at +FROM component_arcgis_online_view, + LATERAL st_dump(st_geomfromgeojson(component_arcgis_online_view.geometry)) dump (path, geom) +WHERE st_geometrytype(st_geomfromgeojson(component_arcgis_online_view.geometry)) = 'ST_MultiPoint'::text; diff --git a/moped-database/migrations/1737754622032_deprecate_type_tables/up.sql b/moped-database/migrations/1737754622032_deprecate_type_tables/up.sql new file mode 100644 index 0000000000..7443617b3e --- /dev/null +++ b/moped-database/migrations/1737754622032_deprecate_type_tables/up.sql @@ -0,0 +1,566 @@ +CREATE SCHEMA deprecated; + +ALTER TABLE moped_types +SET SCHEMA deprecated; + +COMMENT ON TABLE deprecated.moped_types IS 'This table is no longer in use as of January 2025.'; + +ALTER TABLE moped_project_types +SET SCHEMA deprecated; + +COMMENT ON TABLE deprecated.moped_project_types IS 'This table is no longer in use as of January 2025.'; + +-- Remove moped_types and moped_project_types from database views +DROP VIEW IF EXISTS exploded_component_arcgis_online_view; +DROP VIEW IF EXISTS component_arcgis_online_view; +DROP VIEW IF EXISTS project_list_view; + +CREATE OR REPLACE VIEW project_list_view AS WITH project_person_list_lookup AS ( + SELECT + mpp.project_id, + string_agg(DISTINCT concat(mu.first_name, ' ', mu.last_name, ':', mpr.project_role_name), ','::text) AS project_team_members + FROM moped_proj_personnel mpp + JOIN moped_users mu ON mpp.user_id = mu.user_id + JOIN moped_proj_personnel_roles mppr ON mpp.project_personnel_id = mppr.project_personnel_id + JOIN moped_project_roles mpr ON mppr.project_role_id = mpr.project_role_id + WHERE mpp.is_deleted = false AND mppr.is_deleted = false + GROUP BY mpp.project_id +), + +funding_sources_lookup AS ( + SELECT + mpf.project_id, + string_agg( + DISTINCT mfs.funding_source_name, ', '::text + ORDER BY mfs.funding_source_name + ) AS funding_source_name, + string_agg( + DISTINCT mfp.funding_program_name, ', '::text + ORDER BY mfp.funding_program_name + ) AS funding_program_names, + string_agg( + DISTINCT + CASE + WHEN mfs.funding_source_name IS NOT null AND mfp.funding_program_name IS NOT null THEN concat(mfs.funding_source_name, ' - ', mfp.funding_program_name) + WHEN mfs.funding_source_name IS NOT null THEN mfs.funding_source_name + WHEN mfp.funding_program_name IS NOT null THEN mfp.funding_program_name + ELSE null::text + END, ', '::text + ORDER BY ( + CASE + WHEN mfs.funding_source_name IS NOT null AND mfp.funding_program_name IS NOT null THEN concat(mfs.funding_source_name, ' - ', mfp.funding_program_name) + WHEN mfs.funding_source_name IS NOT null THEN mfs.funding_source_name + WHEN mfp.funding_program_name IS NOT null THEN mfp.funding_program_name + ELSE null::text + END + ) + ) AS funding_source_and_program_names + FROM moped_proj_funding mpf + LEFT JOIN moped_fund_sources mfs ON mpf.funding_source_id = mfs.funding_source_id + LEFT JOIN moped_fund_programs mfp ON mpf.funding_program_id = mfp.funding_program_id + WHERE mpf.is_deleted = false + GROUP BY mpf.project_id +), + +child_project_lookup AS ( + SELECT + jsonb_agg(children.project_id) AS children_project_ids, + children.parent_project_id AS parent_id + FROM moped_project children + JOIN moped_project parent ON children.parent_project_id = parent.project_id + WHERE children.is_deleted = false + GROUP BY children.parent_project_id +), + +work_activities AS ( + SELECT + mpwa.project_id, + string_agg(task_order_objects.task_order_object ->> 'display_name'::text, ', '::text) AS task_order_names, + string_agg(task_order_objects.task_order_object ->> 'task_order'::text, ', '::text) AS task_order_names_short, + jsonb_agg(DISTINCT task_order_objects.task_order_object) FILTER (WHERE task_order_objects.task_order_object IS NOT null) AS task_orders, + string_agg(DISTINCT mpwa.workgroup_contractor, ', '::text) AS workgroup_contractors, + string_agg(mpwa.contract_number, ', '::text) AS contract_numbers + FROM moped_proj_work_activity mpwa + LEFT JOIN LATERAL jsonb_array_elements(mpwa.task_orders) task_order_objects (task_order_object) ON true + WHERE 1 = 1 AND mpwa.is_deleted = false + GROUP BY mpwa.project_id +), + +moped_proj_components_subtypes AS ( + SELECT + mpc.project_id, + string_agg(DISTINCT mc.component_name_full, ', '::text) AS components + FROM moped_proj_components mpc + LEFT JOIN moped_components mc ON mpc.component_id = mc.component_id + WHERE mpc.is_deleted = false + GROUP BY mpc.project_id +), + +project_district_association AS ( + WITH project_council_district_map AS ( + SELECT DISTINCT + moped_project.project_id, + features_council_districts.council_district_id + FROM moped_project + LEFT JOIN moped_proj_components ON moped_project.project_id = moped_proj_components.project_id + LEFT JOIN features ON moped_proj_components.project_component_id = features.component_id + LEFT JOIN features_council_districts ON features.id = features_council_districts.feature_id + WHERE features.is_deleted IS false AND moped_proj_components.is_deleted IS false + ), + +parent_child_project_map AS ( + SELECT + parent_projects.project_id, + unnest(ARRAY[parent_projects.project_id] || array_agg(child_projects.project_id)) AS self_and_children_project_ids + FROM moped_project parent_projects + LEFT JOIN moped_project child_projects ON parent_projects.project_id = child_projects.parent_project_id + GROUP BY parent_projects.project_id + ORDER BY parent_projects.project_id + ) + + SELECT + projects.project_id, + array_agg(DISTINCT project_districts.council_district_id) FILTER (WHERE project_districts.council_district_id IS NOT null) AS project_council_districts, + array_agg(DISTINCT project_and_children_districts.council_district_id) FILTER (WHERE project_and_children_districts.council_district_id IS NOT null) AS project_and_child_project_council_districts + FROM parent_child_project_map projects + LEFT JOIN project_council_district_map project_and_children_districts ON projects.self_and_children_project_ids = project_and_children_districts.project_id + LEFT JOIN project_council_district_map project_districts ON projects.project_id = project_districts.project_id + GROUP BY projects.project_id +), + +min_confirmed_phase_dates AS ( + WITH min_dates AS ( + SELECT + phases.project_id, + min(phases.phase_start) AS min_date + FROM moped_proj_phases phases + LEFT JOIN moped_phases ON phases.phase_id = moped_phases.phase_id + WHERE true AND phases.phase_start IS NOT null AND phases.is_phase_start_confirmed = true AND moped_phases.phase_name_simple = 'Complete'::text AND phases.is_deleted = false + GROUP BY phases.project_id + UNION ALL + SELECT + phases.project_id, + min(phases.phase_end) AS min_date + FROM moped_proj_phases phases + LEFT JOIN moped_phases ON phases.phase_id = moped_phases.phase_id + WHERE true AND phases.phase_end IS NOT null AND phases.is_phase_end_confirmed = true AND moped_phases.phase_name_simple = 'Complete'::text AND phases.is_deleted = false + GROUP BY phases.project_id + ) + + SELECT + min_dates.project_id, + min(min_dates.min_date) AS min_phase_date + FROM min_dates + GROUP BY min_dates.project_id +), + +min_estimated_phase_dates AS ( + WITH min_dates AS ( + SELECT + phases.project_id, + min(phases.phase_start) AS min_date + FROM moped_proj_phases phases + LEFT JOIN moped_phases ON phases.phase_id = moped_phases.phase_id + WHERE true AND phases.phase_start IS NOT null AND phases.is_phase_start_confirmed = false AND moped_phases.phase_name_simple = 'Complete'::text AND phases.is_deleted = false + GROUP BY phases.project_id + UNION ALL + SELECT + phases.project_id, + min(phases.phase_end) AS min_date + FROM moped_proj_phases phases + LEFT JOIN moped_phases ON phases.phase_id = moped_phases.phase_id + WHERE true AND phases.phase_end IS NOT null AND phases.is_phase_end_confirmed = false AND moped_phases.phase_name_simple = 'Complete'::text AND phases.is_deleted = false + GROUP BY phases.project_id + ) + + SELECT + min_dates.project_id, + min(min_dates.min_date) AS min_phase_date + FROM min_dates + GROUP BY min_dates.project_id +), + +project_component_work_types AS ( + SELECT + mpc.project_id, + string_agg( + DISTINCT mwt.name, ', '::text + ORDER BY mwt.name + ) AS component_work_type_names + FROM moped_proj_components mpc + LEFT JOIN moped_proj_component_work_types mpcwt ON mpcwt.project_component_id = mpc.project_component_id + LEFT JOIN moped_work_types mwt ON mwt.id = mpcwt.work_type_id + WHERE true AND mpc.is_deleted = false AND mpcwt.is_deleted = false + GROUP BY mpc.project_id +) + +SELECT + mp.project_id, + mp.project_name_full, + mp.project_name, + mp.project_name_secondary, + mp.project_description, + mp.ecapris_subproject_id, + mp.project_website, + mp.date_added, + mp.is_deleted, + mp.updated_at, + current_phase.phase_name AS current_phase, + current_phase.phase_key AS current_phase_key, + current_phase.phase_name_simple AS current_phase_simple, + ppll.project_team_members, + me.entity_name AS project_sponsor, + mel.entity_name AS project_lead, + mpps.name AS public_process_status, + mp.interim_project_id, + mp.parent_project_id, + mp.knack_project_id, + 'https://mobility.austin.gov/moped/projects/'::text || mp.project_id::text AS project_url, + 'https://mobility.austin.gov/moped/projects/'::text || mp.parent_project_id::text AS parent_project_url, + proj_status_update.project_note AS project_status_update, + proj_status_update.date_created AS project_status_update_date_created, + work_activities.workgroup_contractors, + work_activities.contract_numbers, + work_activities.task_order_names, + work_activities.task_order_names_short, + work_activities.task_orders, + ( + SELECT moped_project.project_name_full + FROM moped_project + WHERE moped_project.project_id = mp.parent_project_id + ) AS parent_project_name, + cpl.children_project_ids, + string_agg(DISTINCT me2.entity_name, ', '::text) AS project_partners, + ( + SELECT json_agg(json_build_object('signal_id', feature_signals.signal_id, 'knack_id', feature_signals.knack_id, 'location_name', feature_signals.location_name, 'signal_type', feature_signals.signal_type, 'id', feature_signals.id)) AS json_agg + FROM moped_proj_components components + LEFT JOIN feature_signals ON components.project_component_id = feature_signals.component_id + WHERE true AND components.is_deleted = false AND components.project_id = mp.project_id AND feature_signals.signal_id IS NOT null AND feature_signals.is_deleted = false + ) AS project_feature, + fsl.funding_source_name, + fsl.funding_program_names, + fsl.funding_source_and_program_names, + ( + SELECT min(phases.phase_start) AS min + FROM moped_proj_phases phases + WHERE true AND phases.project_id = mp.project_id AND phases.phase_id = 9 AND phases.is_deleted = false + ) AS construction_start_date, + mcpd.min_phase_date AS substantial_completion_date, + CASE + WHEN mcpd.min_phase_date IS NOT null THEN null::timestamp with time zone + ELSE mepd.min_phase_date + END AS substantial_completion_date_estimated, + ( + SELECT string_agg(concat(users.first_name, ' ', users.last_name), ', '::text) AS string_agg + FROM moped_proj_personnel mpp + JOIN moped_users users ON mpp.user_id = users.user_id + JOIN moped_proj_personnel_roles mppr ON mpp.project_personnel_id = mppr.project_personnel_id + JOIN moped_project_roles mpr ON mppr.project_role_id = mpr.project_role_id + WHERE 1 = 1 AND mpr.project_role_name = 'Inspector'::text AND mpp.is_deleted = false AND mppr.is_deleted = false AND mpp.project_id = mp.project_id + GROUP BY mpp.project_id + ) AS project_inspector, + ( + SELECT string_agg(concat(users.first_name, ' ', users.last_name), ', '::text) AS string_agg + FROM moped_proj_personnel mpp + JOIN moped_users users ON mpp.user_id = users.user_id + JOIN moped_proj_personnel_roles mppr ON mpp.project_personnel_id = mppr.project_personnel_id + JOIN moped_project_roles mpr ON mppr.project_role_id = mpr.project_role_id + WHERE 1 = 1 AND mpr.project_role_name = 'Designer'::text AND mpp.is_deleted = false AND mppr.is_deleted = false AND mpp.project_id = mp.project_id + GROUP BY mpp.project_id + ) AS project_designer, + ( + SELECT string_agg(tags.name, ', '::text) AS string_agg + FROM moped_proj_tags ptags + JOIN moped_tags tags ON ptags.tag_id = tags.id + WHERE 1 = 1 AND ptags.is_deleted = false AND ptags.project_id = mp.project_id + GROUP BY ptags.project_id + ) AS project_tags, + concat(added_by_user.first_name, ' ', added_by_user.last_name) AS added_by, + mpcs.components, + districts.project_council_districts, + districts.project_and_child_project_council_districts, + pcwt.component_work_type_names +FROM moped_project mp +LEFT JOIN project_person_list_lookup ppll ON mp.project_id = ppll.project_id +LEFT JOIN funding_sources_lookup fsl ON mp.project_id = fsl.project_id +LEFT JOIN moped_entity me ON mp.project_sponsor = me.entity_id +LEFT JOIN moped_entity mel ON mp.project_lead_id = mel.entity_id +LEFT JOIN moped_proj_partners mpp2 ON mp.project_id = mpp2.project_id AND mpp2.is_deleted = false +LEFT JOIN moped_entity me2 ON mpp2.entity_id = me2.entity_id +LEFT JOIN work_activities ON mp.project_id = work_activities.project_id +LEFT JOIN moped_users added_by_user ON mp.added_by = added_by_user.user_id +LEFT JOIN current_phase_view current_phase ON mp.project_id = current_phase.project_id +LEFT JOIN moped_public_process_statuses mpps ON mp.public_process_status_id = mpps.id +LEFT JOIN child_project_lookup cpl ON mp.project_id = cpl.parent_id +LEFT JOIN moped_proj_components_subtypes mpcs ON mp.project_id = mpcs.project_id +LEFT JOIN project_district_association districts ON mp.project_id = districts.project_id +LEFT JOIN min_confirmed_phase_dates mcpd ON mp.project_id = mcpd.project_id +LEFT JOIN min_estimated_phase_dates mepd ON mp.project_id = mepd.project_id +LEFT JOIN project_component_work_types pcwt ON mp.project_id = pcwt.project_id +LEFT JOIN LATERAL ( + SELECT + mpn.project_note, + mpn.created_at AS date_created + FROM moped_proj_notes mpn + WHERE mpn.project_id = mp.project_id AND mpn.project_note_type = 2 AND mpn.is_deleted = false + ORDER BY mpn.created_at DESC + LIMIT 1 +) proj_status_update ON true +WHERE mp.is_deleted = false +GROUP BY mp.project_id, mp.project_name, mp.project_description, ppll.project_team_members, mp.ecapris_subproject_id, mp.date_added, mp.is_deleted, me.entity_name, mel.entity_name, mp.updated_at, mp.interim_project_id, mp.parent_project_id, mp.knack_project_id, current_phase.phase_name, current_phase.phase_key, current_phase.phase_name_simple, mpcs.components, fsl.funding_source_name, fsl.funding_program_names, fsl.funding_source_and_program_names, added_by_user.first_name, added_by_user.last_name, mpps.name, cpl.children_project_ids, proj_status_update.project_note, proj_status_update.date_created, work_activities.workgroup_contractors, work_activities.contract_numbers, work_activities.task_order_names, work_activities.task_order_names_short, work_activities.task_orders, districts.project_council_districts, districts.project_and_child_project_council_districts, mepd.min_phase_date, mcpd.min_phase_date, pcwt.component_work_type_names; + +CREATE OR REPLACE VIEW component_arcgis_online_view AS WITH work_types AS ( + SELECT + mpcwt.project_component_id, + string_agg(mwt.name, ', '::text) AS work_types + FROM moped_proj_component_work_types mpcwt + LEFT JOIN moped_work_types mwt ON mpcwt.work_type_id = mwt.id + WHERE mpcwt.is_deleted = false + GROUP BY mpcwt.project_component_id +), + +council_districts AS ( + SELECT + features.component_id AS project_component_id, + string_agg(DISTINCT features_council_districts.council_district_id::text, ', '::text) AS council_districts, + string_agg(DISTINCT lpad(features_council_districts.council_district_id::text, 2, '0'::text), ', '::text) AS council_districts_searchable + FROM features_council_districts + LEFT JOIN features ON features_council_districts.feature_id = features.id + WHERE features.is_deleted = false + GROUP BY features.component_id +), + +comp_geography AS ( + SELECT + feature_union.component_id AS project_component_id, + string_agg(DISTINCT feature_union.id::text, ', '::text) AS feature_ids, + st_asgeojson(st_multi(st_union(array_agg(feature_union.geography))))::json AS geometry, + st_asgeojson(st_multi(st_union(array_agg(feature_union.line_geography))))::json AS line_geometry, + string_agg(DISTINCT feature_union.signal_id::text, ', '::text) AS signal_ids, + sum(feature_union.length_feet) AS length_feet_total + FROM ( + SELECT + feature_signals.id, + feature_signals.component_id, + feature_signals.geography::geometry AS geography, + st_exteriorring(st_buffer(feature_signals.geography, 7::double precision)::geometry) AS line_geography, + feature_signals.signal_id, + null::integer AS length_feet + FROM feature_signals + WHERE feature_signals.is_deleted = false + UNION ALL + SELECT + feature_street_segments.id, + feature_street_segments.component_id, + feature_street_segments.geography::geometry AS geography, + feature_street_segments.geography::geometry AS line_geography, + null::integer AS signal_id, + feature_street_segments.length_feet + FROM feature_street_segments + WHERE feature_street_segments.is_deleted = false + UNION ALL + SELECT + feature_intersections.id, + feature_intersections.component_id, + feature_intersections.geography::geometry AS geography, + st_exteriorring(st_buffer(feature_intersections.geography, 7::double precision)::geometry) AS line_geography, + null::integer AS signal_id, + null::integer AS length_feet + FROM feature_intersections + WHERE feature_intersections.is_deleted = false + UNION ALL + SELECT + feature_drawn_points.id, + feature_drawn_points.component_id, + feature_drawn_points.geography::geometry AS geography, + st_exteriorring(st_buffer(feature_drawn_points.geography, 7::double precision)::geometry) AS line_geography, + null::integer AS signal_id, + null::integer AS length_feet + FROM feature_drawn_points + WHERE feature_drawn_points.is_deleted = false + UNION ALL + SELECT + feature_drawn_lines.id, + feature_drawn_lines.component_id, + feature_drawn_lines.geography::geometry AS geography, + feature_drawn_lines.geography::geometry AS line_geography, + null::integer AS signal_id, + feature_drawn_lines.length_feet + FROM feature_drawn_lines + WHERE feature_drawn_lines.is_deleted = false + UNION ALL + SELECT + feature_school_beacons.id, + feature_school_beacons.component_id, + feature_school_beacons.geography::geometry AS geography, + st_exteriorring(st_buffer(feature_school_beacons.geography, 7::double precision)::geometry) AS line_geography, + null::integer AS signal_id, + null::integer AS length_feet + FROM feature_school_beacons + WHERE feature_school_beacons.is_deleted = false + ) feature_union + GROUP BY feature_union.component_id +), + +subcomponents AS ( + SELECT + mpcs.project_component_id, + string_agg(ms.subcomponent_name, ', '::text) AS subcomponents + FROM moped_proj_components_subcomponents mpcs + LEFT JOIN moped_subcomponents ms ON mpcs.subcomponent_id = ms.subcomponent_id + WHERE mpcs.is_deleted = false + GROUP BY mpcs.project_component_id +), + +component_tags AS ( + SELECT + mpct.project_component_id, + string_agg((mct.type || ' - '::text) || mct.name, ', '::text) AS component_tags + FROM moped_proj_component_tags mpct + LEFT JOIN moped_component_tags mct ON mpct.component_tag_id = mct.id + WHERE mpct.is_deleted = false + GROUP BY mpct.project_component_id +), + +related_projects AS ( + SELECT + pmp.project_id, + concat_ws(', '::text, pmp.project_id, string_agg(cmp.project_id::text, ', '::text)) AS related_project_ids_with_self, + concat_ws(', '::text, lpad(pmp.project_id::text, 5, '0'::text), string_agg(lpad(cmp.project_id::text, 5, '0'::text), ', '::text)) AS related_project_ids_searchable_with_self + FROM moped_project pmp + LEFT JOIN moped_project cmp ON pmp.project_id = cmp.parent_project_id + WHERE cmp.is_deleted = false + GROUP BY pmp.project_id +), + +latest_public_meeting_date AS ( + SELECT + mpm.project_id, + coalesce(max(mpm.date_actual), max(mpm.date_estimate)) AS latest + FROM moped_proj_milestones mpm + WHERE mpm.milestone_id = 65 AND mpm.is_deleted = false + GROUP BY mpm.project_id +), + +earliest_active_or_construction_phase_date AS ( + SELECT + mpp.project_id, + min(mpp.phase_start) AS earliest + FROM moped_proj_phases mpp + LEFT JOIN moped_phases mp ON mpp.phase_id = mp.phase_id + WHERE (mp.phase_name_simple = any(ARRAY['Active'::text, 'Construction'::text])) AND mpp.is_deleted = false + GROUP BY mpp.project_id +) + +SELECT + mpc.project_id, + mpc.project_component_id, + comp_geography.feature_ids, + mpc.component_id, + comp_geography.geometry, + comp_geography.line_geometry, + comp_geography.signal_ids, + council_districts.council_districts, + council_districts.council_districts_searchable, + NOT coalesce(council_districts.council_districts IS null OR council_districts.council_districts = ''::text, false) AS is_within_city_limits, + comp_geography.length_feet_total, + round(comp_geography.length_feet_total::numeric / 5280::numeric, 2) AS length_miles_total, + mc.component_name, + mc.component_subtype, + mc.component_name_full, + 'placeholder text'::text AS component_categories, + CASE + WHEN mc.line_representation = true THEN 'Line'::text + ELSE 'Point'::text + END AS geometry_type, + subcomponents.subcomponents AS component_subcomponents, + work_types.work_types AS component_work_types, + component_tags.component_tags, + mpc.description AS component_description, + mpc.interim_project_component_id, + coalesce(mpc.completion_date, plv.substantial_completion_date) AS substantial_completion_date, + plv.substantial_completion_date_estimated, + mpc.srts_id, + mpc.location_description AS component_location_description, + plv.project_name, + plv.project_name_secondary, + plv.project_name_full, + plv.project_description, + plv.ecapris_subproject_id, + plv.project_website, + plv.updated_at AS project_updated_at, + mpc.phase_id AS component_phase_id, + mph.phase_name AS component_phase_name, + mph.phase_name_simple AS component_phase_name_simple, + current_phase.phase_id AS project_phase_id, + current_phase.phase_name AS project_phase_name, + current_phase.phase_name_simple AS project_phase_name_simple, + coalesce(mph.phase_name, current_phase.phase_name) AS current_phase_name, + coalesce(mph.phase_name_simple, current_phase.phase_name_simple) AS current_phase_name_simple, + plv.project_team_members, + plv.project_sponsor, + plv.project_lead, + plv.public_process_status, + plv.interim_project_id, + plv.project_partners, + plv.task_order_names, + plv.funding_source_and_program_names AS funding_sources, + plv.project_status_update, + plv.project_status_update_date_created, + to_char(timezone('US/Central'::text, plv.construction_start_date), 'YYYY-MM-DD'::text) AS construction_start_date, + plv.project_inspector, + plv.project_designer, + plv.project_tags, + plv.workgroup_contractors, + plv.contract_numbers, + plv.parent_project_id, + plv.parent_project_name, + plv.parent_project_url, + plv.parent_project_name AS parent_project_name_full, + rp.related_project_ids_with_self AS related_project_ids, + rp.related_project_ids_searchable_with_self AS related_project_ids_searchable, + plv.knack_project_id AS knack_data_tracker_project_record_id, + plv.project_url, + (plv.project_url || '?tab=map&project_component_id='::text) || mpc.project_component_id::text AS component_url, + get_project_development_status(lpmd.latest::timestamp with time zone, eaocpd.earliest, coalesce(mpc.completion_date, plv.substantial_completion_date), plv.substantial_completion_date_estimated, coalesce(mph.phase_name_simple, current_phase.phase_name_simple)) AS project_development_status, + project_development_status_date.result AS project_development_status_date, + to_char(project_development_status_date.result, 'YYYY'::text)::integer AS project_development_status_date_calendar_year, + to_char(project_development_status_date.result, 'FMMonth YYYY'::text) AS project_development_status_date_calendar_year_month, + to_char(project_development_status_date.result, 'YYYY-MM'::text) AS project_development_status_date_calendar_year_month_numeric, + date_part('quarter'::text, project_development_status_date.result)::text AS project_development_status_date_calendar_year_quarter, + CASE + WHEN date_part('quarter'::text, project_development_status_date.result) = 4::double precision THEN (to_char(project_development_status_date.result, 'YYYY'::text)::integer + 1)::text + ELSE to_char(project_development_status_date.result, 'YYYY'::text) + END AS project_development_status_date_fiscal_year, + CASE + WHEN date_part('quarter'::text, project_development_status_date.result) = 4::double precision THEN 1::double precision + ELSE date_part('quarter'::text, project_development_status_date.result) + 1::double precision + END::text AS project_development_status_date_fiscal_year_quarter, + plv.added_by AS project_added_by +FROM moped_proj_components mpc +LEFT JOIN comp_geography ON mpc.project_component_id = comp_geography.project_component_id +LEFT JOIN council_districts ON mpc.project_component_id = council_districts.project_component_id +LEFT JOIN subcomponents ON mpc.project_component_id = subcomponents.project_component_id +LEFT JOIN work_types ON mpc.project_component_id = work_types.project_component_id +LEFT JOIN component_tags ON mpc.project_component_id = component_tags.project_component_id +LEFT JOIN project_list_view plv ON mpc.project_id = plv.project_id +LEFT JOIN current_phase_view current_phase ON mpc.project_id = current_phase.project_id +LEFT JOIN moped_phases mph ON mpc.phase_id = mph.phase_id +LEFT JOIN moped_components mc ON mpc.component_id = mc.component_id +LEFT JOIN related_projects rp ON mpc.project_id = rp.project_id +LEFT JOIN latest_public_meeting_date lpmd ON mpc.project_id = lpmd.project_id +LEFT JOIN earliest_active_or_construction_phase_date eaocpd ON mpc.project_id = eaocpd.project_id +LEFT JOIN LATERAL (SELECT timezone('US/Central'::text, get_project_development_status_date(lpmd.latest::timestamp with time zone, eaocpd.earliest, coalesce(mpc.completion_date, plv.substantial_completion_date), plv.substantial_completion_date_estimated, coalesce(mph.phase_name_simple, current_phase.phase_name_simple))) AS result) project_development_status_date ON true +WHERE mpc.is_deleted = false AND plv.is_deleted = false; + +CREATE OR REPLACE VIEW exploded_component_arcgis_online_view AS SELECT + component_arcgis_online_view.project_id, + component_arcgis_online_view.project_component_id, + st_geometrytype(dump.geom) AS geometry_type, + dump.path[1] AS point_index, + component_arcgis_online_view.geometry AS original_geometry, + st_asgeojson(dump.geom) AS exploded_geometry, + component_arcgis_online_view.project_updated_at +FROM component_arcgis_online_view, + LATERAL st_dump(st_geomfromgeojson(component_arcgis_online_view.geometry)) dump (path, geom) +WHERE st_geometrytype(st_geomfromgeojson(component_arcgis_online_view.geometry)) = 'ST_MultiPoint'::text; diff --git a/moped-database/views/component_arcgis_online_view.sql b/moped-database/views/component_arcgis_online_view.sql index ea16e61eeb..4c7faff812 100644 --- a/moped-database/views/component_arcgis_online_view.sql +++ b/moped-database/views/component_arcgis_online_view.sql @@ -1,4 +1,4 @@ --- Most recent migration: moped-database/migrations/1733184698645_add_comp_work_types/up.sql +-- Most recent migration: moped-database/migrations/1737754622032_deprecate_type_tables/up.sql CREATE OR REPLACE VIEW component_arcgis_online_view AS WITH work_types AS ( SELECT @@ -145,7 +145,7 @@ earliest_active_or_construction_phase_date AS ( SELECT mpc.project_id, - comp_geography.project_component_id, + mpc.project_component_id, comp_geography.feature_ids, mpc.component_id, comp_geography.geometry, @@ -196,7 +196,6 @@ SELECT plv.project_partners, plv.task_order_names, plv.funding_source_and_program_names AS funding_sources, - plv.type_name, plv.project_status_update, plv.project_status_update_date_created, to_char(timezone('US/Central'::text, plv.construction_start_date), 'YYYY-MM-DD'::text) AS construction_start_date, diff --git a/moped-database/views/exploded_component_arcgis_online_view.sql b/moped-database/views/exploded_component_arcgis_online_view.sql index 32459065a2..08a2d0dfdc 100644 --- a/moped-database/views/exploded_component_arcgis_online_view.sql +++ b/moped-database/views/exploded_component_arcgis_online_view.sql @@ -1,4 +1,4 @@ --- Most recent migration: moped-database/migrations/1733184698645_add_comp_work_types/up.sql +-- Most recent migration: moped-database/migrations/1737754622032_deprecate_type_tables/up.sql CREATE OR REPLACE VIEW exploded_component_arcgis_online_view AS SELECT component_arcgis_online_view.project_id, diff --git a/moped-database/views/project_list_view.sql b/moped-database/views/project_list_view.sql index 31e4e28466..fb91f3404c 100644 --- a/moped-database/views/project_list_view.sql +++ b/moped-database/views/project_list_view.sql @@ -1,4 +1,4 @@ --- Most recent migration: moped-database/migrations/1733184698645_add_comp_work_types/up.sql +-- Most recent migration: moped-database/migrations/1737754622032_deprecate_type_tables/up.sql CREATE OR REPLACE VIEW project_list_view AS WITH project_person_list_lookup AS ( SELECT @@ -47,15 +47,6 @@ funding_sources_lookup AS ( GROUP BY mpf.project_id ), -project_type_lookup AS ( - SELECT - mpt.project_id, - string_agg(mt.type_name, ', '::text) AS type_name - FROM moped_project_types mpt - LEFT JOIN moped_types mt ON mpt.project_type_id = mt.type_id AND mpt.is_deleted = false - GROUP BY mpt.project_id -), - child_project_lookup AS ( SELECT jsonb_agg(children.project_id) AS children_project_ids, @@ -234,7 +225,6 @@ SELECT fsl.funding_source_name, fsl.funding_program_names, fsl.funding_source_and_program_names, - ptl.type_name, ( SELECT min(phases.phase_start) AS min FROM moped_proj_phases phases @@ -278,7 +268,6 @@ SELECT FROM moped_project mp LEFT JOIN project_person_list_lookup ppll ON mp.project_id = ppll.project_id LEFT JOIN funding_sources_lookup fsl ON mp.project_id = fsl.project_id -LEFT JOIN project_type_lookup ptl ON mp.project_id = ptl.project_id LEFT JOIN moped_entity me ON mp.project_sponsor = me.entity_id LEFT JOIN moped_entity mel ON mp.project_lead_id = mel.entity_id LEFT JOIN moped_proj_partners mpp2 ON mp.project_id = mpp2.project_id AND mpp2.is_deleted = false @@ -303,4 +292,4 @@ LEFT JOIN LATERAL ( LIMIT 1 ) proj_status_update ON true WHERE mp.is_deleted = false -GROUP BY mp.project_id, mp.project_name, mp.project_description, ppll.project_team_members, mp.ecapris_subproject_id, mp.date_added, mp.is_deleted, me.entity_name, mel.entity_name, mp.updated_at, mp.interim_project_id, mp.parent_project_id, mp.knack_project_id, current_phase.phase_name, current_phase.phase_key, current_phase.phase_name_simple, ptl.type_name, mpcs.components, fsl.funding_source_name, fsl.funding_program_names, fsl.funding_source_and_program_names, added_by_user.first_name, added_by_user.last_name, mpps.name, cpl.children_project_ids, proj_status_update.project_note, proj_status_update.date_created, work_activities.workgroup_contractors, work_activities.contract_numbers, work_activities.task_order_names, work_activities.task_order_names_short, work_activities.task_orders, districts.project_council_districts, districts.project_and_child_project_council_districts, mepd.min_phase_date, mcpd.min_phase_date, pcwt.component_work_type_names; +GROUP BY mp.project_id, mp.project_name, mp.project_description, ppll.project_team_members, mp.ecapris_subproject_id, mp.date_added, mp.is_deleted, me.entity_name, mel.entity_name, mp.updated_at, mp.interim_project_id, mp.parent_project_id, mp.knack_project_id, current_phase.phase_name, current_phase.phase_key, current_phase.phase_name_simple, mpcs.components, fsl.funding_source_name, fsl.funding_program_names, fsl.funding_source_and_program_names, added_by_user.first_name, added_by_user.last_name, mpps.name, cpl.children_project_ids, proj_status_update.project_note, proj_status_update.date_created, work_activities.workgroup_contractors, work_activities.contract_numbers, work_activities.task_order_names, work_activities.task_order_names_short, work_activities.task_orders, districts.project_council_districts, districts.project_and_child_project_council_districts, mepd.min_phase_date, mcpd.min_phase_date, pcwt.component_work_type_names; diff --git a/moped-editor/src/queries/project.js b/moped-editor/src/queries/project.js index e36327616d..12d41601a3 100644 --- a/moped-editor/src/queries/project.js +++ b/moped-editor/src/queries/project.js @@ -595,7 +595,7 @@ export const PROJECT_ACTIVITY_LOG = gql` component_name component_subtype } - moped_types(order_by: { type_id: asc }) { + deprecated_moped_types(order_by: { type_id: asc }) { type_id type_name } diff --git a/moped-editor/src/views/projects/projectView/ProjectActivityLog.js b/moped-editor/src/views/projects/projectView/ProjectActivityLog.js index b937ecaaa5..c4b9904b42 100644 --- a/moped-editor/src/views/projects/projectView/ProjectActivityLog.js +++ b/moped-editor/src/views/projects/projectView/ProjectActivityLog.js @@ -119,7 +119,7 @@ const useLookupTables = (data) => component.component_subtype ? ` - ${component.component_subtype}` : "" }`; }); - data["moped_types"].forEach((projectType) => { + data["deprecated_moped_types"].forEach((projectType) => { lookupData.projectTypeList[`${projectType.type_id}`] = projectType.type_name; }); @@ -129,10 +129,7 @@ const useLookupTables = (data) => }, [data]); /** Fields which do not need to be rendered in the activity log */ -const CHANGE_FIELDS_TO_IGNORE = [ - "updated_by_user_id", - "updated_at" -]; +const CHANGE_FIELDS_TO_IGNORE = ["updated_by_user_id", "updated_at"]; /** * Updates the description field with newData and oldData @@ -164,7 +161,10 @@ const usePrepareActivityData = (activityData) => if (!isEqual(newData[key], oldData[key])) { changedField = key; } - } else if (newData[key] !== oldData[key] && !CHANGE_FIELDS_TO_IGNORE.includes(key)) { + } else if ( + newData[key] !== oldData[key] && + !CHANGE_FIELDS_TO_IGNORE.includes(key) + ) { changedField = key; } }); diff --git a/moped-editor/src/views/projects/projectsListView/ProjectsListViewQueryConf.js b/moped-editor/src/views/projects/projectsListView/ProjectsListViewQueryConf.js index 45d7577801..fcd13d0537 100644 --- a/moped-editor/src/views/projects/projectsListView/ProjectsListViewQueryConf.js +++ b/moped-editor/src/views/projects/projectsListView/ProjectsListViewQueryConf.js @@ -219,12 +219,6 @@ export const PROJECT_LIST_VIEW_QUERY_CONFIG = { defaultHidden: true, showInTable: true, }, - type_name: { - type: "string", - sortable: true, - defaultHidden: true, - showInTable: true, - }, funding_source_and_program_names: { type: "string", sortable: true, @@ -319,7 +313,7 @@ export const PROJECT_LIST_VIEW_QUERY_CONFIG = { defaultHidden: true, showInTable: true, }, - component_work_type_names: { + component_work_type_names: { type: "array", sortable: true, defaultHidden: true, diff --git a/moped-etl/arcgis/settings.py b/moped-etl/arcgis/settings.py index 6db3dafd72..de721d6ca0 100644 --- a/moped-etl/arcgis/settings.py +++ b/moped-etl/arcgis/settings.py @@ -82,7 +82,6 @@ substantial_completion_date substantial_completion_date_estimated task_order_names - type_name workgroup_contractors } }