-
Notifications
You must be signed in to change notification settings - Fork 23
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
👋🏽 Are you using Morphism for a project or a library ? Please share the way you use it. #35
Comments
Hello, I am using to convert Angular Reactive Forms to model types. My form object contains {
doc: "123",
nameNickname: "gvsouza"
} My model is class User {
// nameNickname map to :1 of these two bellow, depending of the value of doc
// if doc.length is > 3, maps to name else maps to nickname
name?: string;
nickname?: string;
// doc maps to one of these two fields bellow (if doc.length>3 ? rg : ft)
rg?: string;
ft?: string;
} For the input example I gave, I wanted: {
ft: "123",
nickname: "gvsouza"
} Still trying to figure out a way |
The way I solved is having a function that returns a schema depending on the doc value of the form. fromSchema() {
let schema = {};
if (this.form.get('doc').value.length > 3) {
schema = {
rg: 'doc',
name: 'nameNickname',
};
} else {
schema = {
ft: 'doc',
nickname: 'nameNickname'
};
}
return morphism(schema, this.form.value);
} I personally don't like it, I would rather have the schema not add the field if I don't return a value from a function. const schema = {
ft: (i, s, d) => {
if (i.doc.length <= 3) {
return i.doc;
}
},
rg: (i, s, d) => {
if (i.doc.length > 3) {
return i.doc;
}
},
nickname: (i, s, d) => {
if (i.doc.length <= 3) {
return i.nameNickname;
}
},
name: (i, s, d) => {
if (i.doc.length > 3) {
return i.nameNickname;
}
},
}; Don't know which one is worse...Is there another way? |
Hello @gvsouza, thank you for sharing your experience with I would prefer using the second approach too. You can make it a bit less verbose using ES6 destructuring https://repl.it/@yrnd1/PhonyHeartfeltPattern const input = {
doc: "123",
nameNickname: "gvsouza"
}
const schema = {
ft: ({ doc }) => doc.length <= 3 ? doc : null,
rg: ({ doc }) => doc.length > 3 ? doc: null,
nickname: ({ doc, nameNickname }) => doc.length <= 3 ? nameNickname: null,
name: ({ doc, nameNickname }) => doc.length > 3 ? nameNickname: null,
};
const output = morphism(schema, input)
// =>
// {
// "ft": "123",
// "rg": null,
// "nickname": "gvsouza",
// "name": null
// } I would use the first approach if having 2 target models would make more sense, for example:
|
The thing is, I didn't want the extra |
@gvsouza This is much appreciated! Don't hesitate to share it around you or ask questions whenever you need it. Thank you! 😃 |
Running into the same issue as @gvsouza. I wonder does a special string constant to remove a key make sense? import { REMOVE_KEY } from 'morphism';
const schema = {
ft: ({ doc }) => doc.length <= 3 ? doc : REMOVE_KEY,
rg: ({ doc }) => doc.length > 3 ? doc: REMOVE_KEY,
nickname: ({ doc, nameNickname }) => doc.length <= 3 ? nameNickname : REMOVE_KEY,
name: ({ doc, nameNickname }) => doc.length > 3 ? nameNickname : REMOVE_KEY,
}; |
@davej I understand the point. What do you think if I add a new option to the schema allowing to strip |
Perfect, thanks Yann. |
Hi @emyann Fantastic library you have here. I am using it to keep an internal business object that we have defined, in sync with a flattened out UI object that we are using for React application state. This way we can design an internal object that can work with multiple applications (and not care about any specific UI needs), and we can morph that object into a different UI state depending on the needs of the specific application. Paired with the useEffect hook I am always able to keep a version of our business object in sync with the UI specific state. This makes it really easy to post the updated business object to the server without transforming on the fly. Thanks again for being generous with your time and building this library. I look forward to using it more. |
@aslaker Thank you for this feedback! 🙏🏽 So glad to hear how Morphism helps you with your use case, I would be happy if you're able to share a code snippet of how you use it with a useEffect hook. Thanks! |
@emyann below is a snippet that shows how I am using it with useEffect (with some pseudo-ish code). This way the currentBusinessObject is always in a ready-to-post state whenever the user is done making changes. I have an additional file that defines the mapping (a lot of it is one to one, but some of them require a mapping function) The next step that I may take is raise the logic one level higher into my axios instance config, and use Morphism as middleware. Let me know if you have any questions, or suggestions for using Morphism in a better way. const businessObjectResponse = await fetchComplexBusinessObject();
const [currentUIState, setCurrentUIState] = useState({})
const [currentBusinessObject, setCurrentBusinessObject] = useState({...businessObjectResponse})
useEffect(() => {
let uiStateCopy = makeDeepClone(currentUIState);
let updatedBusinessObject = morphism(UIToBusinessObjectSchema, uiStateCopy);
setCurrentBusinessObject(updatedBusinessObject)
}, [currentUIState]) |
@aslaker Thanks for sharing! Do you think it would be valuable to have a |
@emyann I think that a react-morphism package might have some merit. Especially if it can expose some sort of watch function or event. I'd have to think on that a bit more to see what problems a package like that could solve. The makeDeepClone is in there because the uiState is a large somewhat nested object. It just uses lodash under the hood. I wasn't sure if morphism performs a deep copy during the transformation, so I wanted to make sure the original object remains immutable as it should be completely separate from the business object without any left over references. |
@emyann Thanks for creating Morphism! We are currently using it in a REST API which runs on AWS Lambda. The API is responsible for syncing data between 2 backends. The original backend was made for a website that was developed a while ago. The new backend (AWS) powers a React Native app made with Amplify. The 2 backends use different databases. The app uses DynamoDB (NoSQL) and the original backend (made for the website) uses an SQL based database. Since the 2 databases are not 100% identical, some of the attribute names in the NoSQL tables can differentiate from the corresponding SQL table column name. Because of the mismatch in names, and sometimes data shape/structure, we use Morphism to transform the data. Besides Morphism, we're using ajv for JSON validation. The reason we're using ajv on top of Morphism is because we need to be able to validate value types (string, int etc.), provide defaults for missing fields, and specify which fields are required. Some questions I've gathered after using Morphism for a while: 1. Is there way to remove null and undefined keys with Morphism?I saw how to remove undefined keys in your comment, but don't know how to achieve the same for null. Use case: 2. How do you transform a source but keep all other keys and values that weren't included in the target?Use case: Let's say I have a large data structure and would like to only transform 2 keys. Preferably I would define a schema with only those 2 keys and still end up with all the other keys that weren't included in the schema in my output. Here's an example: const source = {
id: 123,
user_id: 1,
another_field1: 'test',
another_field2: 'test',
another_field3: 'test',
another_field4: 'test',
another_field5: 'test',
};
const schema = {
external_id: 'id',
owner_id: 'user_id',
};
const result = morphism(schema, source); I would like the result to end up like this: {
external_id: 123,
owner_id: 1,
another_field1: 'test',
another_field2: 'test',
another_field3: 'test',
another_field4: 'test',
another_field5: 'test',
} I know I can use the spread operator to achieve the same thing, but I would still have to ignore/delete the keys that did get morphed: const source = {
id: 123,
user_id: 1,
another_field1: 'test',
another_field2: 'test',
another_field3: 'test',
another_field4: 'test',
another_field5: 'test',
};
const schema = {
external_id: 'id',
owner_id: 'user_id',
};
const result = morphism(schema, source);
// Still contains id and user_id
const merged = { ...source , ...result };
// Ignore id and user_id from merged
// The variable final is the result we want
const { id, user_id, ...final } = merged; One final note: Our data structures can be relatively deep. Sometimes 3 or 4 nested objects and/or arrays or combinations. Would it be possible to add more examples for nested data, or is it recommended to write different schemas for each level? For example, imagine a trip object which has the following sub objects, each with data to transform and validate: trip -> destination -> hotels -> rooms Taking the example above, sometimes a certain sub object isn't present: trip -> destination -> I couldn't really find out from the docs how to handle such cases. |
Hi, thanks for this library, used it for the first time. I really like it works well with TypeScript. One issue which required some post-processing is partial objects: interface Source {
foo: any;
bar: any;
baz: any;
}
interface Dest {
myFoo: any;
myBar: any;
myBaz: any;
}
const schema = {
myFoo: 'foo',
myBar: 'bar',
myBaz: 'baz'
}; And I want to map const source = { foo: 'my-foo-value', bar: undefined };
const result = morphism(createSchema<Partial<Dest>, Partial<Source>>(schema), source);
console.log(result);
// output
{
myFoo: 'my-foo-value',
myBar: undefined,
myBaz: undefined,
} But I would like only: {
myFoo: 'my-foo-value',
myBar: undefined,
} |
Last time, I was thinking about adding more real use cases to the documentation. According to npm, there is a certain amount of downloads, I was wondering how and for what do you use
Morphism
Please share you usage or any relevant public link.
example: #33 (comment)
The text was updated successfully, but these errors were encountered: