iCalendar “Campo” lista (per lo schema del database in base a standard iCalendar)

StackOverflow https://stackoverflow.com/questions/1054201

  •  20-08-2019
  •  | 
  •  

Domanda

la mia domanda ha a che fare con le informazioni del calendario (incl. Singola occorrenza, recidiva, ecc). Al fine di interfacciarsi facilmente con altre applicazioni ho pensato che sarebbe una buona idea per creare il mio schema di database in base al formato iCalendar (campi, relazioni, vincoli) direttamente in modo che ricevo oggetti compatibili iCalendar via ORM che posso facilmente esporre quando necessario.

So che la RFC è disponibile, ma è un po 'complicato a causa di tutti gli ulteriori elementi in esso che io non uso al momento.

Potrebbe qualcuno mi punto ad una fonte più facile creare uno schema di database basato sullo standard iCal (vale a dire un elenco di campi / nomi dei campi e il loro rapporto per le voci iCal)?

Grazie!

È stato utile?

Soluzione

Ho fatto questo (per VEvents solo, che non supportano gli elementi TODO o interi giornale o qualcosa di simile). La mia applicazione si presenta così (dopo aver rimosso le colonne che non sono specifici alla domanda):

-- 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.

Per andare avanti con questo, ho diversi SQL Server 2005 + funzioni CLR che possono essere utilizzate per calcolare le date per vari eventi. Ho trovato le seguenti forme di essere molto utile:

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

L'attuazione del divertimento sopra è rammendare per capire!

Altri suggerimenti

Sì, più o meno. Sunbird (calendario Mozilla opensource) si basa su SQLite e ho appena scaricato e decompresso il loro codice sorgente. Ha file sql in esso.

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

Mozilla \ calendario \ fornitori \ storage \ schema-7.sql --Questo è lo schema che utilizza Sunbird per rendere i file iCal validi, quindi non può essere troppo male.

Grazie mille Chris Nielsen per la sua grande soluzione di cui sopra. Tuttavia, ho avuto qualche problema con esso in modo ho modificato. Si prega di notare che la soluzione di cui sopra è in python SQLAlchemy. Io convertirlo molto presto.

I miei principali difficoltà con la soluzione di Chris (e potrebbero non valere per tutti) sono

  1. non ho bisogno di molte delle colonne della sua soluzione. Ho solo bisogno di colonne che mi avrebbe aiutato con eventi e ricorrenze. Questo è il difetto della specifica iCalendar, non Chris. La mia soluzione qui di seguito solo considera le regole di ricorrenza in termini di restrizioni del calendario e le loro restrizioni di sequenza.

  2. Alcune colonne - soprattutto dtstart e DTEND - appartengono a VEVENT, non RRULE, ma Chris li ha posti in RRULE. Questo è stato confuso per me. VEVENT: https://tools.ietf.org/html/rfc5545#section- 3.6.1 RRULE: https://tools.ietf.org/html/rfc5545#section- 3.3.10

  3. Ho anche bisogno di capire come contenere un programma che potrebbe avere una varietà di modelli. Ad esempio, un evento potrebbe accadere ogni settimana il Venerdì dalle 18:00-21:00, ma anche per tutto il giorno il primo maggio. Ciò richiede flessibilità e dtstart DTEND. Per questo motivo, ho creato una tabella "PROGRAMMA" che contiene che mantiene una relazione molti-a-molti con eventi, mentre gli eventi hanno un rapporto di contenimento con RRULES.

Di seguito è la mia soluzione in SQLAlchemy. Io convertire questo a SQL ASAP.

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')

iCal è un'applicazione di Apple che segue lo standard attualmente conosciuto come iCalendar (il successore del precedente Vcalendar). Credo che la wikipedia ha tutte informazioni che ti servono per i vostri scopi, e in modo semplice e facile da seguire formato, ma, non esitate a chiedere per maggiori indicazioni, se necessario !!!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top