私のアプリケーションは、カレンダー情報(1回の発生、再発などを含む)を処理する必要があります。他のアプリケーションと簡単にやり取りするために、iCalendar形式(フィールド、関係、制約)に基づいてデータベーススキーマを直接作成し、ORMを介してiCalendar互換オブジェクトを取得して、いつ簡単に公開できるようにするのがよいと思いました。必要です。
RFCが利用可能であることは知っていますが、現時点では使用していないすべての追加情報があるため、複雑です。
誰かが私にiCal標準(フィールド/フィールド名のリストとiCalエントリの関係)に基づいてデータベーススキーマを作成するためのより簡単なソースを教えてもらえますか?
ありがとう!
私はこれを行いました(VEventsの場合のみ、TODOアイテムやジャーナル全体などはサポートしていません)。私の実装は次のようになります(質問に固有ではない列を削除した後):
-- 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.
これに対応するために、さまざまなイベントの日付を計算するために使用できるSQL Server 2005 + CLR関数がいくつかあります。次のフォームが非常に便利であることがわかりました。
Select * From dbo.getDatesByVEventID(@id, @startDate, @endDate)
Select * From dbo.getEventsByDateRange(@startDate, @endDate, @maxCount)
上記の実装は理解するのがとても楽しいです!
はい、そうですね。 Sunbird(オープンソースのMozillaカレンダー)はsqliteに基づいており、ソースコードをダウンロードして解凍しました。 .sqlファイルが含まれています。
ftp://ftp.mozilla.org/pub/mozilla.org/calendar/sunbird/releases/0.9/source/
mozilla\calendar\provider\storage\schema-7.sql-これは、sunbirdが有効なiCalファイルを作成するために使用するスキーマであるため、それほど悪くはありません。
上記の素晴らしいソリューションを提供してくれたChrisNielsenに感謝します。しかし、問題があったので修正しました。上記の解決策はpython sqlalchemyにあることに注意してください。すぐに変換します。
クリスのソリューションに関する私の主な問題は(そしてそれらはすべての人に当てはまるとは限らないかもしれません)
彼のソリューションでは、多くの列は必要ありませんでした。イベントと繰り返しに役立つ列のみが必要でした。これはiCalendar仕様のせいであり、Chrisのせいではありません。以下の私の解決策は、カレンダーの制限とシーケンスの制限の観点から繰り返しルールのみを考慮しています。
特定の列(最も重要なのはdtStartとdtEnd)は、RRULEではなくVEVENTに属していますが、ChrisはそれらをRRULEに配置しました。これは私を混乱させました。 VEVENT: https://tools.ietf.org/html/rfc5545#section-3.6.1 ルール: https://tools.ietf.org/html/rfc5545#section- 3.3.1
以下はsqlalchemyでの私の解決策です。これをできるだけ早くSQLに変換します。
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')
このドキュメントをApple icalendarで試すことができます。フィールドをデータベーステーブルに直接複製できます。 http://developer.Apple.com/library/mac/#DOCUMENTATION/AppleApplications /Reference/SyncServicesSchemaRef/Articles/Calendars.html
javaを使用する場合、ical4jはスキーマとインターフェースの間の接着剤を提供します。 Javaを使用しない場合は、オカレンスと構造を生成するためのソースコードのアルゴリズムが、実装に役立ちます。