Help wanted #23
|
@ -13,6 +13,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
.dockerignore = .dockerignore
|
.dockerignore = .dockerignore
|
||||||
database\12-add-real-name.sql = database\12-add-real-name.sql
|
database\12-add-real-name.sql = database\12-add-real-name.sql
|
||||||
|
database\16-job-listing.sql = database\16-job-listing.sql
|
||||||
JobsJobsJobs\Directory.Build.props = JobsJobsJobs\Directory.Build.props
|
JobsJobsJobs\Directory.Build.props = JobsJobsJobs\Directory.Build.props
|
||||||
Dockerfile = Dockerfile
|
Dockerfile = Dockerfile
|
||||||
database\tables.sql = database\tables.sql
|
database\tables.sql = database\tables.sql
|
||||||
|
|
|
@ -53,7 +53,8 @@ namespace JobsJobsJobs.Server.Areas.Api.Controllers
|
||||||
if (form.Id == "new")
|
if (form.Id == "new")
|
||||||
{
|
{
|
||||||
var story = new Success(await SuccessId.Create(), CurrentCitizenId, _clock.GetCurrentInstant(),
|
var story = new Success(await SuccessId.Create(), CurrentCitizenId, _clock.GetCurrentInstant(),
|
||||||
form.FromHere, string.IsNullOrWhiteSpace(form.Story) ? null : new MarkdownString(form.Story));
|
form.FromHere, "profile",
|
||||||
|
string.IsNullOrWhiteSpace(form.Story) ? null : new MarkdownString(form.Story));
|
||||||
await _db.AddAsync(story);
|
await _db.AddAsync(story);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -20,6 +20,12 @@ namespace JobsJobsJobs.Server.Data
|
||||||
public static readonly ValueConverter<ContinentId, string> ContinentIdConverter =
|
public static readonly ValueConverter<ContinentId, string> ContinentIdConverter =
|
||||||
new(v => v.ToString(), v => ContinentId.Parse(v));
|
new(v => v.ToString(), v => ContinentId.Parse(v));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Job Listing ID converter
|
||||||
|
/// </summary>
|
||||||
|
public static readonly ValueConverter<ListingId, string> ListingIdConverter =
|
||||||
|
new(v => v.ToString(), v => ListingId.Parse(v));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Markdown converter
|
/// Markdown converter
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -18,6 +18,11 @@ namespace JobsJobsJobs.Server.Data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DbSet<Continent> Continents { get; set; } = default!;
|
public DbSet<Continent> Continents { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Job listings
|
||||||
|
/// </summary>
|
||||||
|
public DbSet<Listing> Listings { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Employment profiles
|
/// Employment profiles
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -66,6 +71,33 @@ namespace JobsJobsJobs.Server.Data
|
||||||
m.Property(e => e.Name).HasColumnName("name").IsRequired().HasMaxLength(255);
|
m.Property(e => e.Name).HasColumnName("name").IsRequired().HasMaxLength(255);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity<Listing>(m =>
|
||||||
|
{
|
||||||
|
m.ToTable("listing", "jjj").HasKey(e => e.Id);
|
||||||
|
m.Property(e => e.Id).HasColumnName("id").IsRequired().HasMaxLength(12)
|
||||||
|
.HasConversion(Converters.ListingIdConverter);
|
||||||
|
m.Property(e => e.CitizenId).HasColumnName("citizen_id").IsRequired().HasMaxLength(12)
|
||||||
|
.HasConversion(Converters.CitizenIdConverter);
|
||||||
|
m.Property(e => e.CreatedOn).HasColumnName("created_on").IsRequired();
|
||||||
|
m.Property(e => e.Title).HasColumnName("title").IsRequired().HasMaxLength(100);
|
||||||
|
m.Property(e => e.ContinentId).HasColumnName("continent_id").IsRequired().HasMaxLength(12)
|
||||||
|
.HasConversion(Converters.ContinentIdConverter);
|
||||||
|
m.Property(e => e.Region).HasColumnName("region").IsRequired().HasMaxLength(255);
|
||||||
|
m.Property(e => e.RemoteWork).HasColumnName("remote_work").IsRequired();
|
||||||
|
m.Property(e => e.IsExpired).HasColumnName("expired").IsRequired();
|
||||||
|
m.Property(e => e.UpdatedOn).HasColumnName("updated_on").IsRequired();
|
||||||
|
m.Property(e => e.Text).HasColumnName("listing").IsRequired()
|
||||||
|
.HasConversion(Converters.MarkdownStringConverter);
|
||||||
|
m.Property(e => e.NeededBy).HasColumnName("needed_by");
|
||||||
|
m.Property(e => e.WasFilledHere).HasColumnName("filled_here");
|
||||||
|
m.HasOne(e => e.Citizen)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(e => e.CitizenId);
|
||||||
|
m.HasOne(e => e.Continent)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(e => e.ContinentId);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity<Profile>(m =>
|
modelBuilder.Entity<Profile>(m =>
|
||||||
{
|
{
|
||||||
m.ToTable("profile", "jjj").HasKey(e => e.Id);
|
m.ToTable("profile", "jjj").HasKey(e => e.Id);
|
||||||
|
@ -111,6 +143,7 @@ namespace JobsJobsJobs.Server.Data
|
||||||
.HasConversion(Converters.CitizenIdConverter);
|
.HasConversion(Converters.CitizenIdConverter);
|
||||||
m.Property(e => e.RecordedOn).HasColumnName("recorded_on").IsRequired();
|
m.Property(e => e.RecordedOn).HasColumnName("recorded_on").IsRequired();
|
||||||
m.Property(e => e.FromHere).HasColumnName("from_here").IsRequired();
|
m.Property(e => e.FromHere).HasColumnName("from_here").IsRequired();
|
||||||
|
m.Property(e => e.Source).HasColumnName("source").IsRequired().HasMaxLength(7);
|
||||||
m.Property(e => e.Story).HasColumnName("story")
|
m.Property(e => e.Story).HasColumnName("story")
|
||||||
.HasConversion(Converters.OptionalMarkdownStringConverter);
|
.HasConversion(Converters.OptionalMarkdownStringConverter);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace JobsJobsJobs.Shared
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The ID of a user (a citizen of Gitmo Nation)
|
|
||||||
/// </summary>
|
|
||||||
public record CitizenId(ShortId Id)
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new citizen ID
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A new citizen ID</returns>
|
|
||||||
public static async Task<CitizenId> Create() => new CitizenId(await ShortId.Create());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempt to create a citizen ID from a string
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The prospective ID</param>
|
|
||||||
/// <returns>The citizen ID</returns>
|
|
||||||
/// <exception cref="System.FormatException">If the string is not a valid citizen ID</exception>
|
|
||||||
public static CitizenId Parse(string id) => new CitizenId(ShortId.Parse(id));
|
|
||||||
|
|
||||||
public override string ToString() => Id.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace JobsJobsJobs.Shared
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The ID of a continent
|
|
||||||
/// </summary>
|
|
||||||
public record ContinentId(ShortId Id)
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new continent ID
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A new continent ID</returns>
|
|
||||||
public static async Task<ContinentId> Create() => new ContinentId(await ShortId.Create());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempt to create a continent ID from a string
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The prospective ID</param>
|
|
||||||
/// <returns>The continent ID</returns>
|
|
||||||
/// <exception cref="System.FormatException">If the string is not a valid continent ID</exception>
|
|
||||||
public static ContinentId Parse(string id) => new ContinentId(ShortId.Parse(id));
|
|
||||||
|
|
||||||
public override string ToString() => Id.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
148
src/JobsJobsJobs/Shared/Domain/Ids.cs
Normal file
148
src/JobsJobsJobs/Shared/Domain/Ids.cs
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
using System;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace JobsJobsJobs.Shared
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A short ID
|
||||||
|
/// </summary>
|
||||||
|
public record ShortId(string Id)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Validate the format of the short ID
|
||||||
|
/// </summary>
|
||||||
|
private static readonly Regex ValidShortId =
|
||||||
|
new Regex("^[a-z0-9_-]{12}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new short ID
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A new short ID</returns>
|
||||||
|
public static async Task<ShortId> Create() => new ShortId(await Nanoid.Nanoid.GenerateAsync(size: 12));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Try to parse a string of text into a short ID
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The text of the prospective short ID</param>
|
||||||
|
/// <returns>The short ID</returns>
|
||||||
|
/// <exception cref="FormatException">If the format is not valid</exception>
|
||||||
|
public static ShortId Parse(string text)
|
||||||
|
{
|
||||||
|
if (text.Length == 12 && ValidShortId.IsMatch(text)) return new ShortId(text);
|
||||||
|
throw new FormatException($"The string {text} is not a valid short ID");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of a user (a citizen of Gitmo Nation)
|
||||||
|
/// </summary>
|
||||||
|
public record CitizenId(ShortId Id)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new citizen ID
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A new citizen ID</returns>
|
||||||
|
public static async Task<CitizenId> Create() => new CitizenId(await ShortId.Create());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempt to create a citizen ID from a string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The prospective ID</param>
|
||||||
|
/// <returns>The citizen ID</returns>
|
||||||
|
/// <exception cref="System.FormatException">If the string is not a valid citizen ID</exception>
|
||||||
|
public static CitizenId Parse(string id) => new(ShortId.Parse(id));
|
||||||
|
|
||||||
|
public override string ToString() => Id.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of a continent
|
||||||
|
/// </summary>
|
||||||
|
public record ContinentId(ShortId Id)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new continent ID
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A new continent ID</returns>
|
||||||
|
public static async Task<ContinentId> Create() => new ContinentId(await ShortId.Create());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempt to create a continent ID from a string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The prospective ID</param>
|
||||||
|
/// <returns>The continent ID</returns>
|
||||||
|
/// <exception cref="System.FormatException">If the string is not a valid continent ID</exception>
|
||||||
|
public static ContinentId Parse(string id) => new(ShortId.Parse(id));
|
||||||
|
|
||||||
|
public override string ToString() => Id.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of a job listing
|
||||||
|
/// </summary>
|
||||||
|
public record ListingId(ShortId Id)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new job listing ID
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A new job listing ID</returns>
|
||||||
|
public static async Task<ListingId> Create() => new ListingId(await ShortId.Create());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempt to create a job listing ID from a string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The prospective ID</param>
|
||||||
|
/// <returns>The job listing ID</returns>
|
||||||
|
/// <exception cref="System.FormatException">If the string is not a valid job listing ID</exception>
|
||||||
|
public static ListingId Parse(string id) => new(ShortId.Parse(id));
|
||||||
|
|
||||||
|
public override string ToString() => Id.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of a skill
|
||||||
|
/// </summary>
|
||||||
|
public record SkillId(ShortId Id)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new skill ID
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A new skill ID</returns>
|
||||||
|
public static async Task<SkillId> Create() => new SkillId(await ShortId.Create());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempt to create a skill ID from a string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The prospective ID</param>
|
||||||
|
/// <returns>The skill ID</returns>
|
||||||
|
/// <exception cref="System.FormatException">If the string is not a valid skill ID</exception>
|
||||||
|
public static SkillId Parse(string id) => new(ShortId.Parse(id));
|
||||||
|
|
||||||
|
public override string ToString() => Id.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of a success report
|
||||||
|
/// </summary>
|
||||||
|
public record SuccessId(ShortId Id)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new success report ID
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A new success report ID</returns>
|
||||||
|
public static async Task<SuccessId> Create() => new SuccessId(await ShortId.Create());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempt to create a success report ID from a string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The prospective ID</param>
|
||||||
|
/// <returns>The success report ID</returns>
|
||||||
|
/// <exception cref="System.FormatException">If the string is not a valid success report ID</exception>
|
||||||
|
public static SuccessId Parse(string id) => new(ShortId.Parse(id));
|
||||||
|
|
||||||
|
public override string ToString() => Id.ToString();
|
||||||
|
}
|
||||||
|
}
|
32
src/JobsJobsJobs/Shared/Domain/Listing.cs
Normal file
32
src/JobsJobsJobs/Shared/Domain/Listing.cs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace JobsJobsJobs.Shared
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A job listing
|
||||||
|
/// </summary>
|
||||||
|
public record Listing(
|
||||||
|
ListingId Id,
|
||||||
|
CitizenId CitizenId,
|
||||||
|
DateTime CreatedOn,
|
||||||
|
string Title,
|
||||||
|
ContinentId ContinentId,
|
||||||
|
string Region,
|
||||||
|
bool RemoteWork,
|
||||||
|
bool IsExpired,
|
||||||
|
DateTime UpdatedOn,
|
||||||
|
MarkdownString Text,
|
||||||
|
DateTime? NeededBy,
|
||||||
|
bool? WasFilledHere)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Navigation property for the citizen who created the job listing
|
||||||
|
/// </summary>
|
||||||
|
public Citizen? Citizen { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Navigation property for the continent
|
||||||
|
/// </summary>
|
||||||
|
public Continent? Continent { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,38 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace JobsJobsJobs.Shared
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A short ID
|
|
||||||
/// </summary>
|
|
||||||
public record ShortId(string Id)
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Validate the format of the short ID
|
|
||||||
/// </summary>
|
|
||||||
private static readonly Regex ValidShortId =
|
|
||||||
new Regex("^[a-z0-9_-]{12}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new short ID
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A new short ID</returns>
|
|
||||||
public static async Task<ShortId> Create() => new ShortId(await Nanoid.Nanoid.GenerateAsync(size: 12));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Try to parse a string of text into a short ID
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text">The text of the prospective short ID</param>
|
|
||||||
/// <returns>The short ID</returns>
|
|
||||||
/// <exception cref="FormatException">If the format is not valid</exception>
|
|
||||||
public static ShortId Parse(string text)
|
|
||||||
{
|
|
||||||
if (text.Length == 12 && ValidShortId.IsMatch(text)) return new ShortId(text);
|
|
||||||
throw new FormatException($"The string {text} is not a valid short ID");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString() => Id;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace JobsJobsJobs.Shared
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The ID of a skill
|
|
||||||
/// </summary>
|
|
||||||
public record SkillId(ShortId Id)
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new skill ID
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A new skill ID</returns>
|
|
||||||
public static async Task<SkillId> Create() => new SkillId(await ShortId.Create());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempt to create a skill ID from a string
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The prospective ID</param>
|
|
||||||
/// <returns>The skill ID</returns>
|
|
||||||
/// <exception cref="System.FormatException">If the string is not a valid skill ID</exception>
|
|
||||||
public static SkillId Parse(string id) => new SkillId(ShortId.Parse(id));
|
|
||||||
|
|
||||||
public override string ToString() => Id.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -10,5 +10,6 @@ namespace JobsJobsJobs.Shared
|
||||||
CitizenId CitizenId,
|
CitizenId CitizenId,
|
||||||
Instant RecordedOn,
|
Instant RecordedOn,
|
||||||
bool FromHere,
|
bool FromHere,
|
||||||
|
string Source,
|
||||||
MarkdownString? Story);
|
MarkdownString? Story);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace JobsJobsJobs.Shared
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The ID of a success report
|
|
||||||
/// </summary>
|
|
||||||
public record SuccessId(ShortId Id)
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new success report ID
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A new success report ID</returns>
|
|
||||||
public static async Task<SuccessId> Create() => new SuccessId(await ShortId.Create());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempt to create a success report ID from a string
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The prospective ID</param>
|
|
||||||
/// <returns>The success report ID</returns>
|
|
||||||
/// <exception cref="System.FormatException">If the string is not a valid success report ID</exception>
|
|
||||||
public static SuccessId Parse(string id) => new SuccessId(ShortId.Parse(id));
|
|
||||||
|
|
||||||
public override string ToString() => Id.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
56
src/database/16-job-listing.sql
Normal file
56
src/database/16-job-listing.sql
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
|
||||||
|
-- Add job listing table
|
||||||
|
|
||||||
|
CREATE TABLE jjj.job_listing (
|
||||||
|
id VARCHAR(12) NOT NULL,
|
||||||
|
citizen_id VARCHAR(12) NOT NULL,
|
||||||
|
created_on TIMESTAMP NOT NULL,
|
||||||
|
title VARCHAR(100) NOT NULL,
|
||||||
|
continent_id VARCHAR(12) NOT NULL,
|
||||||
|
region VARCHAR(255) NOT NULL,
|
||||||
|
remote_work BOOLEAN NOT NULL,
|
||||||
|
expired BOOLEAN NOT NULL,
|
||||||
|
updated_on TIMESTAMP NOT NULL,
|
||||||
|
listing TEXT NOT NULL,
|
||||||
|
needed_by DATE,
|
||||||
|
filled_here BOOLEAN,
|
||||||
|
CONSTRAINT pk_job_listing PRIMARY KEY (id),
|
||||||
|
CONSTRAINT fk_listing_citizen FOREIGN KEY (citizen_id) REFERENCES jjj.citizen (id),
|
||||||
|
CONSTRAINT fk_listing_continent FOREIGN KEY (continent_id) REFERENCES jjj.continent (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE jjj.job_listing IS 'Job Listings';
|
||||||
|
COMMENT ON COLUMN jjj.job_listing.id
|
||||||
|
IS 'A unique identifier for a job listing';
|
||||||
|
COMMENT ON COLUMN jjj.job_listing.created_on
|
||||||
|
IS 'The date/time a job listing was created';
|
||||||
|
COMMENT ON COLUMN jjj.job_listing.title
|
||||||
|
IS 'The title of the job listing';
|
||||||
|
COMMENT ON COLUMN jjj.job_listing.continent_id
|
||||||
|
IS 'The ID of the continent on which this job is based';
|
||||||
|
COMMENT ON COLUMN jjj.job_listing.region
|
||||||
|
IS 'The region in which this job is based';
|
||||||
|
COMMENT ON COLUMN jjj.job_listing.remote_work
|
||||||
|
IS 'Whether this job is a remote job';
|
||||||
|
COMMENT ON COLUMN jjj.job_listing.expired
|
||||||
|
IS 'Whether this listing is expired';
|
||||||
|
COMMENT ON COLUMN jjj.job_listing.updated_on
|
||||||
|
IS 'The date/time this job listing was last updated';
|
||||||
|
COMMENT ON COLUMN jjj.job_listing.listing
|
||||||
|
IS 'The text of the job listing';
|
||||||
|
COMMENT ON COLUMN jjj.job_listing.needed_by
|
||||||
|
IS 'The date by which this job needs to be filled';
|
||||||
|
COMMENT ON COLUMN jjj.job_listing.filled_here
|
||||||
|
IS 'Whether this job listing was filled because it appeared here';
|
||||||
|
|
||||||
|
CREATE INDEX idx_listing_citizen ON jjj.job_listing (citizen_id);
|
||||||
|
CREATE INDEX idx_listing_continent ON jjj.job_listing (continent_id);
|
||||||
|
COMMENT ON INDEX jjj.idx_listing_citizen IS 'FK index';
|
||||||
|
COMMENT ON INDEX jjj.idx_listing_continent IS 'FK index';
|
||||||
|
|
||||||
|
-- Add source column to success story
|
||||||
|
|
||||||
|
ALTER TABLE jjj.success ADD COLUMN source VARCHAR(7) NOT NULL DEFAULT 'profile';
|
||||||
|
ALTER TABLE jjj.success ADD CONSTRAINT ck_source CHECK (source IN ('profile', 'listing'));
|
||||||
|
COMMENT ON COLUMN jjj.success.source
|
||||||
|
IS 'The source of the success story (profile or listing)';
|
Loading…
Reference in New Issue
Block a user