| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- using Invercargill;
- using Invercargill.DataStructures;
- using Invercargill.Expressions;
- using InvercargillSql.Orm;
- using Inversion;
- using ClankerSaddle.Data;
- namespace ClankerSaddle.Services {
- /** Valid values of {@link ProjectLink.relationship}. */
- public const string LINK_CO_DEVELOPED = "co-developed";
- public const string LINK_REFERENCE = "reference";
- /**
- * Project storage: CRUD over `projects`, the directed
- * co-developed/reference link graph in `project_links`, and the
- * project's LLM-authored notes.
- */
- public class ProjectService : Object {
- private OrmSession db = inject<OrmSession>();
- /** Inserts a project; `summary` may be empty. */
- public async Project create_project(string name, string git_url,
- string default_branch, string? summary) throws Error {
- var project = new Project() {
- name = name,
- git_url = git_url,
- default_branch = default_branch.length > 0 ? default_branch : "main",
- summary = summary != null && summary.length > 0 ? summary : null,
- created_at = new DateTime.now_local()
- };
- yield db.insert_async<Project>(project);
- return project;
- }
- /** Loads the project identified by `id`, or null. */
- public async Project? get_project(int64 id) throws Error {
- return yield db.query<Project>()
- .where(expr("id == $0", elem<int64?>(id)))
- .first_async();
- }
- /** Lists every project ordered by name. */
- public async ImmutableLot<Project> list_projects() throws Error {
- return yield db.query<Project>()
- .order_by(expr("name"))
- .materialise_async();
- }
- /**
- * Saves the editable fields of the project identified by `id`;
- * empty arguments keep their current values. Returns the saved
- * project, or null when no such project exists.
- */
- public async Project? update_project(int64 id, string? name, string? git_url,
- string? default_branch, string? summary) throws Error {
- var project = yield get_project(id);
- if (project == null) {
- return null;
- }
- if (name != null && name.length > 0) {
- project.name = name;
- }
- if (git_url != null && git_url.length > 0) {
- project.git_url = git_url;
- }
- if (default_branch != null && default_branch.length > 0) {
- project.default_branch = default_branch;
- }
- if (summary != null) {
- project.summary = summary.length > 0 ? summary : null;
- }
- yield db.update_async<Project>(project);
- return project;
- }
- /**
- * Links `linked_id` to `parent_id` with `relationship`
- * ('co-developed' or 'reference'); self-links and duplicates are
- * rejected.
- */
- public async ProjectLink add_link(int64 parent_id, int64 linked_id,
- string relationship) throws Error {
- if (relationship != LINK_CO_DEVELOPED && relationship != LINK_REFERENCE) {
- throw new Error(Quark.from_string("clanker-saddle"), 1,
- @"Relationship must be '$(LINK_CO_DEVELOPED)' or '$(LINK_REFERENCE)'");
- }
- if (parent_id == linked_id) {
- throw new Error(Quark.from_string("clanker-saddle"), 2,
- "A project cannot be linked to itself");
- }
- var parent = yield get_project(parent_id);
- var linked = yield get_project(linked_id);
- if (parent == null || linked == null) {
- throw new Error(Quark.from_string("clanker-saddle"), 3,
- "Both projects must exist");
- }
- var existing = yield db.query<ProjectLink>()
- .where(expr("parent_project_id == $0 && linked_project_id == $1",
- elem<int64?>(parent_id), elem<int64?>(linked_id)))
- .materialise_async();
- if (existing.length > 0) {
- throw new Error(Quark.from_string("clanker-saddle"), 4,
- "Those projects are already linked");
- }
- var link = new ProjectLink() {
- parent_project_id = parent_id,
- linked_project_id = linked_id,
- relationship = relationship
- };
- yield db.insert_async<ProjectLink>(link);
- return link;
- }
- /** Deletes the link identified by `id`. */
- public async void remove_link(int64 id) throws Error {
- var link = yield db.query<ProjectLink>()
- .where(expr("id == $0", elem<int64?>(id)))
- .first_async();
- if (link != null) {
- yield db.delete_async<ProjectLink>((!)link);
- }
- }
- /** Lists every link whose parent is `project_id`. */
- public async ImmutableLot<ProjectLink> list_links(int64 project_id) throws Error {
- return yield db.query<ProjectLink>()
- .where(expr("parent_project_id == $0", elem<int64?>(project_id)))
- .materialise_async();
- }
- /** Loads the project identified by `name`, or null. */
- public async Project? get_project_by_name(string name) throws Error {
- return yield db.query<Project>()
- .where(expr("name == $0", elem(name)))
- .first_async();
- }
- /**
- * Inserts a project note (LLM-authored via the callback endpoint).
- * `source_task_id` may be 0 (unknown source task).
- */
- public async ProjectNote add_note(int64 project_id, int64 source_task_id,
- string body) throws Error {
- var note = new ProjectNote() {
- project_id = project_id,
- source_task_id = source_task_id,
- body = body,
- created_at = new DateTime.now_local()
- };
- yield db.insert_async<ProjectNote>(note);
- return note;
- }
- /** Loads the note identified by `id`, or null. */
- public async ProjectNote? get_note(int64 id) throws Error {
- return yield db.query<ProjectNote>()
- .where(expr("id == $0", elem<int64?>(id)))
- .first_async();
- }
- /** A project's notes, oldest first. */
- public async ImmutableLot<ProjectNote> list_notes(int64 project_id) throws Error {
- return yield db.query<ProjectNote>()
- .where(expr("project_id == $0", elem<int64?>(project_id)))
- .order_by(expr("id"))
- .materialise_async();
- }
- /** Deletes the note identified by `id`. */
- public async void delete_note(int64 id) throws Error {
- var note = yield get_note(id);
- if (note != null) {
- yield db.delete_async<ProjectNote>((!)note);
- }
- }
- }
- }
|