How to serialize enum in borsh-js - javascript

Trying to serialize an object in Rust and deserialize it in JS
We got 000100000031 hash, after serialization this:
pub enum Service {
Stackoverflow,
Twitter,
Telegram,
}
pub struct ServiceId {
pub service: Service,
pub id: ExternalId,
}
When trying to deserialize in JS use this:
const Service = {
Stackoverflow: 0,
Twitter: 1,
Telegram: 2
}
class ServiceId {
constructor(service, id) {
this.service = service
this.id = id
}
}
const value = new ServiceId(Service.Stackoverflow, userId)
const schema = new Map([
[ServiceId,
{ kind: 'struct', fields: [['service', 'u8'], ['id', 'string']] }]
]);
After deserialization, we got this, but it is incorrect because we have an object inside an object and a redundant id parameter:
ServiceId { service: { service: undefined, id: '1' }, id: undefined }
Firstly it could be because in Rust we have enum type, so how we can use enum in borsh-js.
Second if not, why do we have an incorrect results?

It is hard to understand from documentation, but you need to create your class like this and all will be okay.
class ServiceId {
constructor({ service, id }) {
this.service = service
this.id = id
}
}
new ServiceId({ service: 'lol', id: 'kek' })
So you need to pass your params as object.

Related

How to traverse a typed array?

I have the following class model in my application Angular:
export class IItemsModel {
public description: string;
public itemDetail: IItemDetailModel;
public itemCategories: IItemCategoriesModel[]; // array of IItemCategoriesModel
}
export class IItemCategoriesModel {
public id: string | number;
public description: string;
}
And my Controller:
itemModel: IItemsModel;
selectedCategories: any[] = [];
ngOnInit() {
this.itemModel = new IItemsModel();
this.itemModel.itemCategories = [];
}
onSubmit(form: NgForm) {
// here I format the data
}
In the template I have a multiple select where I fill an array with the id's of the chosen categories.
[25, 38] // selectedCategories
Problem, I'm using ngModel to link the form with the controler, but to send the pre-filled data to the API, I have to format the id's to the model format, that is:
{
...,
itemDetail: 'something',
itemCategories: [
{ id: any Id },
{ id: other Id }
]
}
I try to format the data as follows in the onSubmit() method:
for(let i=0; i<this.selectedCategories.length; i++) {
this.itemModel.itemCategories[i].id = this.selectedCategories[i];
}
But I get the error:
TypeError: Cannot set property 'id' of undefined # undefined:undefined
How could you be formatting the itemCategories to be able to send the data correctly to the API?
Use forEach to iterate instead of for loop.
this.selectedCategories.forEach(f => {
this.itemModel.itemCategories.push({ id: f, description: '' })
});
Since your selectedCategories object is an array of numbers, it doesn't have id property in it. That's why you're getting errors.
Working demo at StackBlitz.
Click the button and check the console log.

How to define and use a related Model in Objection.js

Using the following code (which uses ES6's "type":"module" in package.json), I can't seem to access the related Model Group:
import db from "../connection.js";
import objection from "objection";
const { Model } = objection;
Model.knex(db);
class User extends Model {
static get tableName() {
return "users";
}
static get relationMappings() {
return {
groups: {
relation: Model.ManyToManyRelation,
modelClass: Group,
join: {
from: "users.id",
through: {
from: "users_groups.user_id",
to: "users_groups.group_id",
},
to: "groups.id",
}
}
}
}
}
class Group extends Model {
static get tableName() {
return "groups";
}
}
If I run
const myUser = await User.query().findById(1)
It outputs:
User {id: 1, name: "r", email: "raj#raj.raj", username: "raj", … }
But I still can't access the Group relation:
myUser.groups
Outputs:
undefined
What am I doing wrong?
You have to use eager loading in the query to load the desired relations.
It you are using Objection.js v1:
const myUser = await User.query().eager('groups').findById(1)
And since Objection.js v2, eager was renamed as withGraphFetched:
const myUser = await User.query().withGraphFetched('groups').findById(1)
Extra: Loading relations after instantiation
You can load the relations after instantiation using $relatedQuery. Note all instance methods starts with $:
const myUser = await User.query().findById(1)
const groupsOfMyUser = await myUser.$relatedQuery('groups')

Angular5 - Error: Function DocumentReference.set() called with invalid data. Data must be an object, but it was: a custom PlatformModel object

I find allready some posts on google where people solve this problem. but i cant reproduce the solutions on my project.
My Interface:
declare module PlatformInterface {
export interface Design {
primaryColor: string;
backgroundImage: string;
}
export interface Saga {
id: string;
name: string;
short_desc: string;
desc: string;
manga: Manga[];
anime: Anime[];
}
export interface Root {
id: string;
name: string;
design: Design[];
saga: Saga[];
}
}
My Model:
export class PlatformModel implements PlatformInterface.Root {
id: string;
name: string;
design = [];
saga = [];
constructor(obj?: any) {
this.id = obj.name.toLowerCase().replace(' ', '-');
this.name = obj.name;
this.design = obj.design;
this.saga = obj.saga;
}
}
My Service:
#Injectable()
export class PlatformService {
public list$: Observable<PlatformModel[]>;
private _platform: AngularFirestoreCollection<PlatformModel>;
constructor(db: AngularFirestore) {
this._platform = db.collection<PlatformModel>('platforms');
this.list$ = this._platform.valueChanges();
}
/** Get Platform by id */
get(id: string): Observable<PlatformModel> {
return this._platform.doc<PlatformModel>(id).valueChanges();
}
/** Add / Update Platform */
set(id: string, platforms: PlatformModel) {
return fromPromise(this._platform.doc(id).set(platforms));
}
/** Remove Platform */
remove(id: string) {
return fromPromise(this._platform.doc(id).delete());
}
}
My function in Component.ts
constructor(public _platformService: PlatformService) {
}
addPlatform(name: string) {
if (name !== '') {
const platform = new PlatformModel({
name: name,
design: [],
saga: []
});
this._platformService.set(platform.id, platform).subscribe();
}
}
The Angular Compiler dont Throw any error, But when i try to fire the addPlatform Function i get in Browser this error:
ERROR Error: Function DocumentReference.set() called with invalid data. Data must be an object, but it was: a custom PlatformModel object
The Errors Says that the Data must be an object, but it is allready an object or not? i mean i define in the service it with:
public list$: Observable<PlatformModel[]>;
[] Makes it to an object or not?
I've found some clarification here Firestore: Add Custom Object to db
while firebase could send the data inside your object to the database, when the data comss back it cannot instantiate it back into an instance of your class. Therefore classes are disallowed
my workaround for custom class was
this.db.collection(`${this.basePath}/`).doc(custom_class.$key)
.set(Object.assign({}, JSON.parse(JSON.stringify(custom_class))))
.then( ret => {
log.debug('file added', ret);
}).catch( err => {
log.error(err);
});
so I guess in your case it would be
/** Add / Update Platform */
set(id: string, platforms: PlatformModel) {
return fromPromise(this._platform.doc(id).set(Object.assign({},JSON.parse(JSON.stringify(platforms))));
}
For adding a Map into Firestore document you'll have to use:
Object.assign({}, JSON.parse(JSON.stringify(YOUR_MAP)))

Object URL mapping in JavaScript / TypeScript / Angular4

I have a class for SearchFilter
class SearchFilter {
constructor(bucket: string,
pin: number,
qty: number,
category: string) {
}
}
When user hits search I'm filling in the filter to matrix params.
router.navigate(['filter', searchFilter]); //searchFilter is an instance
The URL looks like
filter;bucket=MPC123;category=JOINT;qty=90;pin=9087
This is being used in another component where the param is mapped back to an Object of type SearchFilter. But here the data types need to be set explicitly as far as I know.
const params = this.activatedRoute.snapshot.params;
const filter = this.getFilterFromParams(params);
getFilterFromParams(params) :SearchFilter {
const filter = new SearchFilter();
Object.keys(params).forEach((key) => {
switch(key) {
case 'pin':
case 'qty': filter[key] = Number(params[key]); break;
default: filter[key] = params[key];
}
});
return filter;
}
As seen from above code, to map the params back to Object a custom mapping function is written, the question is if there is any other obvious way this can be done or is this a common pattern?
I will have to depend on URL as users should be able to share URLs of different filters.
Adding a static factory method would work:
class SearchFilter {
constructor(
bucket: string,
pin: number,
qty: number,
category: string) {
}
public static fromParams({ bucket, pin, qty, category }) {
// TODO Add validation to ensure pin & qty are integers
return new SearchFilter(
bucket,
parseInt(pin),
parseInt(qty),
category);
}
}
Then we can use it like this:
const demoParams = {
bucket: "MPC123",
category: "JOINT",
qty: "90",
pin: "9087"
};
const filter = SearchFilter.fromParams(demoParams);
You could maybe go for the capabilities of Object.assign and the spread syntax:
getFilterFromParams(params) :SearchFilter {
return Object.assign(new SearchFilter(), params,
...['pin', 'qty'].map(key => key in params && { [key]: Number(params[key]) })
);
}

Angular2 Service call Model Method

I'm new to angular2 so I will try to make this question as clear as possible. I want to have a method in my model that I can call from my service. Right now I have it trying to replace the name.
Here is my model
export class Secret {
public name: string;
constructor (
public id: number,
public type: string,
public visible_data: any,
public secrets?: any,
public group_id?: number,
public group_name?: string
) {
this.name = this.myName();
}
public myName(): string {
return this.name = "whaddup"
}
}
and my service method
/*
* get secrets
*/
public getSecrets(): Promise<Secret[]> {
let tempArray = [];
return this.sdk.list_secrets()
.then((resp) => {
resp.map((item) => {
tempArray.push({
id: item.id,
name: this.secret.myName(),
type: item.type,
visible_data: {
"username": item.data
}
}); // end push
});
return tempArray;
})
.catch((err) => {
console.error(err);
});
}
list.component.ts code:
export class ListComponent implements OnInit {
public constantArray: Secret[];
private secrets: Secret[];
private secret: Secret;
constructor(private secretService: SecretService) { }
public ngOnInit() {
this.getSecrets();
}
public getSecrets() {
this.secretService.getSecrets()
.then((data) => {
this.secrets = data;
this.constantArray = data;
});
}
}
Instead of
tempArray.push({
id: item.id,
name: this.secret.myName(),
type: item.type,
visible_data: {
"username": item.data
}); // end push
You should do
tempArray.push(new Secret(item.id, ...));
Reason: in your original code, the object pushed to array are plain old javascript object and they are not typescript objects. The 'new ...' will create a real typescript class object.
To work with angular2 service, you need to do two things. First of all you need to at the #Injectable annotation on top of your services.
If you want to inject services into each other, you need to provide them on your NgModule like this:
#NgModule({
selector: 'my-app',
providers: [NameService]
}):
If you want to inject the service into another service/component you can just leverage typescript and use constructor injection like this:
constructor(private secretService: SecretService) {}

Categories