Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Create an abstraction layer for the database #407

Draft
wants to merge 38 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7cd2e21
Created basic recipe entity's getters and setters
christianlupus Nov 8, 2020
b04bad5
Corrected RecipeEntity copy&paste errors
christianlupus Nov 8, 2020
90a9241
Corrected styling of code
christianlupus Nov 19, 2020
54f7777
Created basic entity structure for categories
christianlupus Nov 19, 2020
c72df66
Added wrapper and entity for keywords
christianlupus Nov 19, 2020
36b4d87
Updated category interconnection
christianlupus Nov 19, 2020
e7736db
Moving JSON entity out of the way and extending structure to recipe t…
christianlupus Nov 19, 2020
efab4ba
Removed missing parts in other wrappers
christianlupus Nov 19, 2020
b31e301
Added mapping structures, not yet implemented
christianlupus Nov 19, 2020
8654dba
Corrected namespacing typos
christianlupus Nov 20, 2020
68d8c80
Created basic service locator for wrappers
christianlupus Nov 20, 2020
3af617f
Added missing constructor to RecipeEntity
christianlupus Nov 20, 2020
b6c6ce1
Corrected namespaces
christianlupus Nov 20, 2020
fce1af2
Added access to the service locator in the abstract wrapper class
christianlupus Nov 20, 2020
474580d
Added missing methods to keyword and category classes
christianlupus Nov 20, 2020
4f47af6
Added basic structure to remove entities
christianlupus Nov 20, 2020
7d734de
Implemented Wrapper for CategoryMappers
christianlupus Nov 20, 2020
73b6584
Implemented search for recipe by id
christianlupus Nov 20, 2020
3f04c7e
Added some error handling and implemented Wrapper for Recipes
christianlupus Nov 20, 2020
7b5ba3a
Intermediate UML diagramm added
christianlupus Nov 21, 2020
0ee944e
Updated diagramm before bigger changes
christianlupus Nov 21, 2020
49c2ced
Removed MappingEntities from structure
christianlupus Nov 21, 2020
f5e508c
Readded MappingEntities in a minimal fashion. Working not yet checked.
christianlupus Nov 21, 2020
2494f98
Usage of generics to simplify abstract DB wrapper
christianlupus Nov 22, 2020
8a876c4
Restrcutured PHP classes according to UML plan
christianlupus Nov 22, 2020
a822bf6
Added some implementation to Entities
christianlupus Nov 22, 2020
9d8ab84
Implemented most of the DB backend, foreign links are not yet managed
christianlupus Nov 22, 2020
6304cbc
Extracted fetching of mappings into separate methods
christianlupus Nov 22, 2020
60d85a4
Implemented all DB related wrappers, no tests carried out, no checks
christianlupus Nov 22, 2020
9884ca7
Added entry to changelog
christianlupus Nov 22, 2020
75d8b99
Corrected style using code styler
christianlupus Nov 22, 2020
df7cbcf
Corrected code to make the unittest run again
christianlupus Nov 23, 2020
de3b3d6
Corrected Exception in AbstractEntity
christianlupus Nov 23, 2020
04750d3
Updated GH actions to make support for PHP 7.2 optional
christianlupus Nov 23, 2020
1aec037
Corrected types to be compatible with PHP prior to 7.4
christianlupus Nov 23, 2020
9a8d907
Updated to the most recent rc of PHP for unit testing
christianlupus Nov 23, 2020
78f94e6
Removed rc PHP testing
christianlupus Nov 23, 2020
4083e95
Added collection classes to UML
christianlupus Nov 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/run-tests/tests/test-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ else

echo 'Copying the app code changes'
echo 'This might cause trouble when dependencies have changed'
rsync -a /app/ apps/cookbook/ --exclude /.git --exclude /build --exclude /.github
rsync -a /app/ apps/cookbook/ --exclude /.git --exclude /build --exclude /.github --exclude /vendor

fi

Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## [Unreleased]

### Added
- Database abstraction added for simpler access
[#407](https://github.com/nextcloud/cookbook/pull/407) @christianlupus

## 0.7.9 - 2021-01-15

### Changed
Expand Down
216 changes: 216 additions & 0 deletions documentation/uml/dbwrappers.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
@startuml

namespace OCA.Cookbook {

namespace Entity {

interface Entity {
+ persist() : void
+ remove() : void
+ reload() : void
}

interface RecipeEntity {
--
+ getId() : int
+ getName() : string
+ setName(string) : void
..
+ getCategory() : CategoryEntity
+ setCategory(CategoryEntity) : void
+ getKeywords() : array
+ addKeyword(KeywordEntity) : void
+ removeKeyword(KeywordEntity) : void
}

interface CategoryEntity {
--
+ getName() : string
+ setName(string) : void
..
+ getRecipes() : array
}

interface KeywordEntity {
--
+ getName() : string
+ setName(string) : void
..
+ getRecipes() : array
}


namespace impl {

abstract class AbstractEntity {
- bool persisted
+ isPersisted() : bool
+ abstract clone() : ImplEntity
+ abstract isSame(AbstractEntity) : bool
+ abstract equals(AbstractEntity) : bool
}

class RecipeEntityImpl {
#id
#name
#userId
# RecipeDbWrapper wrapper
# CategoryEntityImpl newCategory
# array newKeywords
# array removedKeywords
+ getNewCategory() : CategoryEntityImpl | null
+ getNewKeywords() : array
+ getRemovedKeywords() : array
}

class CategoryEntityImpl {
#name
# CategoryDbWrapper wrapper
}

class KeywordEntityImpl {
#name
# KeywordDbWrapper wrapper
}

class CategoryMappingEntity {
}

class KeywordMappingEntity {
}

RecipeEntityImpl --|> AbstractEntity
CategoryEntityImpl --|> AbstractEntity
KeywordEntityImpl --|> AbstractEntity

CategoryMappingEntity -|> AbstractEntity
AbstractEntity <|- KeywordMappingEntity

RecipeEntityImpl "1" *--x CategoryMappingEntity
RecipeEntityImpl "1" *--x KeywordMappingEntity
CategoryEntityImpl "1" *--x CategoryMappingEntity
KeywordEntityImpl "1" *--x KeywordMappingEntity

}

RecipeEntity <|.. OCA.Cookbook.Entity.impl.RecipeEntityImpl
CategoryEntity <|.. OCA.Cookbook.Entity.impl.CategoryEntityImpl
KeywordEntity <|.. OCA.Cookbook.Entity.impl.KeywordEntityImpl

Entity <|.. RecipeEntity
Entity <|.. CategoryEntity
Entity <|.. KeywordEntity

namespace Collections {

abstract class AbstractCollection<T extends Entity> {}
class Recipes {}
class Categories {}
class Keywords {}


AbstractCollection <|-- Recipes
AbstractCollection <|-- Categories
AbstractCollection <|-- Keywords
}

}

namespace Db {

abstract class AbstractDbWrapper {
# IDbConnection db
- array cache
- bool cacheValid
+ abstract createEntity() : T
# abstract fetchDatabase() : array
+ getEntites() : array
# setCache(array) : void
+ getServiceLocator() : DbWrapperSerciveLocator
}
note right
Cache represents the current state
of the database tables as clones.
endnote

class RecipeDbWrapper {
' - array idMap
--
+ createEntity() : RecipeEntityImpl
+ store(RecipeEntityImpl) : void
# storeNew(RecipeEntityImpl) : void
# update(RecipeEntityImpl) : void
+ remove(RecipeEntityImpl) : void
..
/'+ addKeyword(RecipeEntityImpl, KeywordEntityImpl) : KeywordMappingEntity
+ setCategory(RecipeEntityImpl, CategoryEntityImpl) : CategoryMappingEntity'/
+ getCategory(RecipeEntityImpl) : CategoryEntityImpl
+ getKeywords(RecipeEntityImpl) : array
}
class CategoryDbWrapper {
--
+ createEntity() : CategoryEntityImpl
+ store(CategoryEntityImpl) : void
# storeNew(CategoryEntityImpl) : void
# update(CategoryEntityImpl) : void
+ remove(CategoryEntityImpl) : void
..
+ getRecipes(CategoryEntityImpl) : array
}
class KeywordDbWrapper {
--
+ createEntity() : KeywordEntityImpl
+ store(KeywordEntityImpl) : void
# storeNew(KeywordEntityImpl) : void
# update(KeywordEntityImpl) : void
+ remove(KeywordEntityImpl) : void
..
+ getRecipes(KeywordEntityImpl) : array
}

class CategoryMappingsDbWrapper {
+ createEntity() : CategoryMappingEntity
+ store(CategoryMappingEntity) : void
# storeNew(CategoryMappingEntity) : void
# update(CategoryMappingEntity) : void
+ remove(CategoryMappingEntity) : void
}

class KeywordMappingsDbWrapper {
+ createEntity() : KeywordMappingEntity
+ store(KeywordMappingEntity) : void
# storeNew(KeywordMappingEntity) : void
# update(KeywordMappingEntity) : void
+ remove(KeywordMappingEntity) : void
}

class DbWrapperSerciveLocator {
+ getRecipeDbWrapoper() : RecipeDbWrapper
+ getCategoryDbWrapper() : CategoryDbWrapper
+ getKeywordDbWrapper() : KeywordDbWrapper
+ getKeywordMappingDbWrapper() : KeywordMappingsDbWrapper
+ getCategoryMappingDbWrapper() : CategoryMappingsDbWrapper
}

AbstractDbWrapper <|-- RecipeDbWrapper
AbstractDbWrapper <|-- CategoryDbWrapper
AbstractDbWrapper <|-- KeywordDbWrapper

RecipeDbWrapper "1" o-- "1" DbWrapperSerciveLocator
CategoryDbWrapper "1" o-- "1" DbWrapperSerciveLocator
KeywordDbWrapper "1" o-- "1" DbWrapperSerciveLocator

CategoryMappingsDbWrapper "1" o- "1" DbWrapperSerciveLocator
DbWrapperSerciveLocator "1" -o "1" KeywordMappingsDbWrapper

AbstractDbWrapper <|--- CategoryMappingsDbWrapper
AbstractDbWrapper <|--- KeywordMappingsDbWrapper

DbWrapperSerciveLocator -[hidden]-> AbstractDbWrapper
}

}

ArrayIterator <|-- OCA.Cookbook.Entity.Collections.AbstractCollection

@enduml
104 changes: 104 additions & 0 deletions lib/Db/AbstractDbWrapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

namespace OCA\Cookbook\Db;

use OCP\IDBConnection;

abstract class AbstractDbWrapper {

/**
* @var array
*/
private $cache;

/**
* @var bool
*/
private $initialized;

/**
* @var IDBConnection
*/
private $db;

/**
* @var DbWrapperServiceProvider
*/
protected $wrapperLocator;

public function __construct(IDBConnection $db) {
$this->initialized = false;
$this->db = $db;
}

/**
* Fetch all elements from the database.
*
* The concrete class must implemnt a way to fetch an array or elements represented by the database.
* @return array The (possible empty) array of entities in the database
*/
abstract protected function fetchDatabase(): array;

/**
* Fetch the entries in the database
*
* If the cache has already been fetched, the values in the cache are returned.
*
* @return array The entities in the database.
*/
public function getEntries(): array {
if (! $this->initialized) {
$this->reloadCache();
}

return $this->cache;
}

/**
* Reload the cache from the database.
*/
private function reloadCache(): void {
$this->cache = $this->fetchDatabase();
$this->initialized = true;
}

/**
* Invalidate the local cache.
*
* This will cause any access to the entities to refetch the whole cache.
*/
protected function invalidateCache(): void {
$this->initialized = false;
}

/**
* Set the cache to the given array.
*
* This function will repace the current cache by the given array.
* No further checks are carried out.
* Please be very careful to provide the most up to date data as present in the database.
* Otherwise you will see very strange effects.
*
* @param array $entities The new entities of the cache
*/
protected function setEntites(array $entities): void {
$this->cache = $entities;
$this->initialized = true;
}

/**
* Set the central service locator for registering of all wrappers
* @param DbWrapperServiceProvider $locator The locator for the registered wrappers
*/
public function setWrapperServiceLocator(DbWrapperServiceProvider $locator) {
$this->wrapperLocator = $locator;
}

/**
* Get the central service locator for registering of all wrappers
* @return DbWrapperServiceProvider The locator for the registered wrappers
*/
public function getWrapperServiceLocator() {
return $this->wrapperLocator;
}
}
Loading