I have tried to find best practice for Lighthouse subscription during 2 weeks.
But i cant find the best practice until now.
This is my shema.graphql
type Subscription {
rsvHolidaySub(id: ID): Rsv_holiday }
type Mutation {
updateHoliday(id: ID!, holiday_type: Int!): Rsv_holiday #update
#broadcast(subscription: "rsvHolidaySub") }
type Rsv_holiday {
id: ID!
holiday_type: Int!
start_time: String!
end_time: String! }
When i query mutation updateHoliday like below
I hope RsvHolidaySub resolve function is called from #broadcast(subscription: "rsvHolidaySub")
So i can broadcast like this
class RsvHolidaySub extends GraphQLSubscription
{
public function __construct() {}
public function authorize(Subscriber $subscriber, Request $request): bool {}
public function filter(Subscriber $subscriber, $root): bool {}
public function encodeTopic(Subscriber $subscriber, string $fieldName): string {}
public function decodeTopic(string $fieldName, $root): string {}
public function resolve($root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): Rsv_holiday
{
// I wanna call broadcast in here!!!!!!
broadcast(new SomeEvent);
return $root;
}
}
I don't know this is the best practice for Subscription. But i think this is very simple and clean.
But even if i installed websocket by using redis + laravel-echo-server or beyondcode/laravel-websockets,
The resolve function is not called.
So i doubt this is possible or not.
I really want to know Lighthouse subscription best practice. Please share your knowledge.
I trigger all of my subscriptions from code.
But I also don't use those #create or #update directives, but just a kind of field, so I do everything I want in my code and then just trigger the subscription even with any other data... Works fine for me.
But I don't know what would be the "best practices".
Related
I'm using Laravel for a site where most database objects can be private (i.e., viewed only by their owner) or public (viewed by everyone, including guests). Each of these has a user_id, which I set to NULL when the object is public.
What's the simplest way of authenticating routes for this scenario? For example, in /routes/web.php I have:
Route::get('/{tournament}/players', [TournamentController::class, 'indexPlayers']);
and I want to make sure that tournament->user_id is either NULL or corresponds to the user's id. I was able to do this by explicitly binding tournament in /app/Providers/RouteServiceProvider.php:
Route::bind('tournament', function ($hash) {
$user_id = Auth::user()->id ?? NULL;
return Tournament::where([['hash', $hash], ['user_id', $user_id]])
->orWhere([['hash', $hash], ['user_id', NULL]])
->firstOrFail();
});
but I have the strong feeling that I'm making it too complicated or doing things in the wrong place. Is there a better way? Should I by doing this inside TournamentController, for example?
First, there is now the syntax Auth::id() that can be used as a shorthand for Auth::user()->id ?? NULL, so that saves some trouble.
Next, I ended up moving the logic out of RouteServiceProvider.php and into the controller, so that I can explicitly control what happens for public vs. private objects:
class TournamentController extends Controller
{
public function indexPlayers(Tournament $tournament)
{
if ($tournament->user_id === NULL) {
// public
} else if ($tournament->user_id === Auth::id()) {
// private
} else {
// unauthorized
}
}
...
}
I am implementing my own Activiti command intereceptor like this :
public class ActivitiCommandInterceptor extends AbstractCommandInterceptor {
private RuntimeService runtimeService;
private CommandInterceptor delegate;
public ActivitiSpringTxCommandInterceptor(RuntimeService runtimeService, CommandInterceptor delegate) {
this.runtimeService = runtimeService;
this.delegate=delegate;
}
#Override
public <T> T execute(CommandConfig config, Command<T> command) {
String myVariable = runtimeService.getVariable(<missingExecutionId>, "myVariableName");
...
}
}
Inside the execute() method I need to retrieve a variable from the execution context related to this command.
To do that, I need to have the executionId, but I can't find a way to retrieve it.
How can I get my variable from this interceptor?
Thanks
You can create a nativeExecutionQuery
This allows us to use SQL to perform operations directly on DB.
For your case, just find all the execution IDs that contains your variables, and filter them according to your need.
I want to save an array of Mission.class which have variables as follows:
public class Mission {
public MissionEnum missionEnum;
public int progress;
public Mission(MissionEnum missionEnum, int progress) {
this.missionEnum = missionEnum;
this.progress = progress;
}
and also save missions in another java class:
public void saveMissions() {
Json json = new Json();
json.setOutputType(JsonWriter.OutputType.json);
json.addClassTag("Mission", Mission.class);
FileHandle missionFile = Gdx.files.local("missions_array.json");
missionFile.writeString(json.prettyPrint(missions), false);
}
and load missions:
public void loadMissions() {
if (Gdx.files.local("missions_array.json").exists()) {
try {
FileHandle file = Gdx.files.local("missions_array.json");
Json json = new Json();
json.addClassTag("Mission", Mission.class);
missions = json.fromJson(Array.class, Mission.class, file);
for (Mission mission : missions) {
Gdx.app.log(TAG, "Mission loaded: " + mission.missionEnum);
}
Gdx.app.log(TAG, "Load missions successful");
} catch (Exception e) {
Gdx.app.error(TAG, "Unable to read Missions: " + e.getMessage());
}
}
}
I got json like this:
[
{
"class": "Mission",
"missionEnum": "BUY_POWERUP"
},
{
"class": "Mission",
"missionEnum": "DISTANCE_ONE_RUN_2"
},
{
"class": "Mission",
"missionEnum": "BANANA_TOTAL_2",
"progress": 35
}
]
However when loadMissions() is run I got the "Load missions successful" log shown but "Mission loaded..." aren't shown without any error log. Missions appeared not loaded properly. I do not know what went wrong because another array is loaded successful the same way.
Not sure why there are no errors in the logs, since while reproducing your problem I've got an exception.
The problem is in loadMissions() method: you create new Json parser without setting the class tag:
Json json = new Json();
// add the line below
json.addClassTag("Mission", Mission.class);
missions = json.fromJson(Array.class, Mission.class, file);
....
Without the tag parser doesn't know what is "class": "Mission" in json file.
Update
Another thing that may cause this issue is the args-constructor. At least, when I added it I got an exception. If you don't use it - just delete.
Still, quite weird that you don't have any exceptions in logs'cos I definitely have.
Updated response:
Add an empty contructor and read this and this
You will either have to add a no-argument constructor to (Mission), or
you will have to add a custom serializer (see
https://code.google.com/p/libgdx/wiki/JsonParsing#Customizing_serialization)
that knows how to save a (Mission) instance and knows the appropriate
constructor to invoke when reading a (Mission) back in.
public Mission() {
// Do nothing.
}
Reading & writing JSON
The class implementing Json.Serializable must have a zero argument
constructor because object construction is done for you.
Alternatively delete the unused constructor. I think Enigo answer is also correct so I'm going to upvote his answer.
Providing Constructors for Your Classes
You don't have to provide any constructors for your class, but you
must be careful when doing this. The compiler automatically provides a
no-argument, default constructor for any class without constructors.
This default constructor will call the no-argument constructor of the
superclass. In this situation, the compiler will complain if the
superclass doesn't have a no-argument constructor so you must verify
that it does. If your class has no explicit superclass, then it has an
implicit superclass of Object, which does have a no-argument
constructor.
Note: I didn't test our responses, I have not developed games or used libgdx in the last two years.
Also read this libgdx issue: Json - constructor default value with Enum:
I don't know if this would be called a bug but, I have a case where I
have an enum like this;
Then I have a class with 2 constructors;
This second gets called by my framework, the first by Json
deserialization.
...
Previous response:
I guess that the missing progress field in some Mission classes can be the source of the issue but would be interesting to read the error logs to be sure.
I followed this, this and this to confirm this but it's hard without extra information about the exact log error.
I'm trying to implement a somewhat general converter, which transforms the data based on a given annotation. Say I want to transform these annotated strings in any matter.
All is well, until the code hits my converter's "matches" method. The "sourceType" I'm getting is always stripped out of all of the useful information. Has anyone had any success with such a setup, or am I missing something?
public class TestStringWriteConverter implements ConditionalGenericConverter {
#Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
if (sourceType.hasAnnotation(GivenAnnotation.class)) {
//->never gets executed, because sourceType is being stripped out of it's useful infos
}
I followed the problem to MappingMongoConverter from this package org.springframework.data.mongodb.core.convert
protected void writeInternal(Object obj, final DBObject dbo, MongoPersistentEntity<?> entity) {
//...
if (null != propertyObj) {
if (!conversions.isSimpleType(propertyObj.getClass())) {
writePropertyInternal(propertyObj, dbo, prop);
} else {
// I always end up here, which is correct but the whole prop object is being omitted in favor of the getFieldName() property
writeSimpleInternal(propertyObj, dbo, prop.getFieldName());
}
}
}
The spring versions I'm using:
<spring.version>3.2.5.RELEASE</spring.version>
<spring.data.version>1.3.2.RELEASE</spring.data.version>
Any help is much appreciated.
I think you misunderstand what sourceType.hasAnnotation(…) actually returns. As the name suggests, it inspects the type for annotations. So for a given type like this:
#MyAnnotation
class Foo { }
it would allow you to find #MyAnnotation. However you are writing about "annotated strings". I assume you mean something like:
class Bar {
#MyAnnotation
String property;
}
This is not a type annotation and the Converter API is not meant to cover such cases. If you think supporting such scenarios would be worthfile, please file a JIRA ticket.
I'm looking at using oData endpoints in my Silverlight client. Naturally, I'm doing MVVM and I want the project to be nice and "Blendable" (i.e. I must be able to cleanly use static data instead of the oData endpoints when in design mode.)
Now to the problem. I'd like to use the DataServiceCollection in my ViewModels, since it allows for nice bindable collections without having to worry too much with BeginExecute/EndExecute etc.
Now, let's look at some code. My Model interface looks like this:
public interface ITasksModel
{
IQueryable<Task> Tasks { get; }
}
The oData endpoint implementation of that interface:
public class TasksModel : ITasksModel
{
Uri svcUri = new Uri("http://localhost:2404/Services/TasksDataService.svc");
TaskModelContainer _container;
public TasksModel()
{
_container = new TaskModelContainer(svcUri);
}
public IQueryable<Task> Tasks
{
get
{
return _container.TaskSet;
}
}
}
And the "Blendable" design-time implementation:
public class DesignModeTasksModel : ITasksModel
{
private List<Task> _taskCollection = new List<Task>();
public DesignModeTasksModel()
{
_taskCollection.Add(new Task() { Id = 1, Title = "Task 1" });
_taskCollection.Add(new Task() { Id = 2, Title = "Task 2" });
_taskCollection.Add(new Task() { Id = 3, Title = "Task 3" });
}
public IQueryable<Task> Tasks
{
get {
return _taskCollection.AsQueryable();
}
}
}
However, when I try to use this last one in my ViewModel constructor:
public TaskListViewModel(ITasksModel tasksModel)
{
_tasksModel = tasksModel;
_tasks = new DataServiceCollection<Task>();
_tasks.LoadAsync(_tasksModel.Tasks);
}
I get an exception:
Only a typed DataServiceQuery object can be supplied when calling the LoadAsync method on DataServiceCollection.
First of all, if this is the case, why not make the input parameter of LoadAsync be typed as DataServiceQuery?
Second, what is the "proper" way of doing what I'm trying to accomplish?
The reason LoadAsync requires DataServiceQuery is that just plain IQueryable doesn't define asynchronous way of executing the query. The reason the method takes IQueryable type as its parameter is so that users don't have to cast the query object to DataServiceQuery explicitely (makes the code shorter) and since we assume that users will try to run their code at least once, they would see the error immediately (as you did).
LoadAsync only supports asynchronous operations, so it needs the DataServiceQuery. If you already have the results (without a need to execute async request) you can call the Load method instead. Which is the answer to your second question. Instead of calling LoadAsync for both desing time and run time, you could use Load for design time and LoadAsync for run time. But due to tracking constrains you might need to create the DataServiceCollection in different way.
Something like this:
DataServiceCollection<Task> dsc;
DataServiceQuery<Task> dsq = _tasksModel as DataServiceQuery<Task>;
if (dsq != null)
{
dsc = new DataServiceCollection<Task>();
dsc.LoadAsync(dsq);
}
else
{
dsc = new DataServiceCollection<Task>(myDataServiceContext);
dsc.Load(_tasksModel);
// Invoke the LoadAsyncCompleted handler here
}
If you pass the DataServiceContext to the constructor before caling Load the entities will be tracked (just like in the LoadAsync case). If you don't need that you can call the constructor which takes IEnumerable and TrackingMode and turn off tracking on it.