Attribute Value Becomes "Method" Inside Proxy.new (Raku) - methods

I'm trying to understand why an attribute value is a Str (or whatever) outside of Proxy.new, but becomes Method inside of Proxy.new. I golfed my code down to this:
#!/usr/bin/env raku
class Foo does Associative {
has Str $.string;
multi method AT-KEY (::?CLASS:D: Str $key) is rw {
say "\nOutside of Proxy: { $!string.raku }";
say "Outside of Proxy: { $!string.^name }";
Proxy.new(
FETCH => method () {
say "FETCH: { $!string.raku }";
say "FETCH: { $!string.^name }";
},
STORE => method ($value) {
say "STORE: { $!string.raku }";
say "STORE: { $!string.^name }";
}
);
}
}
my $string = 'foobar';
my %foo := Foo.new: :$string;
%foo<bar> = 'baz';
say %foo<bar>;
This is the output:
$ ./proxy.raku
Outside of Proxy: "foobar"
Outside of Proxy: Str
STORE: method <anon> (Mu: *%_) { #`(Method|94229743999472) ... }
STORE: Method
Outside of Proxy: "foobar"
Outside of Proxy: Str
FETCH: method <anon> (Mu: *%_) { #`(Method|94229743999616) ... }
FETCH: Method
FETCH: method <anon> (Mu: *%_) { #`(Method|94229743999616) ... }
FETCH: Method
FETCH: method <anon> (Mu: *%_) { #`(Method|94229743999616) ... }
FETCH: Method
FETCH: method <anon> (Mu: *%_) { #`(Method|94229743999616) ... }
FETCH: Method
FETCH: method <anon> (Mu: *%_) { #`(Method|94229743999616) ... }
FETCH: Method
FETCH: method <anon> (Mu: *%_) { #`(Method|94229743999616) ... }
FETCH: Method
FETCH: method <anon> (Mu: *%_) { #`(Method|94229743999616) ... }
FETCH: Method
FETCH: method <anon> (Mu: *%_) { #`(Method|94229743999616) ... }
FETCH: Method
FETCH: method <anon> (Mu: *%_) { #`(Method|94229743999616) ... }
FETCH: Method
True
Can anyone explain what's going on here? Thanks!

The problem is that $!string is an empty container by the time the block is actually called. Even if it's declared in scope, by the time it's actually used $!str is really pointing to an anonymous method. Just add say $!string in your FETCH or STORE and you'll see that it contains an anonymous Block, printing <anon>.
If what you want is to work on attributes, check this other SO answer to see how it could be done.

Related

Why doesn't my NEAR smart-contract function return an object (AssemblyScript)?

I have a function in my smart contract that looks like this
index.ts
class MsgCode {
msg: string;
code: i32;
}
#nearBindgen
export class Contract {
getFoo(): MsgCode {
return {code: 0, msg: 'foo'};
}
getBar(): string {
return 'bar'
}
}
When I call this function through the near-api-js library like this, I'm not receiving anything from the result
contract = await new Contract(account, CONTRACT_NAME, {
viewMethods: ['getFoo', 'getBar'],
});
const getData = () => {
return contract.getFoo().then(res => console.log(res)); // prints nothing. Expect to print {msg:'foo', code:0}
return contract.getBar().then(res => console.log(res)); // prints bar
};
I'm expecting getFoo() to return {msg:'foo', code:0} when I call it on the client, but I receive nothing. What am I doing wrong?
The class type that we want to return from our function also needs to use the #nearBindgen annotation. Otherwise, it won't be serialized. https://docs.near.org/docs/develop/contracts/as/intro#models-define-new-types
#nearBindgen // Added annotation
class MsgCode {
msg: string;
code: i32;
}

Redux Saga performs yield multiple times

I'm fighting with strange behaviour of my saga.
The story is simple. User clicks the button and dispatch 'generateUserPassword' action.
My saga takes this action and should call password generation only once, but does it multiple times. I do not have backend for that, so i get 404 http response and catch an exception in saga. Then, generateUserPasswordFailed action is dispatched and handled in handleGenerationFailed()
function* generateUserPassword(action: GenerateUserPassword): unknown {
const request: PasswordGenerateRequest = { email: action.email }
try {
yield callPasswordGenerate(request)
yield put(userPasswordGenerated())
} catch (e) {
yield put(generateUserPasswordFailed())
}
}
function* handlePasswordGeneration(): unknown {
yield put(showInfoMessage('Hasło zostało wysłane do Ciebie smsem'))
}
function* handleGenerationFailed(): unknown {
yield put(showWarningAlert('Coś poszło nie tak. Spróbuj ponownie'))
}
export function* userPasswordSaga(): IterableIterator<ForkEffect> {
yield takeLatest(GENERATE_USER_PASSWORD, generateUserPassword)
yield takeLatest(GENERATE_USER_PASSWORD_FAILED, handleGenerationFailed)
yield takeLatest(USER_PASSWORD_GENERATED, handlePasswordGeneration)
}
In result, in console i see this:
As you see, DISPATCH_ALERT is called multiple times.
And 783 requests have been sent:
But why 783?
These are my actions:
export type GenerateUserPassword = {
type: typeof GENERATE_USER_PASSWORD
email: string
}
export type UserPasswordGenerated = {
type: typeof USER_PASSWORD_GENERATED
}
export type GenerateUserPasswordFailed = {
type: typeof GENERATE_USER_PASSWORD_FAILED
}
export const showWarningAlert = (alertKey: string, prefixKey?: string): DispatchAlert => ({
type: DISPATCH_ALERT,
alert: {
type: 'WARNING',
key: alertKey,
prefixKey
}
})
And here is http call:
export type PasswordGenerateRequest = {
email: string
}
export const callPasswordGenerate = async (request: PasswordGenerateRequest): Promise<unknown> => {
const response = await axios.post(`/passCreate`, request)
return response.data
}
It gets weirder, when I put console.log in my saga. It is called 782 times and i don't see any further actions dispatched.
function* generateUserPassword(action: GenerateUserPassword): unknown {
const request: PasswordGenerateRequest = { email: action.email }
console.log('generate user password called')
try {
yield callPasswordGenerate(request)
yield put(userPasswordGenerated())
} catch (e) {
yield put(generateUserPasswordFailed())
}
}
When i put console.log in catch clause:
function* generateUserPassword(action: GenerateUserPassword): unknown {
const request: PasswordGenerateRequest = { email: action.email }
try {
yield callPasswordGenerate(request)
yield put(userPasswordGenerated())
} catch (e) {
console.log('exception')
yield put(generateUserPasswordFailed())
}
}
It's logged only once:
Please help me to understand this.
Thanks in advance!

How to do a nested mutation resolver with nexus-prisma

I have the following datamodel:
type Job {
// ...
example: String
selections: [Selection!]
// ...
}
type Selection {
...
question: String
...
}
I define my object type so:
export const Job = prismaObjectType({
name: 'Job',
definition(t) {
t.prismaFields([
// ...
'example',
{
name: 'selections',
},
// ...
])
},
})
I do my resolver this way:
t.field('createJob', {
type: 'Job',
args: {
// ...
example: stringArg(),
selections: stringArg(),
// ...
},
resolve: (parent, {
example,
selections
}, ctx) => {
// The resolver where I do a ctx.prisma.createJob and connect/create with example
},
})
So now in the resolver I can receive the selections as json string and then parse it and connect/create with the job.
The mutation would look like this:
mutation {
createJob(
example: "bla"
selections: "ESCAPED JSON HERE"
){
id
}
}
I was wondering if there's anything more elegant where I could do something like:
mutation {
createJob(
example: "bla"
selections: {
question: "bla"
}
){
id
}
}
or
mutation {
createJob(
example: "bla"
selections(data: {
// ...
})
){
id
}
}
I've noticed that with nexus-prisma you can do stringArg({list: true}) but you can't really do objects.
My main question is what is the most elegant way to do either nested mutation or connect all in one.
You can use an inputObjectType as shown in the docs:
export const SomeFieldInput = inputObjectType({
name: "SomeFieldInput",
definition(t) {
t.string("name", { required: true });
t.int("priority");
},
});
Make sure to include the type as part of the types you pass to makeSchema. You can then use it to define an argument, like
args: {
input: arg({
type: "SomeFieldInput", // name should match the name you provided
}),
}
Now, the argument value will be available to your resolver as a regular JavaScript object, not a String. If you need a list of input objects, or want to make the argument required, you do so using the same options you would provide with when using a scalar -- list, nullable, description, etc.
Here's a complete example:
const Query = queryType({
definition(t) {
t.field('someField', {
type: 'String',
nullable: true,
args: {
input: arg({
type: "SomeFieldInput", // name should match the name you provided
}),
},
resolve: (parent, { input }) => {
return `You entered: ${input && input.name}`
},
})
},
})
const SomeFieldInput = inputObjectType({
name: "SomeFieldInput",
definition(t) {
t.string("name", { required: true });
},
});
const schema = makeSchema({
types: {Query, SomeFieldInput},
outputs: {
...
},
});
Then query it like:
query {
someField(
input: {
name: "Foo"
}
)
}
Or using variables:
query($input: SomeFieldInput) {
someField(input: $input)
}

Nested resolver in "graphql-tools" not working

I am not able to call nested resolvers using graphql-tools. I have filed bug on github but haven't got any reply yet.
https://github.com/apollographql/graphql-tools/issues/1026.
Nested fields of my schema are not getting called while querying.
Schema
type XYZ {
title: String
}
type NestedLevel1 {
reference: XYZ
}
type ABCD {
title: String
reference: XYZ
nestedLevel1: NestedLevel1
}
type Query {
ABCDList(limit: Int, skip: Int): [ABCD]
}
Resolvers
const Resolvers = {
Query: {
ABCDList: () => []
},
ABCD: {
reference: () => [] // this function is being called
nestedLevel1: {
reference: () => [] // this function is not being called
}
}
}
Resolver function of top level "reference" is being called but not "nestedLevel1.reference" resolver. Please correct me if I am doing something wrong.
I have figured out solution for above issue. Instead of providing field id(key) of type return Type of field should be used in nested resolver.
Following is solution which worked for me.
const Resolvers = {
Query: {
ABCDList: () => []
},
ABCD: {
reference: () => []
},
NestedLevel1: {
reference: () => []
}
}

Phoenix Channel: By every request, I receive a reply more than the previous

I programmed a small app (js) that get all the posts o a blog from the server (phoenix framework+PostgreSQL). The app is working, but at the nth call of the API, I get n replies instead of 1:
Joined successfully app.js:18747:10
client getAll call app.js:18698:8
client getAll reply, Object { posts: Array[3] } app.js:18694:10
client getAll call app.js:18698:8
client getAll reply, Object { posts: Array[3] } app.js:18694:10
client getAll reply, Object { posts: Array[3] } app.js:18694:10
client getAll call app.js:18698:8
client getAll reply, Object { posts: Array[3] } app.js:18694:10
client getAll reply, Object { posts: Array[3] } app.js:18694:10
client getAll reply, Object { posts: Array[3] }
That is: at the 3rd call I get 3 replied instead of 1.
Here the files: user_socket.ex:
defmodule Proto1.UserSocket do
use Phoenix.Socket, Phoenix.LongPoll
channel "blog", Proto1.BlogChannel
transport :websocket, Phoenix.Transports.WebSocket
transport :longpoll, Phoenix.Transports.LongPoll
def connect(_params, socket) do
{:ok, socket}
end
def id(_socket), do: nil
end
blog_channel.ex
defmodule Proto1.BlogChannel do
use Proto1.Web, :channel
def join("blog", _message, socket) do
{:ok, socket }
end
def handle_in("getAll", params, socket) do
IO.puts "Proto1.BlogChannel.handle_in \"all\" called"
posts = Repo.all(Proto1.Post)
push socket, "getAll", %{posts: for p <- posts do %{title: p.title, body: p.body} end }
{:noreply, socket}
end
end
And on the client (vue.js 2): The Endpoint:
defmodule Proto1.Endpoint do
use Phoenix.Endpoint, otp_app: :proto1
socket "/socket", Proto1.UserSocket
The socket:
import {Socket} from 'phoenix'
let socket = new Socket('/socket', {params: {token: window.userToken}})
socket.connect()
export default socket
Some code to manage the channel:
import socket from './socket'
class Blog {
// in the future the construcor will have a single parameter with the
// id of the blog, now we hava a single blog
constructor (blogId) {
this._blogId = blogId
this._channel = socket.channel('blog')
this.join()
this.initOn()
}
join () {
this._channel.join()
.receive('ok', resp => { console.log('Joined successfully') })
.receive('error', resp => { console.log('Unable to join') })
}
initOn () {
this._channel.on('all', payload => {
console.log('payload: ', payload)
})
}
getChannel () {
return this._channel
}
}
let BlogFactory = {
blogs: new Map(),
getBlog: function (blogId = 'default') {
if (this.blogs[blogId] === undefined) {
this.blogs[blogId] = new Blog(blogId)
}
return this.blogs[blogId]
}
}
export default BlogFactory
The data fetch:
[...]
methods: {
fetchData () {
this.error = this.posts = null
this.loading = true
var blog = BlogFactory.getBlog()
var c = blog.getChannel()
c.on('getAll', payload => {
console.log('client getAll reply, ', payload)
this.loading = false
this.posts = payload.posts
})
console.log('client getAll call')
c.push('getAll')
}
}
[...]
Changed client program after the answer of #Nicd (the following code works!):
<script>
// import BlogFactory from '../blog'
import socket from '../socket'
export default {
name: 'blog',
data () {
return {
loading: false,
posts: null,
error: null
}
},
created () {
this.channel = socket.channel('blog')
this.channel.join()
.receive('ok', resp => { console.log('Joined successfully') })
.receive('error', resp => { console.log('Unable to join') })
this.channel.on('getAll', payload => {
console.log('client getAll reply, ', payload)
this.loading = false
this.posts = payload.posts
})
this.fetchData()
},
methods: {
fetchData () {
this.error = this.posts = null
this.loading = true
console.log('client getAll call')
this.channel.push('getAll')
}
}
}
</script>
It seems that every time you call fetchData(), you are adding a new listener with the c.on('getAll', ...) call. So for every received message you run an increasing amount of listeners and that is why it looks like you received many messages.
You can check this with your browser's developer tools – at least Chromium based browsers allow you to inspect the WebSocket traffic to see that there is only one received message.

Resources