Skip to content

Commit

Permalink
Add "category add" command.
Browse files Browse the repository at this point in the history
  • Loading branch information
io7m committed Aug 31, 2024
1 parent 993cfbc commit ddb6ab9
Show file tree
Hide file tree
Showing 7 changed files with 402 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package com.io7m.laurel.filemodel;

import com.io7m.jattribute.core.AttributeReadableType;
import com.io7m.laurel.model.LCategory;
import com.io7m.laurel.model.LException;
import com.io7m.laurel.model.LImage;
import com.io7m.laurel.model.LTag;
Expand All @@ -42,6 +43,17 @@ public interface LFileModelType

Flow.Publisher<LFileModelEvent> events();

/**
* Add a category.
*
* @param text The category
*
* @return The operation in progress
*/

CompletableFuture<?> categoryAdd(
LCategory text);

/**
* Add a tag.
*
Expand Down Expand Up @@ -144,4 +156,10 @@ void close()
*/

AttributeReadableType<Optional<String>> redoText();

/**
* @return The current complete list of categories
*/

AttributeReadableType<List<LCategory>> categoryList();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*
* Copyright © 2024 Mark Raynsford <[email protected]> https://www.io7m.com
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/


package com.io7m.laurel.filemodel.internal;

import com.io7m.laurel.model.LCategory;
import org.jooq.DSLContext;

import java.util.List;
import java.util.Properties;

import static com.io7m.laurel.filemodel.internal.Tables.CATEGORIES;

/**
* Add a category.
*/

public final class LCommandCategoryAdd
extends LCommandAbstract<LCategory>
{
private long id;
private String text;

/**
* Add a category.
*/

public LCommandCategoryAdd()
{

}

/**
* Add a category.
*
* @return A command factory
*/

public static LCommandFactoryType<LCategory> provider()
{
return new LCommandFactory<>(
LCommandCategoryAdd.class.getCanonicalName(),
LCommandCategoryAdd::fromProperties
);
}

private static LCommandCategoryAdd fromProperties(
final Properties p)
{
final var c = new LCommandCategoryAdd();
c.id = Long.parseUnsignedLong(p.getProperty("id"));
c.text = p.getProperty("text");
c.setExecuted(true);
return c;
}

private static List<LCategory> listCategories(
final LDatabaseTransactionType transaction)
{
final var context =
transaction.get(DSLContext.class);

return context.select(CATEGORIES.CATEGORY_TEXT)
.from(CATEGORIES)
.orderBy(CATEGORIES.CATEGORY_TEXT.asc())
.stream()
.map(r -> new LCategory(r.get(CATEGORIES.CATEGORY_TEXT)))
.toList();
}

@Override
protected LCommandUndoable onExecute(
final LFileModel model,
final LDatabaseTransactionType transaction,
final LCategory category)
{
final var context =
transaction.get(DSLContext.class);

model.eventWithoutProgress("Adding category '%s'.", category);

final var recOpt =
context.insertInto(CATEGORIES)
.set(CATEGORIES.CATEGORY_TEXT, category.text())
.onDuplicateKeyIgnore()
.returning(CATEGORIES.CATEGORY_ID)
.fetchOptional();

if (recOpt.isEmpty()) {
model.eventWithoutProgress("Category '%s' already existed.", category);
return LCommandUndoable.COMMAND_NOT_UNDOABLE;
}

final var rec = recOpt.get();
this.id = rec.get(CATEGORIES.CATEGORY_ID).longValue();
this.text = category.text();

model.setCategoriesAll(listCategories(transaction));
model.eventWithoutProgress("Category '%s' added.", category);
return LCommandUndoable.COMMAND_UNDOABLE;
}

@Override
protected void onUndo(
final LFileModel model,
final LDatabaseTransactionType transaction)
{
final var context =
transaction.get(DSLContext.class);

model.eventWithoutProgress("Deleting category '%s'.", this.text);

context.deleteFrom(CATEGORIES)
.where(CATEGORIES.CATEGORY_ID.eq(this.id))
.execute();

model.setCategoriesAll(listCategories(transaction));
}

@Override
protected void onRedo(
final LFileModel model,
final LDatabaseTransactionType transaction)
{
final var context =
transaction.get(DSLContext.class);

model.eventWithoutProgress("Adding category '%s'.", this.text);

context.insertInto(CATEGORIES)
.set(CATEGORIES.CATEGORY_ID, this.id)
.set(CATEGORIES.CATEGORY_TEXT, this.text)
.onDuplicateKeyUpdate()
.set(CATEGORIES.CATEGORY_TEXT, this.text)
.execute();

model.setCategoriesAll(listCategories(transaction));
model.eventWithoutProgress("Category '%s' added.", this.text);
}

@Override
public Properties toProperties()
{
final var properties = new Properties();
properties.setProperty("id", Long.toUnsignedString(this.id));
properties.setProperty("text", this.text);
return properties;
}

@Override
public String describe()
{
return "Add category '%s'".formatted(this.text);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.io7m.jmulticlose.core.CloseableCollectionType;
import com.io7m.laurel.filemodel.LFileModelEvent;
import com.io7m.laurel.filemodel.LFileModelType;
import com.io7m.laurel.model.LCategory;
import com.io7m.laurel.model.LException;
import com.io7m.laurel.model.LImage;
import com.io7m.laurel.model.LTag;
Expand Down Expand Up @@ -72,6 +73,7 @@ public final class LFileModel implements LFileModelType
LOG.error("Uncaught attribute exception: ", throwable);
});

private final AttributeType<List<LCategory>> categoriesAll;
private final AttributeType<List<LImage>> imagesAll;
private final AttributeType<List<LTag>> tagsAll;
private final AttributeType<List<LTag>> tagsAssigned;
Expand All @@ -80,17 +82,19 @@ public final class LFileModel implements LFileModelType
private final AttributeType<Optional<LImage>> imageSelected;
private final AttributeType<Optional<String>> redoText;
private final AttributeType<Optional<String>> undoText;
private final CloseableCollectionType<LException> resources;
private final ConcurrentHashMap<String, String> attributes;
private final LDatabaseType database;
private final ReentrantLock commandLock;
private final CloseableCollectionType<LException> resources;
private final SubmissionPublisher<LFileModelEvent> events;

private LFileModel(
final LDatabaseType inDatabase)
{
this.database =
Objects.requireNonNull(inDatabase, "database");
this.categoriesAll =
ATTRIBUTES.create(List.of());
this.tagsAll =
ATTRIBUTES.create(List.of());
this.tagsAssigned =
Expand Down Expand Up @@ -327,6 +331,13 @@ public SubmissionPublisher<LFileModelEvent> events()
return this.events;
}

@Override
public CompletableFuture<?> categoryAdd(
final LCategory text)
{
return this.runCommand(new LCommandCategoryAdd(), text);
}

@Override
public CompletableFuture<?> tagAdd(
final LTag text)
Expand Down Expand Up @@ -582,6 +593,12 @@ public AttributeReadableType<Optional<String>> redoText()
return this.redoText;
}

@Override
public AttributeReadableType<List<LCategory>> categoryList()
{
return this.categoriesAll;
}

private void executeRedo()
throws Exception
{
Expand Down Expand Up @@ -673,4 +690,10 @@ void eventWithoutProgress(
OptionalDouble.empty()
));
}

void setCategoriesAll(
final List<LCategory> categories)
{
this.categoriesAll.set(categories);
}
}
6 changes: 4 additions & 2 deletions com.io7m.laurel.filemodel/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

import com.io7m.laurel.filemodel.internal.LCommandCategoryAdd;
import com.io7m.laurel.filemodel.internal.LCommandFactoryType;
import com.io7m.laurel.filemodel.internal.LCommandImageAdd;
import com.io7m.laurel.filemodel.internal.LCommandImageSelect;
Expand Down Expand Up @@ -45,9 +46,10 @@
requires org.xerial.sqlitejdbc;

provides LCommandFactoryType with
LCommandTagAdd,
LCommandCategoryAdd,
LCommandImageAdd,
LCommandImageSelect;
LCommandImageSelect,
LCommandTagAdd;

exports com.io7m.laurel.filemodel;
exports com.io7m.laurel.filemodel.internal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,49 @@ CREATE TABLE tags (
-- [jooq ignore start]
STRICT
-- [jooq ignore stop]
]]></Statement>

<Comment>
The categories table stores the categories for tags.
</Comment>

<Statement><![CDATA[
CREATE TABLE categories (
category_id INTEGER PRIMARY KEY NOT NULL,
category_text TEXT NOT NULL
-- [jooq ignore start]
,
CONSTRAINT categories_text_unique
UNIQUE (category_text)
-- [jooq ignore stop]
)
-- [jooq ignore start]
STRICT
-- [jooq ignore stop]
]]></Statement>

<Comment>
The tag_categories table associates tags with categories.
</Comment>

<Statement><![CDATA[
CREATE TABLE tag_categories (
tag_tag_id INTEGER NOT NULL,
tag_category_id INTEGER NOT NULL,
CONSTRAINT tag_categories_tag_exists
FOREIGN KEY (tag_tag_id) REFERENCES tags (tag_id),
CONSTRAINT tag_categories_category_exists
FOREIGN KEY (tag_category_id) REFERENCES categories (category_id),
CONSTRAINT tag_categories_primary_key
PRIMARY KEY (tag_tag_id, tag_category_id)
)
-- [jooq ignore start]
STRICT
-- [jooq ignore stop]
]]></Statement>

<Comment>
Expand Down
Loading

0 comments on commit ddb6ab9

Please sign in to comment.