OpenSocialのサービスプロバイダっぽいのを作ってみる 2.データベース設計を考える

まずはpersonだけ。
適当翻訳。

おそらくサービスプロバイダに用意されているであろう標準的なフィールド。

id                       ユニークな識別子。必須。
displayName              エンドユーザ向けの表示に適した名前。必須。
name                     名前。
    formatted            表示用のフルネーム。
    familyName           姓。
    givenName            名。
    middleName           ミドルネーム。
    honorificPrefix      名前の前に付ける敬称。 ex) Mr.
    honorificSuffix      名前の後につける敬称。 ex) さん
nickname                 普段呼ばれている名前。usernameを表すのには適さない。
published                登録日。xs:dateTime形式で記述。 ex) 2008-01-23T04:56:22Z
updated                  アップデート日。xs:dateTime形式で記述。
birthday                 誕生日。xs:date形式で記述。年を設定/公開していない場合は0000年になるかも。 ex) 1975-02-14
anniversary              結婚記念日。xs:date形式で記述。
gender                   性別。男:male、女:female、非公開:undisclosed。
note                     フリーフォーマットな備考。複数行可。
preferredUsername        所有者について説明するのに役に立つかも。
utcOffset                タイムゾーン。xs:dateTime形式で記述。 ex) -08:00
connected                ViewerとこのPersonが繋がっているか。Boolean。


別の方法で指定されない場合、すべての複数フィールドには、同じ3つの標準のサブフィールドがある。
value                   値。
type                    work, home, otherのいずれか。
primary                 デフォルトで使用するか否か。Boolean。falseの場合はサブフィールドそのものを省略する。


emails                  メールアドレス。小文字化等、正規化はサービスプロバイダ側でする。
urls                    URL。スキーマを付ける等、正規化はサービスプロバイダ側でする。
    type                work, home, other, blog, profileのいずれか。
phoneNumbers            電話番号。正規化はしなくていい。
    type                work, home, other, mobile, fax, pagerのいずれか。
ims                     メッセンジャーアドレス。ホワイトスペース削除や小文字化等、正規化はサービスプロバイダ側でする。
    type                work, home, other, aim, gtalk, icq, xmpp, msn, skype, qq, yahooのいずれか。
photos                  表示用プロフィール写真のURL。
tags                    このPersonに対するユーザによって定義されたカテゴリラベル。大文字小文字を区別しない。
relationships           ViewerとこのPersonの双方向の関係。kin, friend, contact等。

addresses               住所。
    formatted           表示用の完全な住所。
    streetAddress       ストリートアドレス。
    locality            都市。
    region              州。
    postalCode          郵便番号。
    country             国名。
organizations           組織。
    name                組織名。会社、学校、その他組織。
    department          部署。
    title               役職、任務。
    type                job, schoolのいずれか。
    startDate           このPersonがこの組織に参加した日付。可能な限りxs:date形式で記述。
    endDate             このPersonがこの組織か役職を辞めた日付。可能な限りxs:date形式で記述。
    location            この組織の物理的な位置。 ex) San Francisco
    description         このPersonがこの組織で果たした役割。複数行可。
accounts                サービスプロバイダでのPersonのアカウント。
    domain              Personの所属するサービスプロバイダの正式ドメイン ex) twitter.com
    username            通常、ユーザが決めた英数字のユーザ名。
    userid              通常、サービスプロバイダが決めた英数字のユーザID。

 
ここ1〜2週間、どう作れば楽かをずっと考えてた。
で、値を1つしか持たないものをpersonに入れて、値を複数持つものをperson_xxxに入れる。
GETでリクエストが来たときは、そのテーブル1つずつselectして、配列にくっつける。
とりあえず、こんな感じでデータベース作ってみた。

create table consumer(
    consumer_id         serial not null,
    consumer_key        varchar(255) not null unique,
    consumer_secret     varchar(255) not null,
    public_key          text,
    permit_basic        boolean not null default true,
    permit_digest       boolean not null default true,
    permit_wsse         boolean not null default true,
    permit_oauth_hmac   boolean not null default true,
    permit_oauth_rsa    boolean not null default true,
    formattedName       varchar(255) not null default '[fam][giv][suf]',
    honorificPrefix     varchar(255),
    honorificSuffix     varchar(255),
    formattedAddress    varchar(255) not null default '[cou][reg][loc][str]',
    created             datetime not null
);

insert into consumer (consumer_key,consumer_secret,created) values ('test','0123456789',now());

create table person(
    consumer_id         bigint unsigned not null,
    person_id           serial not null,
    password            varchar(255) not null,
    displayName         varchar(255),
    familyName          varchar(255),
    givenName           varchar(255),
    middleName          varchar(255),
    nickname            varchar(255),
    published           datetime not null,
    updated             datetime not null,
    birthday            datetime,
    anniversary         datetime,
    gender              enum('male','female'),
    note                text,
    preferredUsername   varchar(255),
    unique(consumer_id,person_id)
);

insert into person (consumer_id,password,displayName,published,updated,gender,note) values (1,'aaa_pass','aaa_user',now(),now(),'male','hello!!');
insert into person (consumer_id,password,displayName,published,updated,gender,note) values (1,'bbb_pass','bbb_user',now(),now(),'male','hello!!');
insert into person (consumer_id,password,displayName,published,updated,gender,note) values (1,'ccc_pass','ccc_user',now(),now(),'male','hello!!');

create table person_emails(
    consumer_id         bigint unsigned not null,
    person_id           bigint unsigned not null,
    value               varchar(255) not null,
    type                enum('work','home','other') not null,
    `primary`           boolean not null default false,
    unique(consumer_id,person_id,type)
);

create table person_urls(
    consumer_id         bigint unsigned not null,
    person_id           bigint unsigned not null,
    value               varchar(255) not null,
    type                enum('work','home','other','blog','profile') not null,
    `primary`           boolean not null default false,
    unique(consumer_id,person_id,type)
);

create table person_phoneNumbers(
    consumer_id         bigint unsigned not null,
    person_id           bigint unsigned not null,
    value               varchar(255) not null,
    type                enum('work','home','other','mobile','fax','pager') not null,
    `primary`           boolean not null default false,
    unique(consumer_id,person_id,type)
);

create table person_ims(
    consumer_id         bigint unsigned not null,
    person_id           bigint unsigned not null,
    value               varchar(255) not null,
    type                enum('work','home','other','aim','gtalk','icq','xmpp','msn','skype','qq','yahoo') not null,
    `primary`           boolean not null default false,
    unique(consumer_id,person_id,type)
);

create table person_photos(
    consumer_id         bigint unsigned not null,
    person_id           bigint unsigned not null,
    value               varchar(255) not null,
    type                enum('work','home','other') not null,
    `primary`           boolean not null default false,
    unique(consumer_id,person_id,type)
);

create table person_tags(
    consumer_id         bigint unsigned not null,
    person_id           bigint unsigned not null,
    uid                 varchar(255) not null,
    value               varchar(255) not null,
    type                enum('work','home','other') not null,
    `primary`           boolean not null default false,
    unique(consumer_id,person_id,type)
);

create table person_follow(
    consumer_id         bigint unsigned not null,
    person_id           bigint unsigned not null,
    uid                 bigint unsigned not null,
    unique(consumer_id,person_id,uid)
);

create table person_addresses(
    consumer_id         bigint unsigned not null,
    person_id           bigint unsigned not null,
    streetAddress       varchar(255),
    locality            varchar(255),
    region              varchar(255),
    postalCode          varchar(255),
    country             varchar(255),
    type                enum('work','home','other') not null,
    unique(consumer_id,person_id,type)
);

create table person_organizations(
    consumer_id         bigint unsigned not null,
    person_id           bigint unsigned not null,
    name                varchar(255),
    department          varchar(255),
    title               varchar(255),
    type                enum('job','school') not null,
    startDate           varchar(255),
    endDate             varchar(255),
    location            varchar(255),
    description         text,
    unique(consumer_id,person_id,type)
);

create table person_accounts(
    consumer_id         bigint unsigned not null,
    person_id           bigint unsigned not null,
    domain              varchar(255) not null,
    username            varchar(255),
    userid              varchar(255),
    unique(consumer_id,person_id,domain)
);

 
まずは基本。(まだそれしか出来てない)
ユーザ情報の取得。
うっかり名前を階層化するのを忘れた。

GET /people/test:1,test:2/@self?〜〜〜

[{"displayName":"aaa_user","familyName":null,"givenName":null,"middleName":null,"nickname":null,"published":"2009-08-07 03:08:26","updated":"2009-08-07 03:08:26","birthday":null,"anniversary":null,"gender":"male","note":"hello!!","preferredUsername":null,"emails":[],"urls":[],"phoneNumbers":[],"ims":[],"photos":[],"tags":[],"addresses":[],"organizations":[],"accounts":[]},{"displayName":"bbb_user","familyName":null,"givenName":null,"middleName":null,"nickname":null,"published":"2009-08-07 03:08:26","updated":"2009-08-07 03:08:26","birthday":null,"anniversary":null,"gender":"male","note":"hello!!","preferredUsername":null,"emails":[],"urls":[],"phoneNumbers":[],"ims":[],"photos":[],"tags":[],"addresses":[],"organizations":[],"accounts":[]}]

 
どうすれば楽に作れるかなぁ。
多分このデータベースも作り直す。
というか、OpenSocialに準拠しようとしてるはずだけど、あってるのかなぁ。
 
RESTful Protocol v0.8.1
http://www.opensocial.org/Technical-Resources/opensocial-spec-v081/restful-protocol