Unexpected error upon calling hook: Missing value for non-nullable field - graphql

I am trying to build a subgraph for Graph Protocol following the example here (the example with the more performant way). During compilation of my Graph protocol project using a testing tool matchstick-as ^0.5.0, I get the following error:
Igniting tests
nft-lottery
--------------------------------------------------
Enter the NFT Lottery:
thread 'main' panicked at '🆘 Unexpected error upon calling hook: Missing value for non-nullable field 'player' for an entity of type 'PlayerToLottery'.
wasm backtrace:
0: 0x331a - <unknown>!src/nft-lottery/handleNftLotteryEnter;
1: 0x3807 - <unknown>!start:tests/nft-lottery.test~anonymous|0~anonymous|0
Could anyone help me with this, please?
Here is my ./schema.graphql
type NftLottery #entity {
id: ID!
open: BigInt!
close: BigInt!
prize: BigInt!
players: [PlayerToLottery!]! #derivedFrom(field: "lottery")
requestId: BigInt
updatedAtTimestamp: BigInt
}
type Player #entity {
id: ID! # address
lotteries: [PlayerToLottery!]! #derivedFrom(field: "player")
}
type PlayerToLottery #entity {
id: ID! # Set playerAddress.toHexString() + lotteryId.toHexString()
player: Player!
lottery: NftLottery!
}
# events
type NftLotteryEnter #entity {
id: ID! # Set lotteryCounter + playerAddress
lotteryCounter: BigInt!
player: Bytes!
numberOfEntrances: [BigInt!]!
updatedAtTimestamp: BigInt
}
Here is my ./src/mapping.ts
function getIdFromEventAddressInt(par2: Address, par1: BigInt): string {
return par1.toHexString() + par2.toHexString()
}
export function handleNftLotteryEnter(event: NftLotteryEnterEvent): void {
/* if a PlayerToLottery does not exists, create it */
const playerLotteryId = getIdFromEventAddressInt(event.params.player, event.params.lotteryCounter)
let playerToLottery = PlayerToLottery.load(playerLotteryId)
if (!playerToLottery) {
playerToLottery = new PlayerToLottery(playerLotteryId)
playerToLottery.save()
}
/* if a player does not exist, create them */
const playerId = event.params.player.toHexString()
let player = Player.load(playerId)
if (!player) {
player = new Player(playerId)
player.save()
}
/* if a lottery does not exist, create it */
const itemId = event.params.lotteryCounter.toHexString()
let nftLottery = NftLottery.load(itemId)
if (!nftLottery) {
nftLottery = new NftLottery(itemId)
nftLottery.open = event.block.timestamp
nftLottery.close = BigInt.fromString("000000000000")
nftLottery.prize = BigInt.fromString(event.params.entranceFee.toString())
nftLottery.players = new Array<string>()
}
// update lottery data
nftLottery.prize.plus(event.params.entranceFee)
// update players
let arrPlayers = nftLottery.players
arrPlayers.push(event.params.player.toHexString())
nftLottery.players = arrPlayers
nftLottery.updatedAtTimestamp = event.block.timestamp
nftLottery.save()
}

Entity PlayerToLottery needs to have values assigned before saving it:
/* if a PlayerToLottery does not exists, create it */
const playerLotteryId = getIdFromEventAddressInt(event.params.player, event.params.lotteryCounter)
let playerToLottery = PlayerToLottery.load(playerLotteryId)
if (!playerToLottery) {
playerToLottery = new PlayerToLottery(playerLotteryId)
playerToLottery.player = event.params.player.toHexString()
playerToLottery.lottery = event.params.lotteryCounter.toHexString()
playerToLottery.save()
}
Credit goes to Maks#3349 at unit testing of Graph discord.

Related

Kotlin MVVM, How to get the latest value from Entity in ViewModel?

I have created an app where I try to insert a record with the latest order number increased by one.
The main function is triggered from Activity, however, the whole process is in my ViewModel.
Issue no 1, After I insert a new record the order by number is not updated.
Issue no 2, When I insert first record the order by number is null, for that reason I am checking for null and setting the value to 0.
My goal here is to get the latest order_by number from Entity in my ViewModel, increased by 1 and add that new number to my new record using fun addTestData(..).
Entity:
#Entity(tableName = "word_table")
data class Word(
#ColumnInfo(name = "id") val id: Int,
#ColumnInfo(name = "word") val word: String,
#ColumnInfo(name = "order_by") val orderBy: Int
Dao:
#Query("SELECT order_by FROM word_table ORDER BY order_by DESC LIMIT 1")
suspend fun getHighestOrderId(): Int
Repository:
#Suppress("RedundantSuspendModifier")
#WorkerThread
suspend fun getHighestOrderId(): Int {
return wordDao.getHighestOrderId()
}
ViewModel:
private var _highestOrderId = MutableLiveData<Int>()
val highestOrderId: LiveData<Int> = _highestOrderId
fun getHighestOrderId() = viewModelScope.launch {
val highestOrderId = repository.getHighestOrderId()
_highestOrderId.postValue(highestOrderId)
}
fun addTestData(text: String) {
for (i in 0..1500) {
getHighestOrderId()
var highestNo = 0
val highestOrderId = highestOrderId.value
if (highestOrderId == null) {
highestNo = 0
} else {
highestNo = highestOrderId
}
val addNumber = highestNo + 1
val word2 = Word(0, text + "_" + addNumber,addNumber)
insertWord(word2)
}
}
Activity:
wordViewModel.addTestData(text)

Does nearBindgen not support child classes?

When I try to store an instance of a class that is the child of a different class in a PersistentVector or PersistentSet, when I read the same data, the instance fields have their default values.
The same doesn't happen when storing a regular class.
Is this a known issue?
Minimal reproduceable code:
// index.ts
import { PersistentVector } from "near-sdk-as";
#nearBindgen
class Base {
constructor(
public value1: u64
) { }
}
#nearBindgen
class Child extends Base {
constructor(
value1: u64,
public value2: u64
) {
super(value1);
}
}
#nearBindgen
export class Contract {
private pers: PersistentVector<Base> = new PersistentVector<Base>("vec");
add(value1: u64, value2: u64): Child {
const c = new Child(value1, value2);
this.pers.pushBack(c);
return c;
}
get(): Array<Base> {
const res: Array<Base> = [];
for (let i = 0; i < this.pers.length; i++) {
res.push(this.pers[i]);
}
return res;
}
}
// index.unit.spec.ts
import { Contract } from "../assembly/index";
let cont: Contract
beforeEach(() => {
cont = new Contract();
})
describe("Contract", () => {
it("add returns correct value", () => {
const result = cont.add(7, 3);
expect(result.value1).toBe(7);
expect(result.value2).toBe(3);
});
it("get after add returns 1 correct value", () => {
cont.add(7, 3);
const results = cont.get();
expect(results).toHaveLength(1);
const result = results[0];
expect(result.value1).toBe(7);
});
})
It produces the following test output:
[Describe]: Contract
[Success]: ✔ add returns correct value
[Fail]: ✖ get after add returns 1 correct value
[Actual]: 0 as u64
[Expected]: 7 as u64
[Stack]: RuntimeError: unreachable
at node_modules/#as-pect/assembly/assembly/internal/assert/assert (wasm://wasm/00023e6a:wasm-function[52]:0xde9)
at node_modules/#as-pect/assembly/assembly/internal/Expectation/Expectation<u64>#toBe (wasm://wasm/00023e6a:wasm-function[138]:0x2d9c)
at start:src/minimal/__tests__/index.unit.spec~anonymous|1~anonymous|1 (wasm://wasm/00023e6a:wasm-function[176]:0x466a)
at node_modules/#as-pect/assembly/assembly/internal/call/__call (wasm://wasm/00023e6a:wasm-function[179]:0x4690)
[File]: src/minimal/__tests__/index.unit.spec.ts
[Groups]: 2 pass, 2 total
[Result]: ✖ FAIL
[Snapshot]: 0 total, 0 added, 0 removed, 0 different
[Summary]: 1 pass, 1 fail, 2 total
[Time]: 2.333ms

Kotlin entered value not searching database

We have worked on this code to error trap a value entered in a Edit Text field
When the value is entered correctly we are informed that the entered value does not match
BUT if we select the value from a recycler view list and populate the Edit Text field with the value the search tells us we have a match
Here is the code for the search in the DBHelper
fun getOneName(id: Int): Contact? {
val db = this.writableDatabase
val selectQuery = "SELECT * FROM $TABLE_NAME WHERE $colId = ?"
db.rawQuery(selectQuery, arrayOf(id.toString())).use { // .use requires API 16
if (it.moveToFirst()) {
val result = Contact(id = 0,name ="")
result.id = it.getInt(it.getColumnIndex(colId))
result.name = it.getString(it.getColumnIndex(colName))
return result
}
}
return null
}
We used this for the Model Class our first time using data class as just plain class
data class Contact (
var id: Int,
var name: String
)
And here is the button click that manages the search
btnGetID.setOnClickListener {
if(etPerson.text.toString().trim().isNullOrEmpty()){
message("Enter Contact Name")
return#setOnClickListener
}
var numeric = true
var string = etPerson.text.toString().trim()
numeric = string.matches(".*\\d+.*".toRegex())
if(numeric){
message("No NUMBERS")
return#setOnClickListener
}
val dbManager = DBHelper(this)
var name = etPerson.text.toString()
//val contact = dbManager.getOneName(name)
val contact = dbManager.getOneName(id.toInt())
if(contact?.name.equals(name)){
println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! contact ID= "+contact)
etPerson.setText("The contact name is $name the ID is "+contact?.id.toString())
}else{
etPerson.setText("Name NOT = to $name and the ID is "+contact?.id.toString())
}
}
We know the name Sally is in the DB if we type Sally in the else statement shows Name NOT = bla
If we select Sally from the Recyclerview List the first statement shows The contact name bla bla
Kotlin 1.2.71 API 27
Our question is why is the hand typed name failing if it mataches?
HERE IS THE CORRECT CODE FOR THE DBHelper
fun getOneName(name: String): Contact? {
val db = this.writableDatabase
val selectQuery = "SELECT * FROM $TABLE_NAME WHERE $colName = ?"
db.rawQuery(selectQuery, arrayOf(name)).use { // .use requires API 16
if (it.moveToFirst()) {
val result = Contact(id = 0,name ="")
result.id = it.getInt(it.getColumnIndex(colId))
result.name = it.getString(it.getColumnIndex(colName))
return result
}
}
return null
}

How to call Expression Func with two input parameters

I have following Expression Func which is receiving two input paramters, first is Person Object, second is bool and returning another type of Object PersonProfile
private Exression<Func<Person, bool, PersonProfile>> PersonProfileProjection => (person, isValid) =>
new PersonProfile
{
FirstName = person.FirstName,
HasAddress = isValid ? person.Address1 : null
};
And I am trying to call this while fetching Person table from dbContext.
_dbContext.Persons.Select(PersonProfileProjection);
I am confused how to send boolean parameter inside PersonProfileProjection. It works when I only put one input and one output parameter like this. But I want extra boolean input as well.
Any help would be highly appreciated.
You can follow Microsoft documentation for this : Expression Class
One sample created for SQLite that show above function usage.
public void GetData()
{
var connection = new SQLiteConnection(#"Data Source=database.sqlite;Version=3;");
var context = new DataContext(connection);
connection.Open();
var createtableQuery = #"
drop table Company;
CREATE TABLE[Company]
(
[ID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
[Seats] INTEGER NOT NULL
);
";
var command = new SQLiteCommand(createtableQuery, connection);
command.ExecuteNonQuery();
Company com = new Company()
{
Id = 6,
Seats = 7
};
context.GetTable<Company>().InsertOnSubmit(com);
context.SubmitChanges();
var companies = context.GetTable<Company>();
foreach (var company in companies)
{
Console.WriteLine("Company: {0} {1}",
company.Id, company.Seats);
}
//compile Expression using Compile method to invoke it as Delegate
Func<int,int, Company> PersonProfileProjectionComp = PersonProfileProjection.Compile();
var dd = companies.Select(p => PersonProfileProjectionComp(p.Id,p.Seats));
//// Below line inline use. Both works.
//var dd = companies.Select(p => PersonProfileProjection.Compile().Invoke(p.Id,p.Seats));
}
private System.Linq.Expressions.Expression<Func<int, int, Company>> PersonProfileProjection => (person, seats) =>
new Company
{
Id = person,
Seats = seats
};
or in one line use this :
PersonProfileProjection.Compile().Invoke(person, isValid)
You could declare it as a Func instead of an expression:
private Func<Person, bool, PersonProfile> PersonProfileProjection => (person, isValid) =>
new PersonProfile
{
FirstName = person.FirstName,
HasAddress = isValid // do what you meant to do
};
... and call it as:
_dbContext.Persons.Select(p => PersonProfileProjection(p, true));
You could as well write an ordinary method:
private PersonProfile PersonProfileProjection(Person person, bool isValid)
{
return new PersonProfile
{
FirstName = person.FirstName,
HasAddress = isValid // do what you want to do
};
}
...and call it the same way:
_dbContext.Persons.Select(p => PersonProfileProjection(p, true));

Why the warning: "Constant <name> inferred to have type (), which may be unexpected"?

I'm attempting to sort an array of instantiated items of the class: "Employees".
However I'm getting the following error within my playground:
Here's the code as written in my playground:
class Employee {
var firstName:String = ""
var lastName:String = ""
init(fName:String, lName:String) {
self.firstName = fName
self.lastName = lName
}
}
var employees = [Employee]()
// 1)
var employee = Employee(fName: "Ric", lName: "Lee")
employees.append(employee)
// 2)
employee = Employee(fName: "Ralph", lName: "Knott")
employees.append(employee)
// 3)
employee = Employee(fName: "Joe", lName: "Smirf")
employees.append(employee)
// 4)
employee = Employee(fName: "Meredith", lName: "Lind")
employees.append(employee)
// 5)
employee = Employee(fName: "Aarnald", lName: "Zingerhost")
employees.append(employee)
let sortedEmployees = employees.sort { (e1:Employee, e2:Employee) -> Bool in
e1.lastName < e2.lastName
}
What am I missing here?
Why the warning?
The reason is that you are using the wrong function (former sortInPlace):
In Swift 3
sort() has been renamed to sorted()
sortInPlace() has been renamed to sort()
Therefore it's
let sortedEmployees = employees.sorted { (e1:Employee, e2:Employee) -> Bool in
e1.lastName < e2.lastName
}
Source: Swift Evolution: Apply API Guidelines to the Standard Library
try declaring
let sortedEmployees = employees.sort { (e1:Employee, e2:Employee) -> Bool in
e1.lastName < e2.lastName}
as
let sortedEmployees : () = employees.sort { (e1:Employee, e2:Employee) -> Bool in
e1.lastName < e2.lastName}

Resources