mi aplicación tiene que lidiar con la información de calendario (incl. única aparición de la recurrencia, etc.). Con el fin de interactuar fácilmente con otras aplicaciones que he pensado que sería una buena idea crear mi esquema de base de datos basado en el formato iCalendar (campos, relaciones, restricciones) directamente por lo que me sale de iCalendar compatible objetos a través de la ORM que me puede exponer fácilmente cuando sea necesario.

Sé que el RFC está disponible, pero es un poco complicado debido a toda la información adicional que yo no uso en el momento.

Podía alguien me apunte a una más fácil de origen para crear un esquema de base de datos basado en el estándar iCal (es decir, una lista de campos/fieldnames y su relación, por iCal entradas)?

Gracias!

InformationsquelleAutor Alex | 2009-06-28

5 Comentarios

  1. 41

    He hecho esto (para VEvents sólo, no compatible con TODO los elementos o Diario entires ni nada de eso). Mi aplicación se parece a esto (después de eliminar las columnas que no son específicas de la pregunta):

    -- One table for each event.  An event may have multiple rRules.
    Create Table [vEvent]
        (vEventID Integer Identity(1, 1) Not Null
         Constraint [vEvent.pk]
         Primary Key
         Clustered
        ,title nVarChar(200) Not Null);
    
    -- One table for rRules.
    -- My application does NOT support the "bySetPos" rule, so that is not included.
    Create Table [rRule]
        (rRuleID Integer Identity(1, 1) Not Null
         Constraint [rRule.pk]
         Primary Key
         Clustered
        ,vEventID Integer Not Null
         Constraint [fk.vEvent.rRules]
         Foreign Key
         References [vEvent] (vEventID)
         On Update Cascade
         On Delete Cascade
        ,[class]            varChar(  12) Not Null Default('public')
        ,[created]         DateTime       Not Null Default(getUTCDate())
        ,[description]     nVarChar(max)      Null
        ,[dtStart]         DateTime       Not Null
        ,[dtEnd]           DateTime           Null
        ,[duration]         varChar(  20)     Null
        ,[geoLat]          Float              Null
        ,[geoLng]          Float              Null
        ,[lastModified]    DateTime       Not Null Default(getUTCDate())
        ,[location]        nVarChar(max)      Null
        ,[organizerCN]     nVarChar(  50)     Null
        ,[organizerMailTo] nVarChar( 100)     Null
        ,[seq]             Integer        Not Null Default(0)
        ,[status]           varChar(   9) Not Null Default('confirmed')
        ,[summary]         nVarChar(  75)     Null
        ,[transparent]     Bit            Not Null Default(0)
        ,[freq]             varChar(   8) Not Null Default('daily')
        ,[until]           DateTime           Null
        ,[count]           Integer            Null
        ,[interval]        Integer        Not Null Default(1)
        ,[bySecond]         varChar( 170)     Null
        ,[byMinute]         varChar( 170)     Null
        ,[byHour]           varChar(  61)     Null
        ,[byDay]            varChar(  35)     Null
        ,[byMonthDay]       varChar( 200)     Null
        ,[byYearDay]        varChar(3078)     Null
        ,[byWeekNo]         varChar( 353)     Null
        ,[byMonth]          varChar(  29)     Null
        ,[wkSt]             Char   (   2)     Null Default('mo'));
    
    -- Class must be one of "Confidential", "Private", or "Public"
    Alter Table [rRule]
    Add Constraint [rRule.ck.Class]
    Check ([class] In ('confidential', 'private', 'public'));
    
    -- Start date must come before End date
    Alter Table [rRule]
    Add Constraint [rRule.ck.dtStart]
    Check ([dtEnd] Is Null Or [dtStart] <= [dtEnd]);
    
    -- dtEnd and duration may not both be present
    Alter Table [rRule]
    Add Constraint [rRule.ck.duration]
    Check (Not ([dtEnd] Is Not Null And [duration] Is Not Null));
    
    -- Check valid values for [freq]. Note that 'single' is NOT in the RFC;
    -- it is an optimization for my particular iCalendar calculation engine.
    -- I use it as a clue that this pattern has only a single date (dtStart),
    -- and there is no need to perform extra calculations on it.
    Alter Table [rRule]
    Add Constraint [rRule.ck.freq]
    Check ([freq] In
        ('yearly'
        ,'monthly'
        ,'weekly'
        ,'daily'
        ,'hourly'
        ,'minutely'
        ,'secondly'
        ,'single')); -- Single is NOT part of the spec!
    
    -- If there is a latitude, there must be a longitude, and vice versa.
    Alter Table [rRule]
    Add Constraint [rRule.ck.geo]
    Check (([geoLat] Is Null And [geoLng] Is Null)
           Or ([geoLat] Is Not Null And [geoLng] Is Not Null));
    
    -- Interval must be positive.
    Alter Table [rRule]
    Add Constraint [rRule.ck.interval]
    Check ([interval] > 0);
    
    -- Status has a set of defined values.
    Alter Table [rRule]
    Add Constraint [rRule.ck.status]
    Check ([status] In ('cancelled', 'confirmed', 'tentative'));
    
    -- Until and Count may not coexist in the same rule.
    Alter Table [rRule]
    Add Constraint [rRule.ck.until and count]
    Check (Not ([until] Is Not Null And [count] Is Not Null));
    
    
    -- One table for exceptions to rRules.  In my application, this covers both
    -- exDate and rDate.  I do NOT support extended rule logic here;  The RFC says
    -- you should support the same sort of date calculations here as are supported
    -- in rRules: exceptions can recur, etc.  I don't do that; mine is simply a
    -- set of dates that are either "exceptions" (dates which don't appear, even
    -- if the rule otherwise says they should) or "extras" (dates which do appear,
    -- even if the rule otherwise wouldn't include them).  This has proved
    -- sufficient for my application, and something that can be exported into a
    -- valid iCalendar file--even if I can't import an iCalendar file that makes
    -- use of recurring rules for exceptions to recurring rules.
    Create Table [exDate]
        (exDateID Integer Identity(1, 1) Not Null
         Constraint [exDate.pk]
         Primary Key
         Clustered
        ,rRuleID Integer Not Null
         Constraint [fk.rRule.exDates]
         Foreign Key
         References [rRule] (rRuleID)
         On Update Cascade
         On Delete Cascade
        ,[date] DateTime Not Null
        ,[type] varChar(6) Not Null);  -- Type = "exDate" or "rDate" for me; YMMV.

    Para ir junto con esto, tengo varios de SQL Server 2005+ CLR funciones que se pueden utilizar para calcular las fechas para eventos varios. He encontrado los siguientes formularios a ser muy útil:

    Select * From dbo.getDatesByVEventID(@id, @startDate, @endDate)
    Select * From dbo.getEventsByDateRange(@startDate, @endDate, @maxCount)

    La aplicación de las anteriores es muy divertido para averiguar!

    • Sé que esto es más de 7 años de edad, es cómo acercarse a este, Y hacer una versión más reciente de SQL dar mejores opciones de consulta?
  2. 12

    Sí, una especie de. Sunbird (opensource mozilla calendar) está basado en sqlite y me acaba de descargar y descomprimir su código fuente. Ha .sql archivos.

    ftp://ftp.mozilla.org/pub/mozilla.org/calendar/sunbird/releases/0.9/source/

    mozilla\calendario\proveedores\almacenamiento\schema-7.sql –este es el esquema que sunbird utiliza para hacer válido archivos iCal, por lo que no puede ser tan malo.

  3. 1

    Muchas gracias Chris Nielsen por su gran solución anterior. Sin embargo, he tenido algunos problemas con ella, así que la he modificado. Por favor, tenga en cuenta que la solución anterior es en python sqlalchemy. Voy a convertir muy pronto.

    Mis principales dificultades con Chris de la solución (y que puede que no se aplique a todo el mundo) son

    1. No tenía la necesidad de muchas de las columnas en su solución. Sólo necesitaba columnas que me ayudaría con los Eventos y las Recurrencias. Esto es culpa de la iCalendar spec, no de Chris. Mi solución a continuación sólo tiene en cuenta la recurrencia de reglas en términos de su calendario de restricciones y su secuencia de restricciones.

    2. Ciertas columnas, lo más importante dtStart y dtEnd — pertenecen a VEVENT, no la regla, pero Chris colocó en la regla. Esto era confuso para mí.
      VEVENT: https://tools.ietf.org/html/rfc5545#section-3.6.1
      La regla: https://tools.ietf.org/html/rfc5545#section-3.3.10

    3. Yo también tenía que averiguar cómo contener una programación que podría tener una variedad de patrones. Por ejemplo, un evento puede suceder cada semana, los viernes de 6PM-9PM, sino también todo el día en el primer Día de Mayo. Esto requiere flexibilidad con dtStart y dtEnd. Por este motivo, he creado una Tabla que contiene la «PROGRAMACIÓN» que mantiene muchos-a-muchos relación con los EVENTOS, mientras que los EVENTOS tienen una relación de contención con RRULES.

    A continuación es mi solución en sqlalchemy. Voy a convertir esto en SQL lo antes posible.

    from app import db
    from sqlalchemy import CheckConstraint
    from sqlalchemy.ext.associationproxy import association_proxy
    
    
    class Schedule(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        subtypes_relation = db.relationship('Event', secondary=schedule_event_association,
                                            backref=db.backref('Schedule', lazy='dynamic'))
    
    schedule_event_association = db.Table(
        'schedule_event_association',
        db.Column('schedule_id', db.Integer, db.ForeignKey('schedule.id')),
        db.Column('event_id', db.Integer, db.ForeignKey('event.id')))
    
    class Event(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        dt_start = db.Column(db.DateTime)  # start time
        dt_end = db.Column(db.DateTime) # end time
        tz_id = db.Column(db.String) # Time Zone
    
        recurrence_rule = db.Column('RecurrenceRule_id',  db.Integer, db.ForeignKey('RecurrenceRule.id'))
    
    # Start date must come before End date
        CheckConstraint('dtEnd is NULL OR dtStart <= dtEnd', name='Valid: Time Period')
    
    class RecurrenceRule(db.Model):
        id = db.Column(db.Integer, primary_key=True)
    
        # Frequency Type
        freq = db.Column(db.String(8), nullable=False, default='weekly') # type of recurrence
    
        # Calendar-Based Rules
        byDay = db.Column(db.String(35))   # List of Day of the Week
                                            # "mo,tu,we" for weekly
                                            # "+2MO, -1MO" = second monday, last monday for yearly or monthly
        byMonthDay = db.Column(db.String(200)) # List of Day of the Month
                                                # +1,-1"
                                                # Only for Monthly or Yearly
        byYearDay = db.Column(db.String(3078)) # List Day of the Year
                                                #"+1, -1"
                                                # Only for yearly
                                                # Take care with leap years
        byWeekNo = db.Column(db.String(353)) # Which week of Mon`enter code here`th
                                                # "+5, -3" for fifth and third-to-last
                                                # Only for yearly
        byMonth = db.Column(db.String(29))   # Month of year.
    
        # Sequence-Based Rules
        until = db.Column(db.DateTime)   # last day of occurence
        count = db.Column(db.Integer)    # number of occurences
        interval = db.Column(db.Integer, nullable=False, default=1) # interval between recurrences
        bysetpos = db.Column(db.String()) # Specifies specific instances of recurrence
    
    
    # Valid Values
        CheckConstraint(freq in ('yearly', 'monthly', 'weekly', 'daily', 'single'),
                        name='Valid: Frequency Value')
        CheckConstraint(interval > 0, name='Valid: Positive Interval')
        CheckConstraint(byDay is not None and freq in ('daily', 'yearly', 'monthly'))
        CheckConstraint(byWeekNo is not None and freq in ('yearly', 'monthly'))
        CheckConstraint(byYearDay is not None and freq == 'yearly')
    
    # Until and Count may not coexist in the same rule.
        CheckConstraint(not (until is not None and count is not None),
                        name='Valid: Not Both Until and Count')
  4. 0

    iCal es una aplicación de Apple que sigue la norma que actualmente se conoce como Icalendar (el sucesor del anterior Vcalendar). Creo que la wikipedia la entrada tiene toda la información que usted necesita para sus fines, y en un simple y fácil-a-sigue el formato, pero, siéntase libre de pedir más ayuda si lo necesita!!!

  5. 0

Dejar respuesta

Please enter your comment!
Please enter your name here