wordstudent

Word learning program
git clone git://git.wimdupont.com/wordstudent.git
Log | Files | Refs | LICENSE

commit 1a2fe81a958a5aec6451f83df071dbaed8e91941
parent 91841e87fd586ed4cbf0a39086310a3045d1351e
Author: Wim Dupont <wim@wimdupont.com>
Date:   Sat, 26 Aug 2023 09:29:26 +0200

switched to swing UI with couchdb init

Diffstat:
Mpom.xml | 14+-------------
Msrc/main/java/com/wimdupont/WordStudentAdvancedApplication.java | 26++++++++++++++++++--------
Asrc/main/java/com/wimdupont/client/Client.java | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/main/java/com/wimdupont/client/DictionaryAPI.java | 44--------------------------------------------
Asrc/main/java/com/wimdupont/client/DictionaryApi.java | 19+++++++++++++++++++
Dsrc/main/java/com/wimdupont/client/model/dto/DefinitionDto.java | 14--------------
Dsrc/main/java/com/wimdupont/client/model/dto/DictionaryDto.java | 16----------------
Dsrc/main/java/com/wimdupont/client/model/dto/MeaningDto.java | 13-------------
Dsrc/main/java/com/wimdupont/client/model/dto/PhoneticDto.java | 11-----------
Dsrc/main/java/com/wimdupont/config/AppConfig.java | 14--------------
Asrc/main/java/com/wimdupont/config/ApplicationProperties.java | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/main/java/com/wimdupont/converter/AntonymConverter.java | 16----------------
Dsrc/main/java/com/wimdupont/converter/DefinitionConverter.java | 31-------------------------------
Dsrc/main/java/com/wimdupont/converter/DictionaryConverter.java | 33---------------------------------
Dsrc/main/java/com/wimdupont/converter/MeaningConverter.java | 24------------------------
Dsrc/main/java/com/wimdupont/converter/PhoneticConverter.java | 16----------------
Dsrc/main/java/com/wimdupont/converter/SynonymConverter.java | 14--------------
Dsrc/main/java/com/wimdupont/converter/WordConverter.java | 27---------------------------
Asrc/main/java/com/wimdupont/model/db/WordCouchDocument.java | 18++++++++++++++++++
Asrc/main/java/com/wimdupont/model/db/WordSelectorResponse.java | 13+++++++++++++
Asrc/main/java/com/wimdupont/model/dto/DefinitionDto.java | 14++++++++++++++
Asrc/main/java/com/wimdupont/model/dto/DictionaryDto.java | 16++++++++++++++++
Asrc/main/java/com/wimdupont/model/dto/MeaningDto.java | 13+++++++++++++
Asrc/main/java/com/wimdupont/model/dto/PhoneticDto.java | 11+++++++++++
Asrc/main/java/com/wimdupont/model/dto/WordDto.java | 12++++++++++++
Dsrc/main/java/com/wimdupont/repository/WordRepository.java | 13-------------
Dsrc/main/java/com/wimdupont/repository/dao/Antonym.java | 74--------------------------------------------------------------------------
Dsrc/main/java/com/wimdupont/repository/dao/Definition.java | 138-------------------------------------------------------------------------------
Dsrc/main/java/com/wimdupont/repository/dao/Dictionary.java | 143-------------------------------------------------------------------------------
Dsrc/main/java/com/wimdupont/repository/dao/Meaning.java | 94-------------------------------------------------------------------------------
Dsrc/main/java/com/wimdupont/repository/dao/Phonetic.java | 81-------------------------------------------------------------------------------
Dsrc/main/java/com/wimdupont/repository/dao/Synonym.java | 70----------------------------------------------------------------------
Dsrc/main/java/com/wimdupont/repository/dao/Word.java | 93-------------------------------------------------------------------------------
Msrc/main/java/com/wimdupont/service/WordFetcher.java | 21+++++++--------------
Msrc/main/java/com/wimdupont/service/WordService.java | 84+++++++++++++++++++++++++++++++------------------------------------------------
Msrc/main/java/com/wimdupont/service/WordTester.java | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Dsrc/main/resources/init.sql | 54------------------------------------------------------
37 files changed, 378 insertions(+), 1156 deletions(-)

diff --git a/pom.xml b/pom.xml @@ -3,11 +3,6 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-parent</artifactId> - <version>3.1.2</version> - </parent> <groupId>com.wimdupont</groupId> <artifactId>WordStudentAdvanced</artifactId> <version>1.0-SNAPSHOT</version> @@ -21,14 +16,7 @@ <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-data-jpa</artifactId> - </dependency> - <dependency> - <groupId>org.mariadb.jdbc</groupId> - <artifactId>mariadb-java-client</artifactId> + <version>2.15.2</version> </dependency> </dependencies> <build> diff --git a/src/main/java/com/wimdupont/WordStudentAdvancedApplication.java b/src/main/java/com/wimdupont/WordStudentAdvancedApplication.java @@ -1,19 +1,29 @@ package com.wimdupont; +import com.wimdupont.client.DictionaryApi; +import com.wimdupont.service.WordFetcher; import com.wimdupont.service.WordService; import com.wimdupont.service.WordTester; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.ApplicationContext; -@SpringBootApplication public class WordStudentAdvancedApplication { + private static final WordService WORD_SERVICE = new WordService(); + private static final WordFetcher WORD_FETCHER = new WordFetcher(); + private static final DictionaryApi DICTIONARY_API = new DictionaryApi(); + public static void main(String[] args) { - ApplicationContext context = SpringApplication.run(WordStudentAdvancedApplication.class, args); - context.getBean(WordService.class).saveNew(); - context.getBean(WordTester.class).process(); - System.exit(0); + + new WordTester(WORD_FETCHER, WORD_SERVICE).process(); +// var words = WORD_FETCHER.fetch(); +// +// words.forEach(word -> { +// var result = DICTIONARY_API.getDictionary(word); +// result.ifPresent(WORD_SERVICE::save); +// }); +// var result = new WordService().findByWord("acumen"); +// +// System.out.println(result.get()); +// System.exit(0); } } diff --git a/src/main/java/com/wimdupont/client/Client.java b/src/main/java/com/wimdupont/client/Client.java @@ -0,0 +1,58 @@ +package com.wimdupont.client; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Map; +import java.util.Optional; + +public class Client { + + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + private static final Map<String, String> POST_HEADER_MAP = Map.of("Content-type", "application/json"); + + public static <T> Optional<T> get(String url, Class<T> responseClazz) { + try { + HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + StringBuilder stringBuilder = new StringBuilder(); + for (String line = bufferedReader.readLine(); line != null; line = bufferedReader.readLine()) { + stringBuilder.append(line); + } + return Optional.of(OBJECT_MAPPER.readValue(stringBuilder.toString(), responseClazz)); + } catch (Exception e) { + System.out.println(e.getMessage()); + return Optional.empty(); + } + } + + public static <T> Optional<T> post(String url, Class<T> responseClazz, String body) { + try { + HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); + connection.setRequestMethod("POST"); + POST_HEADER_MAP.forEach(connection::setRequestProperty); + connection.setDoOutput(true); + OutputStream outStream = connection.getOutputStream(); + OutputStreamWriter outStreamWriter = new OutputStreamWriter(outStream, "UTF-8"); + outStreamWriter.write(body); + outStreamWriter.flush(); + outStreamWriter.close(); + outStream.close(); + + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + StringBuilder stringBuilder = new StringBuilder(); + for (String line = bufferedReader.readLine(); line != null; line = bufferedReader.readLine()) { + stringBuilder.append(line); + } + return Optional.of(OBJECT_MAPPER.readValue(stringBuilder.toString(), responseClazz)); + } catch (Exception e) { + System.out.println(e.getMessage()); + return Optional.empty(); + } + } +} diff --git a/src/main/java/com/wimdupont/client/DictionaryAPI.java b/src/main/java/com/wimdupont/client/DictionaryAPI.java @@ -1,44 +0,0 @@ -package com.wimdupont.client; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.wimdupont.client.model.dto.DictionaryDto; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.net.URL; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -@Component -public class DictionaryAPI { - - private static final String AFFIRMATION_URL = "https://api.dictionaryapi.dev/api/v2/entries/en/"; - private static final Logger LOGGER = LoggerFactory.getLogger(DictionaryAPI.class); - private final ObjectMapper objectMapper; - - public DictionaryAPI(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - } - - public List<DictionaryDto> getAffirmation(String word) { - try { - URL url = new URL(AFFIRMATION_URL + word); - URLConnection connection = url.openConnection(); - BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); - StringBuilder sbuilder = new StringBuilder(); - String aux; - while ((aux = in.readLine()) != null) { - sbuilder.append(aux); - } - return Arrays.asList(objectMapper.readValue(sbuilder.toString(), DictionaryDto[].class)); - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - return new ArrayList<>(); - } - } -} diff --git a/src/main/java/com/wimdupont/client/DictionaryApi.java b/src/main/java/com/wimdupont/client/DictionaryApi.java @@ -0,0 +1,19 @@ +package com.wimdupont.client; + +import com.wimdupont.config.ApplicationProperties; +import com.wimdupont.model.dto.DictionaryDto; +import com.wimdupont.model.dto.WordDto; + +import java.util.Arrays; +import java.util.Optional; + +public class DictionaryApi { + + private final ApplicationProperties applicationProperties = ApplicationProperties.getInstance(); + + public Optional<WordDto> getDictionary(String word) { + return Client.get(applicationProperties.getDictionaryClientUrl() + word, DictionaryDto[].class) + .map(Arrays::asList) + .map(f -> new WordDto(word, f)); + } +} diff --git a/src/main/java/com/wimdupont/client/model/dto/DefinitionDto.java b/src/main/java/com/wimdupont/client/model/dto/DefinitionDto.java @@ -1,14 +0,0 @@ -package com.wimdupont.client.model.dto; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record DefinitionDto( - String definition, - String example, - List<String> synonyms, - List<String> antonyms -) { -} diff --git a/src/main/java/com/wimdupont/client/model/dto/DictionaryDto.java b/src/main/java/com/wimdupont/client/model/dto/DictionaryDto.java @@ -1,16 +0,0 @@ -package com.wimdupont.client.model.dto; - - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record DictionaryDto( - String word, - String phonetic, - List<PhoneticDto> phonetics, - String origin, - List<MeaningDto> meanings -) { -} diff --git a/src/main/java/com/wimdupont/client/model/dto/MeaningDto.java b/src/main/java/com/wimdupont/client/model/dto/MeaningDto.java @@ -1,13 +0,0 @@ -package com.wimdupont.client.model.dto; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record MeaningDto( - String partOfSpeech, - List<DefinitionDto> definitions -) { - -} diff --git a/src/main/java/com/wimdupont/client/model/dto/PhoneticDto.java b/src/main/java/com/wimdupont/client/model/dto/PhoneticDto.java @@ -1,11 +0,0 @@ -package com.wimdupont.client.model.dto; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public record PhoneticDto( - String text, - String audio -) { -} - diff --git a/src/main/java/com/wimdupont/config/AppConfig.java b/src/main/java/com/wimdupont/config/AppConfig.java @@ -1,14 +0,0 @@ -package com.wimdupont.config; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class AppConfig { - - @Bean - public ObjectMapper objectMapper() { - return new ObjectMapper(); - } -} diff --git a/src/main/java/com/wimdupont/config/ApplicationProperties.java b/src/main/java/com/wimdupont/config/ApplicationProperties.java @@ -0,0 +1,57 @@ +package com.wimdupont.config; + +import java.io.IOException; +import java.io.InputStream; +import java.util.MissingResourceException; +import java.util.Properties; + +public class ApplicationProperties { + + private static ApplicationProperties instance; + private final String couchdbUrl; + private final String dictionaryClientUrl; + private final String wordCsvDir; + + public String getDictionaryClientUrl() { + return dictionaryClientUrl; + } + + public String getCouchdbUrl() { + return couchdbUrl; + } + + public String getWordCsvDir() { + return wordCsvDir; + } + + private ApplicationProperties() { + Properties properties = loadProperties(); + couchdbUrl = properties.getProperty("couchdb.connection-url"); + dictionaryClientUrl = properties.getProperty("dictionary.client.connection-url"); + wordCsvDir = properties.getProperty("csv.dir"); + if (couchdbUrl == null | dictionaryClientUrl == null | wordCsvDir == null) + throw new RuntimeException("Properties missing."); + } + + public static ApplicationProperties getInstance() { + if (instance == null) { + instance = new ApplicationProperties(); + } + + return instance; + } + + private Properties loadProperties() { + final Properties properties = new Properties(); + InputStream inputStream = getClass().getResourceAsStream("/application.properties"); + try { + if (inputStream == null) { + throw new IOException(); + } + properties.load(inputStream); + } catch (IOException e) { + throw new MissingResourceException("Missing application properties", Properties.class.getSimpleName(), "application.properties"); + } + return properties; + } +} diff --git a/src/main/java/com/wimdupont/converter/AntonymConverter.java b/src/main/java/com/wimdupont/converter/AntonymConverter.java @@ -1,16 +0,0 @@ -package com.wimdupont.converter; - - -import com.wimdupont.repository.dao.Antonym; -import org.springframework.stereotype.Component; - -@Component -public class AntonymConverter { - - public Antonym convert(String relatedWord) { - return Antonym.Builder.newBuilder() - .word(relatedWord) - .build(); - } - -} diff --git a/src/main/java/com/wimdupont/converter/DefinitionConverter.java b/src/main/java/com/wimdupont/converter/DefinitionConverter.java @@ -1,31 +0,0 @@ -package com.wimdupont.converter; - -import com.wimdupont.client.model.dto.DefinitionDto; -import com.wimdupont.repository.dao.Definition; -import org.springframework.stereotype.Component; - -@Component -public class DefinitionConverter { - - private final SynonymConverter synonymConverter; - private final AntonymConverter antonymConverter; - - public DefinitionConverter(SynonymConverter synonymConverter, - AntonymConverter antonymConverter) { - this.synonymConverter = synonymConverter; - this.antonymConverter = antonymConverter; - } - - public Definition convert(DefinitionDto definitionDto) { - return Definition.Builder.newBuilder() - .definition(definitionDto.definition()) - .example(definitionDto.example()) - .synonyms(definitionDto.synonyms().stream() - .map(synonymConverter::convert) - .toList()) - .antonyms(definitionDto.antonyms().stream() - .map(antonymConverter::convert) - .toList()) - .build(); - } -} diff --git a/src/main/java/com/wimdupont/converter/DictionaryConverter.java b/src/main/java/com/wimdupont/converter/DictionaryConverter.java @@ -1,33 +0,0 @@ -package com.wimdupont.converter; - -import com.wimdupont.client.model.dto.DictionaryDto; -import com.wimdupont.repository.dao.Dictionary; -import org.springframework.stereotype.Component; - -import java.util.stream.Collectors; - -@Component -public class DictionaryConverter { - - private final PhoneticConverter phoneticConverter; - private final MeaningConverter meaningConverter; - - public DictionaryConverter(PhoneticConverter phoneticConverter, - MeaningConverter meaningConverter) { - this.phoneticConverter = phoneticConverter; - this.meaningConverter = meaningConverter; - } - - public Dictionary convert(DictionaryDto dictionaryDto) { - return Dictionary.Builder.newBuilder() - .phonetic(dictionaryDto.phonetic()) - .word(dictionaryDto.word()) - .phonetics(dictionaryDto.phonetics().stream() - .map(phoneticConverter::convert) - .collect(Collectors.toList())) - .meanings(dictionaryDto.meanings().stream() - .map(meaningConverter::convert) - .collect(Collectors.toList())) - .build(); - } -} diff --git a/src/main/java/com/wimdupont/converter/MeaningConverter.java b/src/main/java/com/wimdupont/converter/MeaningConverter.java @@ -1,24 +0,0 @@ -package com.wimdupont.converter; - -import com.wimdupont.client.model.dto.MeaningDto; -import com.wimdupont.repository.dao.Meaning; -import org.springframework.stereotype.Component; - -@Component -public class MeaningConverter { - - private final DefinitionConverter definitionConverter; - - public MeaningConverter(DefinitionConverter definitionConverter) { - this.definitionConverter = definitionConverter; - } - - public Meaning convert(MeaningDto meaningDto) { - return Meaning.Builder.newBuilder() - .partOfSpeech(meaningDto.partOfSpeech()) - .definitions(meaningDto.definitions().stream() - .map(definitionConverter::convert) - .toList()) - .build(); - } -} diff --git a/src/main/java/com/wimdupont/converter/PhoneticConverter.java b/src/main/java/com/wimdupont/converter/PhoneticConverter.java @@ -1,16 +0,0 @@ -package com.wimdupont.converter; - -import com.wimdupont.client.model.dto.PhoneticDto; -import com.wimdupont.repository.dao.Phonetic; -import org.springframework.stereotype.Component; - -@Component -public class PhoneticConverter { - - public Phonetic convert(PhoneticDto phoneticDto) { - return Phonetic.Builder.newBuilder() - .audio(phoneticDto.audio()) - .text(phoneticDto.text()) - .build(); - } -} diff --git a/src/main/java/com/wimdupont/converter/SynonymConverter.java b/src/main/java/com/wimdupont/converter/SynonymConverter.java @@ -1,14 +0,0 @@ -package com.wimdupont.converter; - -import com.wimdupont.repository.dao.Synonym; -import org.springframework.stereotype.Component; - -@Component -public class SynonymConverter { - - public Synonym convert(String relatedWord) { - return Synonym.Builder.newBuilder() - .word(relatedWord) - .build(); - } -} diff --git a/src/main/java/com/wimdupont/converter/WordConverter.java b/src/main/java/com/wimdupont/converter/WordConverter.java @@ -1,27 +0,0 @@ -package com.wimdupont.converter; - -import com.wimdupont.client.model.dto.DictionaryDto; -import com.wimdupont.repository.dao.Word; -import org.springframework.stereotype.Component; - -import java.util.List; -import java.util.stream.Collectors; - -@Component -public class WordConverter { - - private final DictionaryConverter dictionaryConverter; - - public WordConverter(DictionaryConverter dictionaryConverter) { - this.dictionaryConverter = dictionaryConverter; - } - - public Word convert(String word, List<DictionaryDto> dictionaryDtoList) { - return Word.Builder.newBuilder() - .word(word) - .dictionaries(dictionaryDtoList.stream() - .map(dictionaryConverter::convert) - .collect(Collectors.toList())) - .build(); - } -} diff --git a/src/main/java/com/wimdupont/model/db/WordCouchDocument.java b/src/main/java/com/wimdupont/model/db/WordCouchDocument.java @@ -0,0 +1,18 @@ +package com.wimdupont.model.db; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.wimdupont.model.dto.WordDto; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record WordCouchDocument( + List<Row> rows + +) { + @JsonIgnoreProperties(ignoreUnknown = true) + public record Row( + WordDto doc) { + + } +} diff --git a/src/main/java/com/wimdupont/model/db/WordSelectorResponse.java b/src/main/java/com/wimdupont/model/db/WordSelectorResponse.java @@ -0,0 +1,13 @@ +package com.wimdupont.model.db; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.wimdupont.model.dto.WordDto; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record WordSelectorResponse( + List<WordDto> docs + +) { +} diff --git a/src/main/java/com/wimdupont/model/dto/DefinitionDto.java b/src/main/java/com/wimdupont/model/dto/DefinitionDto.java @@ -0,0 +1,14 @@ +package com.wimdupont.model.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record DefinitionDto( + String definition, + String example, + List<String> synonyms, + List<String> antonyms +) { +} diff --git a/src/main/java/com/wimdupont/model/dto/DictionaryDto.java b/src/main/java/com/wimdupont/model/dto/DictionaryDto.java @@ -0,0 +1,16 @@ +package com.wimdupont.model.dto; + + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record DictionaryDto( + String word, + String phonetic, + List<PhoneticDto> phonetics, + String origin, + List<MeaningDto> meanings +) { +} diff --git a/src/main/java/com/wimdupont/model/dto/MeaningDto.java b/src/main/java/com/wimdupont/model/dto/MeaningDto.java @@ -0,0 +1,13 @@ +package com.wimdupont.model.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record MeaningDto( + String partOfSpeech, + List<DefinitionDto> definitions +) { + +} diff --git a/src/main/java/com/wimdupont/model/dto/PhoneticDto.java b/src/main/java/com/wimdupont/model/dto/PhoneticDto.java @@ -0,0 +1,11 @@ +package com.wimdupont.model.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record PhoneticDto( + String text, + String audio +) { +} + diff --git a/src/main/java/com/wimdupont/model/dto/WordDto.java b/src/main/java/com/wimdupont/model/dto/WordDto.java @@ -0,0 +1,12 @@ +package com.wimdupont.model.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record WordDto ( + String word, + List<DictionaryDto> dictionaryResults +){ +} diff --git a/src/main/java/com/wimdupont/repository/WordRepository.java b/src/main/java/com/wimdupont/repository/WordRepository.java @@ -1,13 +0,0 @@ -package com.wimdupont.repository; - -import com.wimdupont.repository.dao.Word; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import java.util.Optional; - -@Repository -public interface WordRepository extends JpaRepository<Word, String> { - - Optional<Word> findByWord(String word); -} diff --git a/src/main/java/com/wimdupont/repository/dao/Antonym.java b/src/main/java/com/wimdupont/repository/dao/Antonym.java @@ -1,74 +0,0 @@ -package com.wimdupont.repository.dao; - -import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import org.hibernate.annotations.UuidGenerator; - - -@Entity -@JsonPOJOBuilder(withPrefix = "") -public class Antonym { - - @Id - @UuidGenerator - private String id; - private String word; - - protected Antonym() { - - } - - private Antonym(Builder builder) { - setId(builder.id); - setWord(builder.word); - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getWord() { - return word; - } - - public void setWord(String word) { - this.word = word; - } - - - @Override - public String toString() { - return getWord(); - } - - public static final class Builder { - private String id; - private String word; - - private Builder() { - } - - public static Builder newBuilder() { - return new Builder(); - } - - public Builder id(String val) { - id = val; - return this; - } - - public Builder word(String val) { - word = val; - return this; - } - - public Antonym build() { - return new Antonym(this); - } - } -} diff --git a/src/main/java/com/wimdupont/repository/dao/Definition.java b/src/main/java/com/wimdupont/repository/dao/Definition.java @@ -1,138 +0,0 @@ -package com.wimdupont.repository.dao; - -import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; -import jakarta.persistence.CascadeType; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.OneToMany; -import org.hibernate.annotations.UuidGenerator; - -import java.util.List; - -@Entity -@JsonPOJOBuilder(withPrefix = "") -public class Definition { - - @Id - @UuidGenerator - private String id; - @Column(length = 500) - private String definition; - @Column(length = 500) - private String example; - - @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) - @JoinColumn(name = "definition_id") - private List<Synonym> synonyms; - - @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) - @JoinColumn(name = "definition_id") - private List<Antonym> antonyms; - - protected Definition() { - - } - - private Definition(Builder builder) { - setId(builder.id); - setDefinition(builder.definition); - setExample(builder.example); - setSynonyms(builder.synonyms); - setAntonyms(builder.antonyms); - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getDefinition() { - return definition; - } - - public void setDefinition(String definition) { - this.definition = definition; - } - - public String getExample() { - return example; - } - - public void setExample(String example) { - this.example = example; - } - - public List<Synonym> getSynonyms() { - return synonyms; - } - - public void setSynonyms(List<Synonym> synonyms) { - this.synonyms = synonyms; - } - - public List<Antonym> getAntonyms() { - return antonyms; - } - - public void setAntonyms(List<Antonym> antonyms) { - this.antonyms = antonyms; - } - - - @Override - public String toString() { - return "\t" + getDefinition() + System.lineSeparator() + - (getSynonyms().isEmpty() ? "" : "Synonyms: " + System.lineSeparator() + "\t" + getSynonyms() + System.lineSeparator()) + - (getAntonyms().isEmpty() ? "" : "Antonyms: " + System.lineSeparator() + "\t" + getAntonyms() + System.lineSeparator() + - (getExample() == null ? "" : "Example: " + getExample())); - } - - public static final class Builder { - private String id; - private String definition; - private String example; - private List<Synonym> synonyms; - private List<Antonym> antonyms; - - private Builder() { - } - - public static Builder newBuilder() { - return new Builder(); - } - - public Builder id(String val) { - id = val; - return this; - } - - public Builder definition(String val) { - definition = val; - return this; - } - - public Builder example(String val) { - example = val; - return this; - } - - public Builder synonyms(List<Synonym> val) { - synonyms = val; - return this; - } - - public Builder antonyms(List<Antonym> val) { - antonyms = val; - return this; - } - - public Definition build() { - return new Definition(this); - } - } -} diff --git a/src/main/java/com/wimdupont/repository/dao/Dictionary.java b/src/main/java/com/wimdupont/repository/dao/Dictionary.java @@ -1,143 +0,0 @@ -package com.wimdupont.repository.dao; - -import jakarta.persistence.CascadeType; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.OneToMany; -import org.hibernate.annotations.UuidGenerator; - -import java.util.List; - -@Entity -public class Dictionary { - - @Id - @UuidGenerator - private String id; - private String word; - private String phonetic; - @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) - @JoinColumn(name = "dictionary_id") - private List<Phonetic> phonetics; - private String origin; - @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) - @JoinColumn(name = "dictionary_id") - private List<Meaning> meanings; - - protected Dictionary() { - - } - - private Dictionary(Builder builder) { - setId(builder.id); - setWord(builder.word); - setPhonetic(builder.phonetic); - setPhonetics(builder.phonetics); - setOrigin(builder.origin); - setMeanings(builder.meanings); - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getWord() { - return word; - } - - public void setWord(String word) { - this.word = word; - } - - public String getPhonetic() { - return phonetic; - } - - public void setPhonetic(String phonetic) { - this.phonetic = phonetic; - } - - public List<Phonetic> getPhonetics() { - return phonetics; - } - - public void setPhonetics(List<Phonetic> phonetics) { - this.phonetics = phonetics; - } - - public String getOrigin() { - return origin; - } - - public void setOrigin(String origin) { - this.origin = origin; - } - - public List<Meaning> getMeanings() { - return meanings; - } - - public void setMeanings(List<Meaning> meanings) { - this.meanings = meanings; - } - - @Override - public String toString() { - return getMeanings().toString(); - } - - public static final class Builder { - private String id; - private String word; - private String phonetic; - private List<Phonetic> phonetics; - private String origin; - private List<Meaning> meanings; - - private Builder() { - } - - public static Builder newBuilder() { - return new Builder(); - } - - public Builder id(String val) { - id = val; - return this; - } - - public Builder word(String val) { - word = val; - return this; - } - - public Builder phonetic(String val) { - phonetic = val; - return this; - } - - public Builder phonetics(List<Phonetic> val) { - phonetics = val; - return this; - } - - public Builder origin(String val) { - origin = val; - return this; - } - - public Builder meanings(List<Meaning> val) { - meanings = val; - return this; - } - - public Dictionary build() { - return new Dictionary(this); - } - } -} diff --git a/src/main/java/com/wimdupont/repository/dao/Meaning.java b/src/main/java/com/wimdupont/repository/dao/Meaning.java @@ -1,94 +0,0 @@ -package com.wimdupont.repository.dao; - -import jakarta.persistence.CascadeType; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.OneToMany; -import org.hibernate.annotations.UuidGenerator; - -import java.util.List; - -@Entity -public class Meaning { - @Id - @UuidGenerator - private String id; - private String partOfSpeech; - - @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) - @JoinColumn(name = "meaning_id") - private List<Definition> definitions; - - protected Meaning() { - - } - - private Meaning(Builder builder) { - setId(builder.id); - setPartOfSpeech(builder.partOfSpeech); - setDefinitions(builder.definitions); - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getPartOfSpeech() { - return partOfSpeech; - } - - public void setPartOfSpeech(String partOfSpeech) { - this.partOfSpeech = partOfSpeech; - } - - public List<Definition> getDefinitions() { - return definitions; - } - - public void setDefinitions(List<Definition> definitions) { - this.definitions = definitions; - } - - @Override - public String toString() { - return getPartOfSpeech() + System.lineSeparator() + - (getDefinitions().isEmpty() ? "" : "Definitions: " + System.lineSeparator() + getDefinitions()); - } - - public static final class Builder { - private String id; - private String partOfSpeech; - private List<Definition> definitions; - - private Builder() { - } - - public static Builder newBuilder() { - return new Builder(); - } - - public Builder id(String val) { - id = val; - return this; - } - - public Builder partOfSpeech(String val) { - partOfSpeech = val; - return this; - } - - public Builder definitions(List<Definition> val) { - definitions = val; - return this; - } - - public Meaning build() { - return new Meaning(this); - } - } -} diff --git a/src/main/java/com/wimdupont/repository/dao/Phonetic.java b/src/main/java/com/wimdupont/repository/dao/Phonetic.java @@ -1,81 +0,0 @@ -package com.wimdupont.repository.dao; - -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import org.hibernate.annotations.UuidGenerator; - -@Entity -public class Phonetic { - - @Id - @UuidGenerator - private String id; - private String text; - private String audio; - - protected Phonetic() { - - } - - private Phonetic(Builder builder) { - setId(builder.id); - setText(builder.text); - setAudio(builder.audio); - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } - - public String getAudio() { - return audio; - } - - public void setAudio(String audio) { - this.audio = audio; - } - - public static final class Builder { - private String id; - private String text; - private String audio; - - private Builder() { - } - - public static Builder newBuilder() { - return new Builder(); - } - - public Builder id(String val) { - id = val; - return this; - } - - public Builder text(String val) { - text = val; - return this; - } - - public Builder audio(String val) { - audio = val; - return this; - } - - public Phonetic build() { - return new Phonetic(this); - } - } -} diff --git a/src/main/java/com/wimdupont/repository/dao/Synonym.java b/src/main/java/com/wimdupont/repository/dao/Synonym.java @@ -1,70 +0,0 @@ -package com.wimdupont.repository.dao; - -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import org.hibernate.annotations.UuidGenerator; - -@Entity -public class Synonym { - - @Id - @UuidGenerator - private String id; - private String word; - - protected Synonym() { - - } - - private Synonym(Builder builder) { - setId(builder.id); - setWord(builder.word); - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getWord() { - return word; - } - - public void setWord(String word) { - this.word = word; - } - - @Override - public String toString() { - return getWord(); - } - - public static final class Builder { - private String id; - private String word; - - private Builder() { - } - - public static Builder newBuilder() { - return new Builder(); - } - - public Builder id(String val) { - id = val; - return this; - } - - public Builder word(String val) { - word = val; - return this; - } - - public Synonym build() { - return new Synonym(this); - } - } -} diff --git a/src/main/java/com/wimdupont/repository/dao/Word.java b/src/main/java/com/wimdupont/repository/dao/Word.java @@ -1,93 +0,0 @@ -package com.wimdupont.repository.dao; - - -import jakarta.persistence.CascadeType; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.OneToMany; -import org.hibernate.annotations.UuidGenerator; - -import java.util.List; - -@Entity -public class Word { - - @Id - @UuidGenerator - private String id; - private String word; - @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) - @JoinColumn(name = "word_id") - private List<Dictionary> dictionaries; - - protected Word() { - } - - private Word(Builder builder) { - setId(builder.id); - setWord(builder.word); - setDictionaries(builder.dictionaries); - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getWord() { - return word; - } - - public void setWord(String word) { - this.word = word; - } - - public List<Dictionary> getDictionaries() { - return dictionaries; - } - - public void setDictionaries(List<Dictionary> dictionaries) { - this.dictionaries = dictionaries; - } - - @Override - public String toString() { - return dictionaries.toString().replaceAll("\\[", "").replaceAll("]", ""); - } - - public static final class Builder { - private String id; - private String word; - private List<Dictionary> dictionaries; - - private Builder() { - } - - public static Builder newBuilder() { - return new Builder(); - } - - public Builder id(String val) { - id = val; - return this; - } - - public Builder word(String val) { - word = val; - return this; - } - - public Builder dictionaries(List<Dictionary> val) { - dictionaries = val; - return this; - } - - public Word build() { - return new Word(this); - } - } -} diff --git a/src/main/java/com/wimdupont/service/WordFetcher.java b/src/main/java/com/wimdupont/service/WordFetcher.java @@ -1,33 +1,26 @@ package com.wimdupont.service; -import org.springframework.stereotype.Component; +import com.wimdupont.config.ApplicationProperties; import java.io.IOException; -import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Properties; -@Component public class WordFetcher { - private static final String CSV_PROPERTY = "csv.dir"; + private final ApplicationProperties applicationProperties = ApplicationProperties.getInstance(); public List<String> fetch() { - final Properties properties = new Properties(); - try (InputStream is = getClass().getResourceAsStream("/application.properties")) { - properties.load(is); - String csvDir = properties.getProperty(CSV_PROPERTY); - List<String> words = new ArrayList<>(); - Files.lines(Path.of(csvDir)).forEach(line -> words.addAll(Arrays.stream(line.split(";")) - .map(String::trim).toList()) - ); - return words; + List<String> words = new ArrayList<>(); + try (var lines = Files.lines(Path.of(applicationProperties.getWordCsvDir()))) { + lines.forEach(line -> words.addAll(Arrays.stream(line.split(";")) + .map(String::trim).toList())); } catch (IOException e) { throw new RuntimeException(e); } + return words; } } diff --git a/src/main/java/com/wimdupont/service/WordService.java b/src/main/java/com/wimdupont/service/WordService.java @@ -1,62 +1,44 @@ package com.wimdupont.service; -import com.wimdupont.client.DictionaryAPI; -import com.wimdupont.client.model.dto.DictionaryDto; -import com.wimdupont.converter.WordConverter; -import com.wimdupont.repository.WordRepository; -import com.wimdupont.repository.dao.Word; -import jakarta.persistence.EntityManager; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.wimdupont.client.Client; +import com.wimdupont.config.ApplicationProperties; +import com.wimdupont.model.db.WordCouchDocument; +import com.wimdupont.model.db.WordSelectorResponse; +import com.wimdupont.model.dto.WordDto; + +import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.Optional; + -@Service -@Transactional public class WordService { + private final ApplicationProperties applicationProperties = ApplicationProperties.getInstance(); + + public List<String> findAllWords() { + return Client.get(applicationProperties.getCouchdbUrl() + "/_all_docs?include_docs=true", WordCouchDocument.class) + .map(wordCouchDocument -> wordCouchDocument.rows().stream().map(row -> row.doc().word()).toList()) + .orElseGet(ArrayList::new); + } - private final DictionaryAPI dictionaryAPI; - private final WordRepository wordRepository; - private final WordConverter wordConverter; - private final EntityManager entityManager; - private final WordFetcher wordFetcher; - - public WordService(DictionaryAPI dictionaryAPI, - WordRepository wordRepository, - WordConverter wordConverter, - EntityManager entityManager, - WordFetcher wordFetcher) { - this.dictionaryAPI = dictionaryAPI; - this.wordRepository = wordRepository; - this.wordConverter = wordConverter; - this.entityManager = entityManager; - this.wordFetcher = wordFetcher; + public Optional<WordDto> findByWord(String word) { + var url = applicationProperties.getCouchdbUrl() + "/_find"; + var requestString = String.format("{ \"selector\": { \"word\": { \"$eq\": \"%s\" } } }", word); + return Client.post(url, WordSelectorResponse.class, requestString).flatMap(f -> f.docs().stream().findAny()); } - public void saveNew() { - List<String> words = wordFetcher.fetch(); - List<Word> savedWordList = wordRepository.findAll(); - System.out.printf("Words in database: %s%n", savedWordList.size()); - List<String> savedWords = savedWordList.stream().map(Word::getWord).toList(); - AtomicInteger count = new AtomicInteger(0); - words.stream() - .filter(csvWord -> !savedWords.contains(csvWord)) - .forEach(newWord -> { - List<DictionaryDto> response = dictionaryAPI.getAffirmation(newWord); - if (response.isEmpty()) { - System.out.printf("No results found for '%s', no data saved%n", newWord); - count.get(); - } else { - Word word = wordRepository.save(wordConverter.convert(newWord, response)); - System.out.printf("Saved new word %s%n", word.getWord()); - count.getAndIncrement(); - } - }); - - if (count.get() > 0) - System.out.printf("Saved %s words%n", count.get()); - entityManager.flush(); + public void save(WordDto wordDto) { + if (findByWord(wordDto.word()).isEmpty()) { + var url = applicationProperties.getCouchdbUrl(); + try { + Client.post(url, WordSelectorResponse.class, new ObjectMapper().writeValueAsString(wordDto)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } else { + System.out.printf("Word %s already saved", wordDto.word()); + } } } diff --git a/src/main/java/com/wimdupont/service/WordTester.java b/src/main/java/com/wimdupont/service/WordTester.java @@ -1,59 +1,110 @@ package com.wimdupont.service; -import com.wimdupont.client.DictionaryAPI; -import com.wimdupont.client.model.dto.DictionaryDto; -import com.wimdupont.converter.WordConverter; -import com.wimdupont.repository.WordRepository; -import com.wimdupont.repository.dao.Word; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; +import com.wimdupont.model.dto.DictionaryDto; +import com.wimdupont.model.dto.WordDto; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import java.awt.BorderLayout; +import java.awt.GridBagLayout; import java.util.Collections; import java.util.List; -import java.util.Optional; -import java.util.Scanner; +import java.util.concurrent.atomic.AtomicInteger; -@Component -@Transactional public class WordTester { + /* + - navigate with hjkl, arrows, spacebar,... + - close frame + - add database options: remove word, fully clean database,... + - + - + */ - private final DictionaryAPI dictionaryAPI; - private final WordRepository wordRepository; - private final WordConverter wordConverter; private final WordFetcher wordFetcher; + private final WordService wordService; - public WordTester(DictionaryAPI dictionaryAPI, - WordRepository wordRepository, - WordConverter wordConverter, - WordFetcher wordFetcher) { - this.dictionaryAPI = dictionaryAPI; - this.wordRepository = wordRepository; - this.wordConverter = wordConverter; + public WordTester(WordFetcher wordFetcher, + WordService wordService) { this.wordFetcher = wordFetcher; + this.wordService = wordService; } public void process() { - Scanner scanner = new Scanner(System.in); List<String> words = wordFetcher.fetch(); System.out.printf("Words in csv file: %s%n", words.size()); Collections.shuffle(words); - for (String word : words) { - System.out.println(); - System.out.println(word); - Optional<Word> result = wordRepository.findByWord(word); - Word saved; - if (result.isEmpty()) { - List<DictionaryDto> response = dictionaryAPI.getAffirmation(word); - saved = wordRepository.save(wordConverter.convert(word, response)); - } else { - saved = result.get(); - } - scanner.nextLine(); - System.out.println(saved); - System.out.println("========================"); - } + panelItUp(words); + System.out.println("========================"); System.out.println("All words have been tested."); } + + private JTextArea createShowPanel() { + var dictionaryPanel = new JTextArea(); + dictionaryPanel.setLineWrap(true); + dictionaryPanel.setEditable(false); + return dictionaryPanel; + + } + + private void panelItUp(List<String> words) { + AtomicInteger index = new AtomicInteger(0); + JFrame jFrame = new JFrame(); + jFrame.setLayout(new BorderLayout()); + final JPanel jPanel = new JPanel(); + jPanel.add(new JLabel("A Panel")); + jFrame.add(jPanel, BorderLayout.CENTER); + var wordPanel = new JPanel(new GridBagLayout()); + var wordField = new JLabel(words.get(index.get())); + wordPanel.add(wordField); + var showPanel = createShowPanel(); + + wordPanel.add(showPanel); + + JButton previousButton = new JButton("Previous"); + previousButton.addActionListener(e -> { + if (index.get() > 0) { + wordField.setText(words.get(index.decrementAndGet())); + } + }); + JButton showButton = new JButton("Show"); + showButton.addActionListener(e -> { + var word = wordService.findByWord(words.get(index.get())); + word.ifPresent(wordDto -> showPanel.setText(toMeaning(wordDto))); + //TODO else grab and save + + }); + + JButton nextButton = new JButton("Next"); + nextButton.addActionListener(e -> { + if (index.get() < words.size()) { + wordField.setText(words.get(index.incrementAndGet())); + } + }); + var btnPanel = new JPanel(); + btnPanel.add(previousButton); + btnPanel.add(showButton); + btnPanel.add(nextButton); + + jFrame.add(wordPanel, BorderLayout.CENTER); + jFrame.add(btnPanel, BorderLayout.SOUTH); + jFrame.pack(); + jFrame.setVisible(true); + } + + private String toMeaning(WordDto wordDto) { + return """ + Word: %s + Meaning: %s + """ + .formatted(wordDto.word() + System.lineSeparator(), + wordDto.dictionaryResults().stream() + .map(DictionaryDto::meanings) + .toList()); + } + } diff --git a/src/main/resources/init.sql b/src/main/resources/init.sql @@ -1,54 +0,0 @@ -CREATE TABLE word ( - id VARCHAR(36) PRIMARY KEY NOT NULL, - word VARCHAR(200) UNIQUE -); - -CREATE UNIQUE INDEX word_index ON word(word); - -CREATE TABLE dictionary ( - id VARCHAR(36) PRIMARY KEY NOT NULL, - word VARCHAR(200), - phonetic VARCHAR(200), - origin VARCHAR(200), - word_id VARCHAR(36), - CONSTRAINT fk_word_dictionary FOREIGN KEY (word_id) REFERENCES word (id) -); - -CREATE TABLE phonetic ( - id VARCHAR(36) PRIMARY KEY NOT NULL, - text VARCHAR(200), - audio VARCHAR(200), - dictionary_id VARCHAR(36), - CONSTRAINT fk_dictionary_phonetic FOREIGN KEY (dictionary_id) REFERENCES dictionary (id) -); - -CREATE TABLE meaning ( - id VARCHAR(36) PRIMARY KEY NOT NULL, - part_of_speech VARCHAR(200), - dictionary_id VARCHAR(36), - CONSTRAINT fk_dictionary_meaning FOREIGN KEY (dictionary_id) REFERENCES dictionary (id) -); - -CREATE TABLE definition ( - id VARCHAR(36) PRIMARY KEY NOT NULL, - definition VARCHAR(1000), - example VARCHAR(1000), - synonyms VARCHAR(1000), - antonyms VARCHAR(1000), - meaning_id VARCHAR(36), - CONSTRAINT fk_meaning_definition FOREIGN KEY (meaning_id) REFERENCES meaning (id) -); - -CREATE TABLE synonym ( - id VARCHAR(36) PRIMARY KEY NOT NULL, - word VARCHAR(200), - definition_id VARCHAR(36), - CONSTRAINT fk_definition_synonym FOREIGN KEY (definition_id) REFERENCES definition (id) -); - -CREATE TABLE antonym ( - id VARCHAR(36) PRIMARY KEY NOT NULL, - word VARCHAR(200), - definition_id VARCHAR(36), - CONSTRAINT fk_definition_antonym FOREIGN KEY (definition_id) REFERENCES definition (id) -);