-
Notifications
You must be signed in to change notification settings - Fork 196
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
Adding a special constructor to one implementation of an interface #160
Comments
At what point is the string available?
I.e. where would that SetBackingStore be called if we had that?
Depending on that you might be interested in one of:
https://github.com/google/fruit/wiki/quick-reference#providers
https://github.com/google/fruit/wiki/quick-reference#factories-and-assisted-injection
…On Thu, Mar 28, 2024 at 10:47 AM IrisPeter ***@***.***> wrote:
When implementing a JSON repository so that it could replace the standard
repository that would just load the information from disk I have now
discovered a requirement to somehow modify the constructor of the JSON
repository so that it can take a std::string which will be the backing
store that the JSON repository object uses to load itself.
A reminder of the interface:
template <typename T, typename key_type = void, typename the_key = Key<key_type>>class IRepository
{public:
using key = the_key;
virtual ~IRepository() = default;
virtual T GetByKey(const key& theKey = {}) = 0;
virtual void Add(const T& entity) = 0;
virtual void Remove(const T& entity) = 0;
virtual void Update(const T& entity) = 0;
};
Then a section of the JSON Repository implementation
class JSONScalerRepositoryImpl : public IScalerRepository
{public:
INJECT(JSONScalerRepositoryImpl()) = default;
...
};
fruit::Component<IScalerRepository> getScalerJsonRepository()
{
return fruit::createComponent().bind<IScalerRepository, JSONScalerRepositoryImpl>();
}
*Testing.cpp*
include "Testing.h"
#include "DBScalerRepository.h"
#include "JSONScalerRepository.h"
fruit::Component<ScalerFactory> getScalerTestComponent()
{
return fruit::createComponent()
// Note: order matters here. This replace().with() must be before the install. Otherwise Fruit will report the
// wrong order as a run-time error.
.replace(getScalerRepositoryDB).with(getScalerJsonRepository)
.install(getScalerComponent);
}
*main.cpp*
#include <print>
#include "Repositories.h"
#include "scaler.h"
Injector<ScalerFactory> underTestInjector(getScalerTestComponent);
ScalerFactory scalerUnderTestInjector(underTestInjector);
std::unique_ptr<Scaler> scalerLoadedUnderTest = scalerUnderTestInjector(12.1);
std::println("{}", scalerLoadedUnderTest->scale(3));
So my question is there any way to modify the code to somehow get a
std::string to the JSONScalerRepositoryImpl constructor?
Otherwise I think I will just have to add an extra method to the interface
that would only ever be used by JSONScalerRepositoryImpl
template <typename T, typename key_type = void, typename the_key = Key<key_type>>class IRepository
{public:
....
//Same as before
virtual void SetBackingStore(const std::string& json) = 0;
};
—
Reply to this email directly, view it on GitHub
<#160>, or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AALZ4FY25BAPVJRSHM6UFDDY2RCSDAVCNFSM6AAAAABFNHBTW6VHI2DSMVQWIX3LMV43ASLTON2WKOZSGIYTGNZZG4YDAMI>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
I was hoping that it would be possible somehow to avoid polluting
I'm not quite sure what you were getting at with your two references, but in your Server example which uses providers I see something interesting in static void worker_thread_main(const NormalizedComponent<Required<Request>, RequestDispatcher>& requestDispatcherNormalizedComponent, Request request)
{
Injector<RequestDispatcher> injector(requestDispatcherNormalizedComponent, getRequestComponent, &request);
RequestDispatcher* requestDispatcher(injector);
requestDispatcher->handleRequest();
} I also see something similar happening when setting up the NormalizedComponent. I've noticed in these repositories that come from C# that a repository usually has a context variable in this case public class Repository<TEntity> : IRepository <TEntity> where TEntity : class
{
protected readonly DbContext Context;
protected readonly DbSet<TEntity> Entities;
public Repository(DbContext context)
{
Context = context;
Entities = Context.Set<TEntity>();
}
public void Add(TEntity entity)
{
Entities.Add(entity);
}
} Upon seeing this I asked ChatGPT about other The different context objects are much more fully featured than anything I might need, I think that I would only need a For my requirements it is only the JSON version of the repository that needs a context object, as all the DB implementations would just feature one of our special DAO objects and they are able to retrieve the DB connections/strings without being explicitly stated. I imagine that both repositories will need to have context objects passed to their constructors, the string would just be empty for the DB repositories. I would imagine I would probably do the same thing as you do in the example where the string lives as a member of some struct, say I find certain parts of the Fruit library hard to get my head around, so even though I have stepped through the Server example I still require some guidance on how I can get this to work. |
Could you pass the backing store as a param to getScalerTestComponent and use bindInstance() there?
|
The modifications to Testing.cpp are compiling OK. However when I try and compile JSONScalerRepository.cpp I receive the following compilation errors:
main.cpp I am receiving the following compilation errors:
JSONScalerRepository.cpp #include "JSONScalerRepository.h"
class JSONScalerRepositoryImpl : public IScalerRepository
{
private:
std::string& backingStore;
public:
INJECT(JSONScalerRepositoryImpl(std::string& backingStore)) : backingStore(backingStore) {};
//INJECT(JSONScalerRepositoryImpl()) = default;
scaler GetByKey(const key& theKey = {}) override
{
std::println("GetByKey called from the JSON Scaler Repository");
scaler scale;
scale.factor = 5.5;
return scale;
}
void Add(const scaler& item) override
{
}
void Update(const scaler& item) override
{
}
void Remove(const scaler& key) override
{
}
};
fruit::Component<IScalerRepository> getScalerRepositoryJSONComponent()
{
return fruit::createComponent().bind<IScalerRepository, JSONScalerRepositoryImpl>();
}
|
I also tried turning the That gave slightly different errors, in the main.cpps the main error was inside this bit of the fruit code template <typename T>
FRUIT_ALWAYS_INLINE inline int checkAcceptableComponentInstallArg() {
// This lambda checks that the required operations on T exist.
// Note that the lambda is never actually executed.
auto checkRequirements = [](const T& constRef, T value) {
T x1(constRef);
T x2(std::move(value));
x1 = constRef;
x2 = std::move(value);
bool b = (constRef == constRef);
std::size_t h = std::hash<T>()(constRef);
(void)x1;
(void)x2;
(void)b;
(void)h;
};
(void)checkRequirements;
return 0;
} Its the Inside JSONScalerRepository.cpp its the following code that fails:
The only thing that changes is that I'm not sure what is going on, as it doesn't seem that different to the |
I wondered whether the return type of both fruit::Component<fruit::Required<std::string>, IScalerRepository> getScalerJsonRepository();
fruit::Component<fruit::Required<std::string>, IScalerRepository> getScalerRepositoryDBComponent(); and whilst that seemed to fix the compiling of JSONScalerRepository.cpp, it seemed to break compiling Scaler.cpp. Also whilst Testing.cpp compiled OK with getScalerTestComponent having
|
Oh sorry I forgot the component types had to be the same since you're using replace(...).with(...).
|
Thanks @poletti-marco , I'm further along, I can manage to get the std::string version to compile. The compiler won't accept your specific changes, I had to remove the & from In the auto operator<=>(const Context&) const = default; and also outside the struct: namespace std
{
template <>
struct hash<Context>
{
size_t operator()(const Context& ctx) const { return std::hash<std::string>()(ctx.BackingStore); }
};
} The problem I'm having is that the repository crashes the moment you access the If you modify class JSONScalerRepositoryImpl : public IScalerRepository
{
private:
std::string backingStore;
public:
INJECT(JSONScalerRepositoryImpl(std::string info)) : backingStore(info) {};
... The crash will move to the injection site (an STL member throws when trying to fulfil the constructor. I then wondered whether the static Component<Request> getRequestComponent(Request* request)
{
return createComponent().bindInstance(*request);
} When the request is injected at that point in the Server example it does bind as a I tried that modification both in my In In |
Just noticed In the fruit::Component<ScalerFactory> getScalerTestComponent(std::string) When I changed that to |
So now I have a working version with The
For some reason the fuller error is only showing in the problem details view. Its confusing why the |
I'm guessing there's a mismatch somewhere. |
Scratch the above I had forgotten to update the variable passed to the Injector constructor so that it was a Context object rather than a It's all now working, thanks @poletti-marco So in summary for anyone who looks at this issue wanting to do something similar, the steps where: fruit::Component<IScalerRepository> getScalerJsonRepository(std::string* pJsonString)
{
return fruit::createComponent()
.bind<IScalerRepository, JSONScalerRepositoryImpl>()
.bindInstance(*pJsonString);
} // As before
fruit::Component<IScalerRepository> getScalerRepositoryDBComponent() {...} fruit::Component<ScalerFactory> getScalerTestComponent(std::string* pJsonString)
{
return fruit::createComponent()
// Note: order matters here. This replace().with() must be before the install. Otherwise Fruit will report the
// wrong order as a run-time error.
.replace(getScalerRepositoryDB).with(getScalerJsonRepository, pJsonString)
.install(getScalerComponent);
} and finally class JSONScalerRepositoryImpl : public IScalerRepository
{
private:
std::string m_context;
public:
INJECT(JSONScalerRepositoryImpl(const std::string& json)) : m_context(json) {}
...
}; So both the spaceship operator inside |
Closing Issue due to working instructions in thread |
When implementing a JSON repository so that it could replace the standard repository that would just load the information from disk I have now discovered a requirement to somehow modify the constructor of the JSON repository so that it can take a std::string which will be the backing store that the JSON repository object uses to load itself.
A reminder of the interface:
Then a section of the JSON Repository implementation
Testing.cpp
main.cpp
So my question is there any way to modify the code to somehow get a std::string to the JSONScalerRepositoryImpl constructor?
Otherwise I think I will just have to add an extra method to the interface that would only ever be used by JSONScalerRepositoryImpl
The text was updated successfully, but these errors were encountered: