parent
351fe2a257
commit
97d0ff1467
8 changed files with 816 additions and 0 deletions
@ -0,0 +1,17 @@ |
||||
#!/usr/bin/env bash |
||||
|
||||
CLASS_NAME="WeightGrapher::DB" |
||||
|
||||
# Generate a random 8 character name for the docker container that holds the PSQL |
||||
# database. |
||||
PSQL_NAME=$(cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z' | fold -w 8 | head -n 1) |
||||
|
||||
# Launch a PSQL Instance |
||||
PSQL_DOCKER=`docker run --rm --name $PSQL_NAME -e POSTGRES_PASSWORD=dbic -e POSTGRES_USER=dbic -e POSTGRES_DB=dbic -d \ |
||||
--mount type=bind,src=$PWD/etc/schema.sql,dst=/docker-entrypoint-initdb.d/schema.sql postgres:11` |
||||
|
||||
docker run --rm --link $PSQL_NAME:psqldb --mount type=bind,src=$PWD,dst=/app symkat/schema_builder /bin/build-schema $CLASS_NAME |
||||
|
||||
docker kill $PSQL_DOCKER |
||||
|
||||
sudo chown -R $USER:$USER lib |
||||
@ -0,0 +1,21 @@ |
||||
name = WeightGrapher-DB |
||||
author = Kaitlyn Parkhurst <symkat@symkat.com> |
||||
license = Perl_5 |
||||
copyright_holder = Kaitlyn Parkhurst |
||||
copyright_year = 2022 |
||||
abstract = WeightGrapher Database |
||||
version = 1 |
||||
|
||||
[@Basic] |
||||
|
||||
[Prereqs] |
||||
DBIx::Class::InflateColumn::Serializer = 0 |
||||
DBIx::Class::Schema::Config = 0 |
||||
DBIx::Class::DeploymentHandler = 0 |
||||
DBIx::Class::Schema::ResultSetNames = 0 |
||||
MooseX::AttributeShortcuts = 0 |
||||
MooseX::Getopt = 0 |
||||
Data::GUID = 0 |
||||
DBD::Pg = 0 |
||||
Crypt::Eksblowfish::Bcrypt = 0 |
||||
Crypt::Random = 0 |
||||
@ -0,0 +1,68 @@ |
||||
CREATE EXTENSION IF NOT EXISTS citext; |
||||
|
||||
CREATE TABLE person ( |
||||
id serial PRIMARY KEY, |
||||
name text not null, |
||||
email citext not null unique, |
||||
is_enabled boolean not null default true, |
||||
is_admin boolean not null default false, |
||||
created_at timestamptz not null default current_timestamp |
||||
); |
||||
|
||||
-- Settings for a given user. | Use with care, add things to the data model when you should. |
||||
CREATE TABLE person_settings ( |
||||
id serial PRIMARY KEY, |
||||
person_id int not null references person(id), |
||||
name text not null, |
||||
value json not null default '{}', |
||||
created_at timestamptz not null default current_timestamp, |
||||
|
||||
-- Allow ->find_or_new_related() |
||||
CONSTRAINT unq_person_id_name UNIQUE(person_id, name) |
||||
); |
||||
|
||||
CREATE TABLE auth_password ( |
||||
person_id int not null unique references person(id), |
||||
password text not null, |
||||
salt text not null, |
||||
updated_at timestamptz not null default current_timestamp, |
||||
created_at timestamptz not null default current_timestamp |
||||
); |
||||
|
||||
CREATE TABLE auth_token ( |
||||
id serial PRIMARY KEY, |
||||
person_id int not null references person(id), |
||||
scope text not null, |
||||
token text not null, |
||||
created_at timestamptz not null default current_timestamp |
||||
); |
||||
|
||||
--- |
||||
--- |
||||
--- |
||||
|
||||
-- CREATE TABLE graph ( |
||||
-- id serial PRIMARY KEY, |
||||
-- person_id int not null references person(id), |
||||
-- title text not null, |
||||
-- unit text not null, -- lb / kg / st |
||||
-- created_at timestamptz not null default current_timestamp |
||||
-- ); |
||||
-- |
||||
-- CREATE TABLE graph_settings ( |
||||
-- id serial PRIMARY KEY, |
||||
-- graph_id int not null references graph(id), |
||||
-- name text not null, |
||||
-- value json not null default '{}', |
||||
-- |
||||
-- -- Allow ->find_or_new_related() |
||||
-- CONSTRAINT unq_graph_id_name UNIQUE(graph_id, name) |
||||
-- ); |
||||
-- |
||||
-- CREATE TABLE graph_data ( |
||||
-- id serial PRIMARY KEY, |
||||
-- graph_id int not null references graph(id), |
||||
-- value numeric not null, |
||||
-- note text , |
||||
-- ts timestamptz not null default current_timestamp |
||||
-- ); |
||||
@ -0,0 +1,22 @@ |
||||
use utf8; |
||||
package WeightGrapher::DB; |
||||
|
||||
# Created by DBIx::Class::Schema::Loader |
||||
# DO NOT MODIFY THE FIRST PART OF THIS FILE |
||||
|
||||
use strict; |
||||
use warnings; |
||||
|
||||
use base 'DBIx::Class::Schema'; |
||||
|
||||
__PACKAGE__->load_components("Schema::Config", "Schema::ResultSetNames"); |
||||
|
||||
__PACKAGE__->load_namespaces; |
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-08-29 23:53:08 |
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:rztJ5RmpMtq7ukHg5gS0vw |
||||
|
||||
|
||||
# You can replace this text with custom code or comments, and it will be preserved on regeneration |
||||
1; |
||||
@ -0,0 +1,176 @@ |
||||
use utf8; |
||||
package WeightGrapher::DB::Result::AuthPassword; |
||||
|
||||
# Created by DBIx::Class::Schema::Loader |
||||
# DO NOT MODIFY THE FIRST PART OF THIS FILE |
||||
|
||||
=head1 NAME |
||||
|
||||
WeightGrapher::DB::Result::AuthPassword |
||||
|
||||
=cut |
||||
|
||||
use strict; |
||||
use warnings; |
||||
|
||||
use base 'DBIx::Class::Core'; |
||||
|
||||
=head1 COMPONENTS LOADED |
||||
|
||||
=over 4 |
||||
|
||||
=item * L<DBIx::Class::InflateColumn::DateTime> |
||||
|
||||
=item * L<DBIx::Class::InflateColumn::Serializer> |
||||
|
||||
=back |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->load_components("InflateColumn::DateTime", "InflateColumn::Serializer"); |
||||
|
||||
=head1 TABLE: C<auth_password> |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->table("auth_password"); |
||||
|
||||
=head1 ACCESSORS |
||||
|
||||
=head2 person_id |
||||
|
||||
data_type: 'integer' |
||||
is_foreign_key: 1 |
||||
is_nullable: 0 |
||||
|
||||
=head2 password |
||||
|
||||
data_type: 'text' |
||||
is_nullable: 0 |
||||
|
||||
=head2 salt |
||||
|
||||
data_type: 'text' |
||||
is_nullable: 0 |
||||
|
||||
=head2 updated_at |
||||
|
||||
data_type: 'timestamp with time zone' |
||||
default_value: current_timestamp |
||||
is_nullable: 0 |
||||
|
||||
=head2 created_at |
||||
|
||||
data_type: 'timestamp with time zone' |
||||
default_value: current_timestamp |
||||
is_nullable: 0 |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->add_columns( |
||||
"person_id", |
||||
{ data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, |
||||
"password", |
||||
{ data_type => "text", is_nullable => 0 }, |
||||
"salt", |
||||
{ data_type => "text", is_nullable => 0 }, |
||||
"updated_at", |
||||
{ |
||||
data_type => "timestamp with time zone", |
||||
default_value => \"current_timestamp", |
||||
is_nullable => 0, |
||||
}, |
||||
"created_at", |
||||
{ |
||||
data_type => "timestamp with time zone", |
||||
default_value => \"current_timestamp", |
||||
is_nullable => 0, |
||||
}, |
||||
); |
||||
|
||||
=head1 UNIQUE CONSTRAINTS |
||||
|
||||
=head2 C<auth_password_person_id_key> |
||||
|
||||
=over 4 |
||||
|
||||
=item * L</person_id> |
||||
|
||||
=back |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->add_unique_constraint("auth_password_person_id_key", ["person_id"]); |
||||
|
||||
=head1 RELATIONS |
||||
|
||||
=head2 person |
||||
|
||||
Type: belongs_to |
||||
|
||||
Related object: L<WeightGrapher::DB::Result::Person> |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->belongs_to( |
||||
"person", |
||||
"WeightGrapher::DB::Result::Person", |
||||
{ id => "person_id" }, |
||||
{ is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, |
||||
); |
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-08-29 23:53:08 |
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:vdn8gq3VmE1q9sqlN7w3fA |
||||
|
||||
__PACKAGE__->set_primary_key('person_id'); |
||||
|
||||
use Crypt::Eksblowfish::Bcrypt qw( bcrypt_hash en_base64 de_base64 ); |
||||
use Crypt::Random; |
||||
|
||||
sub check_password { |
||||
my ( $self, $password ) = @_; |
||||
return de_base64($self->password) eq bcrypt_hash({ |
||||
key_nul => 1, |
||||
cost => 8, |
||||
salt => de_base64($self->salt), |
||||
}, $password ); |
||||
} |
||||
|
||||
sub set_password { |
||||
my ( $self, $password ) = @_; |
||||
$self->_fill_password( $password ); |
||||
$self->insert; |
||||
return $self; |
||||
} |
||||
|
||||
sub update_password { |
||||
my ( $self, $password ) = @_; |
||||
$self->_fill_password( $password ); |
||||
$self->update; |
||||
return $self; |
||||
} |
||||
|
||||
sub _fill_password { |
||||
my ( $self, $password ) = @_; |
||||
|
||||
my $salt = random_salt(); |
||||
|
||||
$self->password( |
||||
en_base64( |
||||
bcrypt_hash({ |
||||
key_nul => 1, |
||||
cost => 8, |
||||
salt => $salt, |
||||
}, $password ) |
||||
) |
||||
); |
||||
|
||||
$self->salt( en_base64($salt) ); |
||||
} |
||||
|
||||
sub random_salt { |
||||
Crypt::Random::makerandom_octet( Length => 16 ); |
||||
} |
||||
|
||||
1; |
||||
@ -0,0 +1,128 @@ |
||||
use utf8; |
||||
package WeightGrapher::DB::Result::AuthToken; |
||||
|
||||
# Created by DBIx::Class::Schema::Loader |
||||
# DO NOT MODIFY THE FIRST PART OF THIS FILE |
||||
|
||||
=head1 NAME |
||||
|
||||
WeightGrapher::DB::Result::AuthToken |
||||
|
||||
=cut |
||||
|
||||
use strict; |
||||
use warnings; |
||||
|
||||
use base 'DBIx::Class::Core'; |
||||
|
||||
=head1 COMPONENTS LOADED |
||||
|
||||
=over 4 |
||||
|
||||
=item * L<DBIx::Class::InflateColumn::DateTime> |
||||
|
||||
=item * L<DBIx::Class::InflateColumn::Serializer> |
||||
|
||||
=back |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->load_components("InflateColumn::DateTime", "InflateColumn::Serializer"); |
||||
|
||||
=head1 TABLE: C<auth_token> |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->table("auth_token"); |
||||
|
||||
=head1 ACCESSORS |
||||
|
||||
=head2 id |
||||
|
||||
data_type: 'integer' |
||||
is_auto_increment: 1 |
||||
is_nullable: 0 |
||||
sequence: 'auth_token_id_seq' |
||||
|
||||
=head2 person_id |
||||
|
||||
data_type: 'integer' |
||||
is_foreign_key: 1 |
||||
is_nullable: 0 |
||||
|
||||
=head2 scope |
||||
|
||||
data_type: 'text' |
||||
is_nullable: 0 |
||||
|
||||
=head2 token |
||||
|
||||
data_type: 'text' |
||||
is_nullable: 0 |
||||
|
||||
=head2 created_at |
||||
|
||||
data_type: 'timestamp with time zone' |
||||
default_value: current_timestamp |
||||
is_nullable: 0 |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->add_columns( |
||||
"id", |
||||
{ |
||||
data_type => "integer", |
||||
is_auto_increment => 1, |
||||
is_nullable => 0, |
||||
sequence => "auth_token_id_seq", |
||||
}, |
||||
"person_id", |
||||
{ data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, |
||||
"scope", |
||||
{ data_type => "text", is_nullable => 0 }, |
||||
"token", |
||||
{ data_type => "text", is_nullable => 0 }, |
||||
"created_at", |
||||
{ |
||||
data_type => "timestamp with time zone", |
||||
default_value => \"current_timestamp", |
||||
is_nullable => 0, |
||||
}, |
||||
); |
||||
|
||||
=head1 PRIMARY KEY |
||||
|
||||
=over 4 |
||||
|
||||
=item * L</id> |
||||
|
||||
=back |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->set_primary_key("id"); |
||||
|
||||
=head1 RELATIONS |
||||
|
||||
=head2 person |
||||
|
||||
Type: belongs_to |
||||
|
||||
Related object: L<WeightGrapher::DB::Result::Person> |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->belongs_to( |
||||
"person", |
||||
"WeightGrapher::DB::Result::Person", |
||||
{ id => "person_id" }, |
||||
{ is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, |
||||
); |
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-08-29 23:53:08 |
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:BYnapLoZXU3d6DbiJpsdkA |
||||
|
||||
|
||||
# You can replace this text with custom code or comments, and it will be preserved on regeneration |
||||
1; |
||||
@ -0,0 +1,233 @@ |
||||
use utf8; |
||||
package WeightGrapher::DB::Result::Person; |
||||
|
||||
# Created by DBIx::Class::Schema::Loader |
||||
# DO NOT MODIFY THE FIRST PART OF THIS FILE |
||||
|
||||
=head1 NAME |
||||
|
||||
WeightGrapher::DB::Result::Person |
||||
|
||||
=cut |
||||
|
||||
use strict; |
||||
use warnings; |
||||
|
||||
use base 'DBIx::Class::Core'; |
||||
|
||||
=head1 COMPONENTS LOADED |
||||
|
||||
=over 4 |
||||
|
||||
=item * L<DBIx::Class::InflateColumn::DateTime> |
||||
|
||||
=item * L<DBIx::Class::InflateColumn::Serializer> |
||||
|
||||
=back |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->load_components("InflateColumn::DateTime", "InflateColumn::Serializer"); |
||||
|
||||
=head1 TABLE: C<person> |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->table("person"); |
||||
|
||||
=head1 ACCESSORS |
||||
|
||||
=head2 id |
||||
|
||||
data_type: 'integer' |
||||
is_auto_increment: 1 |
||||
is_nullable: 0 |
||||
sequence: 'person_id_seq' |
||||
|
||||
=head2 name |
||||
|
||||
data_type: 'text' |
||||
is_nullable: 0 |
||||
|
||||
=head2 email |
||||
|
||||
data_type: 'citext' |
||||
is_nullable: 0 |
||||
|
||||
=head2 is_enabled |
||||
|
||||
data_type: 'boolean' |
||||
default_value: true |
||||
is_nullable: 0 |
||||
|
||||
=head2 is_admin |
||||
|
||||
data_type: 'boolean' |
||||
default_value: false |
||||
is_nullable: 0 |
||||
|
||||
=head2 created_at |
||||
|
||||
data_type: 'timestamp with time zone' |
||||
default_value: current_timestamp |
||||
is_nullable: 0 |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->add_columns( |
||||
"id", |
||||
{ |
||||
data_type => "integer", |
||||
is_auto_increment => 1, |
||||
is_nullable => 0, |
||||
sequence => "person_id_seq", |
||||
}, |
||||
"name", |
||||
{ data_type => "text", is_nullable => 0 }, |
||||
"email", |
||||
{ data_type => "citext", is_nullable => 0 }, |
||||
"is_enabled", |
||||
{ data_type => "boolean", default_value => \"true", is_nullable => 0 }, |
||||
"is_admin", |
||||
{ data_type => "boolean", default_value => \"false", is_nullable => 0 }, |
||||
"created_at", |
||||
{ |
||||
data_type => "timestamp with time zone", |
||||
default_value => \"current_timestamp", |
||||
is_nullable => 0, |
||||
}, |
||||
); |
||||
|
||||
=head1 PRIMARY KEY |
||||
|
||||
=over 4 |
||||
|
||||
=item * L</id> |
||||
|
||||
=back |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->set_primary_key("id"); |
||||
|
||||
=head1 UNIQUE CONSTRAINTS |
||||
|
||||
=head2 C<person_email_key> |
||||
|
||||
=over 4 |
||||
|
||||
=item * L</email> |
||||
|
||||
=back |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->add_unique_constraint("person_email_key", ["email"]); |
||||
|
||||
=head1 RELATIONS |
||||
|
||||
=head2 auth_password |
||||
|
||||
Type: might_have |
||||
|
||||
Related object: L<WeightGrapher::DB::Result::AuthPassword> |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->might_have( |
||||
"auth_password", |
||||
"WeightGrapher::DB::Result::AuthPassword", |
||||
{ "foreign.person_id" => "self.id" }, |
||||
{ cascade_copy => 0, cascade_delete => 0 }, |
||||
); |
||||
|
||||
=head2 auth_tokens |
||||
|
||||
Type: has_many |
||||
|
||||
Related object: L<WeightGrapher::DB::Result::AuthToken> |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->has_many( |
||||
"auth_tokens", |
||||
"WeightGrapher::DB::Result::AuthToken", |
||||
{ "foreign.person_id" => "self.id" }, |
||||
{ cascade_copy => 0, cascade_delete => 0 }, |
||||
); |
||||
|
||||
=head2 person_settings |
||||
|
||||
Type: has_many |
||||
|
||||
Related object: L<WeightGrapher::DB::Result::PersonSetting> |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->has_many( |
||||
"person_settings", |
||||
"WeightGrapher::DB::Result::PersonSetting", |
||||
{ "foreign.person_id" => "self.id" }, |
||||
{ cascade_copy => 0, cascade_delete => 0 }, |
||||
); |
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-08-29 23:53:08 |
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:I1siWN8RScSHO2w7nsrddg |
||||
|
||||
use Data::GUID; |
||||
|
||||
sub setting { |
||||
my ( $self, $setting, $value ) = @_; |
||||
|
||||
if ( defined $value ) { |
||||
my $rs = $self->find_or_new_related( 'person_settings', { name => $setting } ); |
||||
$rs->value( ref $value ? $value : { value => $value } ); |
||||
|
||||
$rs->update if $rs->in_storage; |
||||
$rs->insert unless $rs->in_storage; |
||||
|
||||
return $value; |
||||
} else { |
||||
my $result = $self->find_related('person_settings', { name => $setting }); |
||||
return undef unless $result; |
||||
return $self->_get_setting_value($result); |
||||
} |
||||
} |
||||
|
||||
sub _get_setting_value { |
||||
my ( $self, $setting ) = @_; |
||||
|
||||
if ( ref $setting->value eq 'HASH' and keys %{$setting->value} == 1 and exists $setting->value->{value} ) { |
||||
return $setting->value->{value}; |
||||
} |
||||
|
||||
return $setting->value; |
||||
} |
||||
|
||||
sub get_settings { |
||||
my ( $self ) = @_; |
||||
|
||||
my $return = {}; |
||||
|
||||
foreach my $setting ( $self->search_related( 'person_settings', {} )->all ) { |
||||
$return->{${\($setting->name)}} = $self->_get_setting_value($setting); |
||||
} |
||||
|
||||
return $return; |
||||
} |
||||
|
||||
sub create_auth_token { |
||||
my ( $self, $scope ) = @_; |
||||
|
||||
my $token = Data::GUID->guid_string; |
||||
|
||||
$self->create_related( 'auth_tokens', { |
||||
token => $token, |
||||
scope => $scope, |
||||
}); |
||||
|
||||
return $token; |
||||
} |
||||
|
||||
1; |
||||
@ -0,0 +1,151 @@ |
||||
use utf8; |
||||
package WeightGrapher::DB::Result::PersonSetting; |
||||
|
||||
# Created by DBIx::Class::Schema::Loader |
||||
# DO NOT MODIFY THE FIRST PART OF THIS FILE |
||||
|
||||
=head1 NAME |
||||
|
||||
WeightGrapher::DB::Result::PersonSetting |
||||
|
||||
=cut |
||||
|
||||
use strict; |
||||
use warnings; |
||||
|
||||
use base 'DBIx::Class::Core'; |
||||
|
||||
=head1 COMPONENTS LOADED |
||||
|
||||
=over 4 |
||||
|
||||
=item * L<DBIx::Class::InflateColumn::DateTime> |
||||
|
||||
=item * L<DBIx::Class::InflateColumn::Serializer> |
||||
|
||||
=back |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->load_components("InflateColumn::DateTime", "InflateColumn::Serializer"); |
||||
|
||||
=head1 TABLE: C<person_settings> |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->table("person_settings"); |
||||
|
||||
=head1 ACCESSORS |
||||
|
||||
=head2 id |
||||
|
||||
data_type: 'integer' |
||||
is_auto_increment: 1 |
||||
is_nullable: 0 |
||||
sequence: 'person_settings_id_seq' |
||||
|
||||
=head2 person_id |
||||
|
||||
data_type: 'integer' |
||||
is_foreign_key: 1 |
||||
is_nullable: 0 |
||||
|
||||
=head2 name |
||||
|
||||
data_type: 'text' |
||||
is_nullable: 0 |
||||
|
||||
=head2 value |
||||
|
||||
data_type: 'json' |
||||
default_value: '{}' |
||||
is_nullable: 0 |
||||
serializer_class: 'JSON' |
||||
|
||||
=head2 created_at |
||||
|
||||
data_type: 'timestamp with time zone' |
||||
default_value: current_timestamp |
||||
is_nullable: 0 |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->add_columns( |
||||
"id", |
||||
{ |
||||
data_type => "integer", |
||||
is_auto_increment => 1, |
||||
is_nullable => 0, |
||||
sequence => "person_settings_id_seq", |
||||
}, |
||||
"person_id", |
||||
{ data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, |
||||
"name", |
||||
{ data_type => "text", is_nullable => 0 }, |
||||
"value", |
||||
{ |
||||
data_type => "json", |
||||
default_value => "{}", |
||||
is_nullable => 0, |
||||
serializer_class => "JSON", |
||||
}, |
||||
"created_at", |
||||
{ |
||||
data_type => "timestamp with time zone", |
||||
default_value => \"current_timestamp", |
||||
is_nullable => 0, |
||||
}, |
||||
); |
||||
|
||||
=head1 PRIMARY KEY |
||||
|
||||
=over 4 |
||||
|
||||
=item * L</id> |
||||
|
||||
=back |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->set_primary_key("id"); |
||||
|
||||
=head1 UNIQUE CONSTRAINTS |
||||
|
||||
=head2 C<unq_person_id_name> |
||||
|
||||
=over 4 |
||||
|
||||
=item * L</person_id> |
||||
|
||||
=item * L</name> |
||||
|
||||
=back |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->add_unique_constraint("unq_person_id_name", ["person_id", "name"]); |
||||
|
||||
=head1 RELATIONS |
||||
|
||||
=head2 person |
||||
|
||||
Type: belongs_to |
||||
|
||||
Related object: L<WeightGrapher::DB::Result::Person> |
||||
|
||||
=cut |
||||
|
||||
__PACKAGE__->belongs_to( |
||||
"person", |
||||
"WeightGrapher::DB::Result::Person", |
||||
{ id => "person_id" }, |
||||
{ is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, |
||||
); |
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-08-29 23:53:08 |
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:lgwAMRyofSiVVgh5M+B+LQ |
||||
|
||||
|
||||
# You can replace this text with custom code or comments, and it will be preserved on regeneration |
||||
1; |
||||
Loading…
Reference in new issue