import os from modules.logger_tool import initialise_logger logger = initialise_logger(__name__, os.getenv("LOG_LEVEL"), os.getenv("LOG_PATH"), 'default', True) import modules.database.schemas.nodes.calendars as calendar_schemas import modules.database.schemas.relationships.calendars as calendar_relationships import modules.database.schemas.relationships.calendar_sequence as calendar_sequence_relationships import modules.database.schemas.relationships.owner_relationships as owner_relationships import modules.database.tools.neontology_tools as neon from datetime import timedelta, datetime def create_calendar(db_name, start_date, end_date, attach_to_calendar_node=False, owner_node=None, time_chunk_node_length: int = None): logger.info(f"Creating calendar for {start_date} to {end_date}") logger.info(f"Initializing Neontology connection") neon.init_neontology_connection() created_years = {} created_months = {} created_weeks = {} created_days = {} last_year_node = None last_month_node = None last_week_node = None last_day_node = None calendar_nodes = { 'calendar_node': None, 'calendar_year_nodes': [], 'calendar_month_nodes': [], 'calendar_week_nodes': [], 'calendar_day_nodes': [] } if attach_to_calendar_node and owner_node: logger.info(f"Attaching calendar to owner's node {owner_node.unique_id} in database: {db_name}") owner_unique_id = owner_node.unique_id calendar_unique_id = f"{start_date.strftime('%Y-%m-%d')}_{end_date.strftime('%Y-%m-%d')}" calendar_node = calendar_schemas.CalendarNode( unique_id=calendar_unique_id, name=f"{start_date.strftime('%Y-%m-%d')} to {end_date.strftime('%Y-%m-%d')}", start_date=start_date, end_date=end_date, tldraw_snapshot="" ) neon.create_or_merge_neontology_node(calendar_node, database=db_name, operation='merge') calendar_nodes['calendar_node'] = calendar_node logger.info(f"Calendar node created: {calendar_node.unique_id}") import modules.database.schemas.relationships.owner_relationships as owner_relationships neon.create_or_merge_neontology_relationship( owner_relationships.OwnerHasCalendar(source=owner_node, target=calendar_node), database=db_name, operation='merge' ) logger.info(f"Relationship created from {owner_node.unique_id} to {calendar_node.unique_id}") elif attach_to_calendar_node and not owner_node: logger.info(f"Creating calendar for {start_date} to {end_date} in database: {db_name}") calendar_node = calendar_schemas.CalendarNode( unique_id=f"{start_date.strftime('%Y-%m-%d')}_{end_date.strftime('%Y-%m-%d')}", name=f"{start_date.strftime('%Y-%m-%d')} to {end_date.strftime('%Y-%m-%d')}", start_date=start_date, end_date=end_date, tldraw_snapshot="" ) neon.create_or_merge_neontology_node(calendar_node, database=db_name, operation='merge') calendar_nodes['calendar_node'] = calendar_node logger.info(f"Calendar node created: {calendar_node.unique_id}") else: logger.error("Invalid combination of parameters for calendar creation.") raise ValueError("Invalid combination of parameters for calendar creation.") current_date = start_date while current_date <= end_date: year = current_date.year month = current_date.month day = current_date.day iso_year, iso_week, iso_weekday = current_date.isocalendar() calendar_year_unique_id = f"{year}" if year not in created_years: year_node = calendar_schemas.CalendarYearNode( unique_id=calendar_year_unique_id, year=str(year), tldraw_snapshot="" ) neon.create_or_merge_neontology_node(year_node, database=db_name, operation='merge') calendar_nodes['calendar_year_nodes'].append(year_node) created_years[year] = year_node logger.info(f"Year node created: {year_node.unique_id}") if attach_to_calendar_node: neon.create_or_merge_neontology_relationship( calendar_relationships.CalendarIncludesYear(source=calendar_node, target=year_node), database=db_name, operation='merge' ) logger.info(f"Relationship created from {calendar_node.unique_id} to {year_node.unique_id}") if last_year_node: neon.create_or_merge_neontology_relationship( calendar_sequence_relationships.YearFollowsYear(source=last_year_node, target=year_node), database=db_name, operation='merge' ) logger.info(f"Relationship created from {last_year_node.unique_id} to {year_node.unique_id}") last_year_node = year_node calendar_month_unique_id = f"{year}_{month}" month_key = f"{year}-{month}" if month_key not in created_months: month_node = calendar_schemas.CalendarMonthNode( unique_id=calendar_month_unique_id, year=str(year), month=str(month), month_name=datetime(year, month, 1).strftime('%B'), tldraw_snapshot="" ) neon.create_or_merge_neontology_node(month_node, database=db_name, operation='merge') calendar_nodes['calendar_month_nodes'].append(month_node) created_months[month_key] = month_node logger.info(f"Month node created: {month_node.unique_id}") # Check for the end of year transition for months if last_month_node: if int(month) == 1 and int(last_month_node.month) == 12 and int(last_month_node.year) == year - 1: neon.create_or_merge_neontology_relationship( calendar_sequence_relationships.MonthFollowsMonth(source=last_month_node, target=month_node), database=db_name, operation='merge' ) logger.info(f"Relationship created from {last_month_node.unique_id} to {month_node.unique_id}") elif int(month) == int(last_month_node.month) + 1: neon.create_or_merge_neontology_relationship( calendar_sequence_relationships.MonthFollowsMonth(source=last_month_node, target=month_node), database=db_name, operation='merge' ) logger.info(f"Relationship created from {last_month_node.unique_id} to {month_node.unique_id}") last_month_node = month_node neon.create_or_merge_neontology_relationship( calendar_relationships.YearIncludesMonth(source=year_node, target=month_node), database=db_name, operation='merge' ) logger.info(f"Relationship created from {year_node.unique_id} to {month_node.unique_id}") calendar_week_unique_id = f"{iso_year}_{iso_week}" week_key = f"{iso_year}-W{iso_week}" if week_key not in created_weeks: # Get the date of the first monday of the week week_start_date = current_date - timedelta(days=current_date.weekday()) week_node = calendar_schemas.CalendarWeekNode( unique_id=calendar_week_unique_id, start_date=week_start_date, week_number=str(iso_week), iso_week=f"{iso_year}-W{iso_week:02}", tldraw_snapshot="" ) neon.create_or_merge_neontology_node(week_node, database=db_name, operation='merge') calendar_nodes['calendar_week_nodes'].append(week_node) created_weeks[week_key] = week_node logger.info(f"Week node created: {week_node.unique_id}") if last_week_node and ((last_week_node.iso_week.split('-')[0] == str(iso_year) and int(last_week_node.week_number) == int(iso_week) - 1) or (last_week_node.iso_week.split('-')[0] != str(iso_year) and int(last_week_node.week_number) == 52 and int(iso_week) == 1)): neon.create_or_merge_neontology_relationship( calendar_sequence_relationships.WeekFollowsWeek(source=last_week_node, target=week_node), database=db_name, operation='merge' ) logger.info(f"Relationship created from {last_week_node.unique_id} to {week_node.unique_id}") last_week_node = week_node neon.create_or_merge_neontology_relationship( calendar_relationships.YearIncludesWeek(source=year_node, target=week_node), database=db_name, operation='merge' ) logger.info(f"Relationship created from {year_node.unique_id} to {week_node.unique_id}") # Day node management calendar_day_unique_id = f"{year}_{month}_{day}" day_key = f"{year}-{month}-{day}" day_node = calendar_schemas.CalendarDayNode( unique_id=calendar_day_unique_id, date=current_date, day_of_week=current_date.strftime('%A'), iso_day=f"{year}-{month:02}-{day:02}", tldraw_snapshot="" ) neon.create_or_merge_neontology_node(day_node, database=db_name, operation='merge') calendar_nodes['calendar_day_nodes'].append(day_node) created_days[day_key] = day_node logger.info(f"Day node created: {day_node.unique_id}") if last_day_node: neon.create_or_merge_neontology_relationship( calendar_sequence_relationships.DayFollowsDay(source=last_day_node, target=day_node), database=db_name, operation='merge' ) logger.info(f"Relationship created from {last_day_node.unique_id} to {day_node.unique_id}") last_day_node = day_node neon.create_or_merge_neontology_relationship( calendar_relationships.MonthIncludesDay(source=month_node, target=day_node), database=db_name, operation='merge' ) logger.info(f"Relationship created from {month_node.unique_id} to {day_node.unique_id}") neon.create_or_merge_neontology_relationship( calendar_relationships.WeekIncludesDay(source=week_node, target=day_node), database=db_name, operation='merge' ) logger.info(f"Relationship created from {week_node.unique_id} to {day_node.unique_id}") current_date += timedelta(days=1) if time_chunk_node_length: time_chunk_interval = time_chunk_node_length # Get every calendar day node and create time chunks of length time_chunk_node minutes for the whole day for day_node in calendar_nodes['calendar_day_nodes']: total_time_chunks_in_day = (24 * 60) / time_chunk_interval for i in range(total_time_chunks_in_day): time_chunk_unique_id = f"{day_node.unique_id}_{i}" time_chunk_start_time = day_node.date.time() + timedelta(minutes=i * time_chunk_interval) time_chunk_end_time = time_chunk_start_time + timedelta(minutes=time_chunk_interval) time_chunk_node = calendar_schemas.CalendarTimeChunkNode( unique_id=time_chunk_unique_id, start_time=time_chunk_start_time, end_time=time_chunk_end_time, tldraw_snapshot="" ) neon.create_or_merge_neontology_node(time_chunk_node, database=db_name, operation='merge') calendar_nodes['calendar_time_chunk_nodes'].append(time_chunk_node) logger.info(f"Time chunk node created: {time_chunk_node.unique_id}") # Create a relationship between the time chunk node and the day node neon.create_or_merge_neontology_relationship( calendar_relationships.DayIncludesTimeChunk(source=day_node, target=time_chunk_node), database=db_name, operation='merge' ) logger.info(f"Relationship created from {day_node.unique_id} to {time_chunk_node.unique_id}") # Create sequential relationship between the time chunk nodes if i > 0: neon.create_or_merge_neontology_relationship( calendar_sequence_relationships.TimeChunkFollowsTimeChunk(source=calendar_nodes['calendar_time_chunk_nodes'][i-1], target=time_chunk_node), database=db_name, operation='merge' ) logger.info(f"Relationship created from {calendar_nodes['calendar_time_chunk_nodes'][i-1].unique_id} to {time_chunk_node.unique_id}") logger.info(f'Created calendar: {calendar_nodes["calendar_node"].unique_id}') return calendar_nodes