-
Notifications
You must be signed in to change notification settings - Fork 41
generate metadata #145
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
base: main
Are you sure you want to change the base?
generate metadata #145
Conversation
patmood
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @jackyscript,
Thanks for the PR! Overall looks good, can you please address the comments and add some tests for the new behavior?
src/lib.ts
Outdated
| parts.push(`min: ${field.min}`) | ||
| } | ||
| if (typeof field.max === "number" && field.max !== 0) { | ||
| parts.push(`max: ${field.max}`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about other fields? eg maxSelect, maxSize, required?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I think this pull request currently only addresses text input field types:
const fieldsToIgnore = ["id", "password", "tokenKey", "token"]
const textBasedTypes = ["text", "email", "url", "number"]
const metadata = schema
.filter((field) => {
if (field.system || fieldsToIgnore.includes(field.name)) return false
if (!textBasedTypes.includes(field.type)) return false
})I gather maxSelect and maxSize apply for relation fields and json fields respectively. Do you think we should add them here with this pull request too? Or should we add those in a subsequent PR, what do you think? I will add the required metadata though now, as this is useful for validation too.
Edit, see my answer in the next comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nevermind, for the sake of illustrating the metadata content, I included all fields in and discarded the current filter, then there is a lot of metadata outputted (see below). Should we keep that or skip over some of the metadata?
I think we could use some degree of filtering, as I feel we do not need everything in the frontend or the metadata generated is already provided elsewhere (for instance the select field values).
EDIT: After I reflected on this for a while, I think generally this is fine and it is consistent with the output of the pocketbase-types.ts file. Maybe for the time being, we could remove the select field values output, as this is already provided with the current enum Options types in pocketbase-types.ts. In a later PR we could merge them, i.e. in the Metadata we reference the Options accordingly. What do you think?
/**
* This file was @generated using pocketbase-typegen
*/
export const AuthoriginsFieldMetadata = {
id: {
min: 15,
max: 15,
required: true,
pattern: "^[a-z0-9]+$",
},
collectionRef: {
required: true,
},
recordRef: {
required: true,
},
fingerprint: {
required: true,
},
created: {
onCreate: true,
onUpdate: false,
},
updated: {
onCreate: true,
onUpdate: true,
},
} as const
export const ExternalauthsFieldMetadata = {
id: {
min: 15,
max: 15,
required: true,
pattern: "^[a-z0-9]+$",
},
collectionRef: {
required: true,
},
recordRef: {
required: true,
},
provider: {
required: true,
},
providerId: {
required: true,
},
created: {
onCreate: true,
onUpdate: false,
},
updated: {
onCreate: true,
onUpdate: true,
},
} as const
export const MfasFieldMetadata = {
id: {
min: 15,
max: 15,
required: true,
pattern: "^[a-z0-9]+$",
},
collectionRef: {
required: true,
},
recordRef: {
required: true,
},
method: {
required: true,
},
created: {
onCreate: true,
onUpdate: false,
},
updated: {
onCreate: true,
onUpdate: true,
},
} as const
export const OtpsFieldMetadata = {
id: {
min: 15,
max: 15,
required: true,
pattern: "^[a-z0-9]+$",
},
collectionRef: {
required: true,
},
recordRef: {
required: true,
},
password: {
required: true,
},
created: {
onCreate: true,
onUpdate: false,
},
updated: {
onCreate: true,
onUpdate: true,
},
sentTo: {
required: false,
},
} as const
export const SuperusersFieldMetadata = {
id: {
min: 15,
max: 15,
required: true,
pattern: "^[a-z0-9]+$",
},
password: {
min: 8,
required: true,
},
tokenKey: {
min: 30,
max: 60,
required: true,
},
email: {
required: true,
},
emailVisibility: {
required: false,
},
verified: {
required: false,
},
created: {
onCreate: true,
onUpdate: false,
},
updated: {
onCreate: true,
onUpdate: true,
},
} as const
export const BaseFieldMetadata = {
id: {
min: 15,
max: 15,
required: true,
pattern: "^[a-z0-9]+$",
},
field: {
required: false,
},
created: {
onCreate: true,
onUpdate: false,
},
updated: {
onCreate: true,
onUpdate: true,
},
} as const
export const CustomAuthFieldMetadata = {
id: {
min: 15,
max: 15,
required: true,
pattern: "^[a-z0-9]+$",
},
password: {
min: 8,
required: true,
},
tokenKey: {
min: 30,
max: 60,
required: true,
},
email: {
required: true,
},
emailVisibility: {
required: false,
},
verified: {
required: false,
},
custom_field: {
required: false,
},
created: {
onCreate: true,
onUpdate: false,
},
updated: {
onCreate: true,
onUpdate: true,
},
} as const
export const EverythingFieldMetadata = {
id: {
min: 15,
max: 15,
required: true,
pattern: "^[a-z0-9]+$",
},
text_field: {
required: false,
},
number_field: {
required: false,
},
bool_field: {
required: false,
},
email_field: {
required: false,
},
url_field: {
required: false,
},
date_field: {
required: false,
},
select_field: {
maxSelect: 1,
required: false,
values: ["optionA","optionA","OptionA","optionB","optionC","option with space","sy?mb@!$"],
},
json_field: {
maxSize: 2000000,
required: false,
},
another_json_field: {
maxSize: 2000000,
required: false,
},
file_field: {
maxSelect: 1,
required: false,
},
three_files_field: {
maxSelect: 99,
required: false,
},
user_relation_field: {
maxSelect: 1,
required: false,
},
custom_relation_field: {
maxSelect: 999,
required: false,
},
select_field_no_values: {
required: false,
},
rich_editor_field: {
required: false,
},
post_relation_field: {
maxSelect: 1,
required: false,
},
geopoint_field: {
required: false,
},
created: {
onCreate: true,
onUpdate: false,
},
updated: {
onCreate: false,
onUpdate: true,
},
} as const
export const MyViewFieldMetadata = {
id: {
required: true,
pattern: "^[a-z0-9]+$",
},
post_relation_field: {
maxSelect: 1,
required: false,
},
text_field: {
required: false,
},
json_field: {
maxSize: 2000000,
required: false,
},
} as const
export const PostsFieldMetadata = {
id: {
min: 15,
max: 15,
required: true,
pattern: "^[a-z0-9]+$",
},
nonempty_field: {
required: true,
},
nonempty_bool: {
required: true,
},
field1: {
required: false,
},
created: {
onCreate: true,
onUpdate: false,
},
updated: {
onCreate: false,
onUpdate: true,
},
} as const
export const UsersFieldMetadata = {
id: {
min: 15,
max: 15,
required: true,
pattern: "^[a-z0-9]+$",
},
password: {
min: 8,
required: true,
},
tokenKey: {
min: 30,
max: 60,
required: true,
},
email: {
required: true,
},
emailVisibility: {
required: false,
},
verified: {
required: false,
},
name: {
max: 255,
required: false,
},
avatar: {
maxSelect: 1,
mimeTypes: ["image/jpeg","image/png","image/svg+xml","image/gif","image/webp"],
required: false,
},
created: {
onCreate: true,
onUpdate: false,
},
updated: {
onCreate: true,
onUpdate: true,
},
} as constThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example the EverythingCollectionsMetadata could look like this (in a separate PR):
...
export const EverythingFieldMetadata = {
id: {
min: 15,
max: 15,
required: true,
pattern: "^[a-z0-9]+$",
},
text_field: {
required: false,
},
number_field: {
required: false,
},
bool_field: {
required: false,
},
email_field: {
required: false,
},
url_field: {
required: false,
},
date_field: {
required: false,
},
select_field: {
maxSelect: 1,
required: false,
values: EverythingSelectFieldOptions,
},
json_field: {
maxSize: 2000000,
required: false,
},
another_json_field: {
maxSize: 2000000,
required: false,
},
file_field: {
maxSelect: 1,
required: false,
},
three_files_field: {
maxSelect: 99,
required: false,
},
user_relation_field: {
maxSelect: 1,
required: false,
},
custom_relation_field: {
maxSelect: 999,
required: false,
},
select_field_no_values: {
required: false,
},
rich_editor_field: {
required: false,
},
post_relation_field: {
maxSelect: 1,
required: false,
},
geopoint_field: {
required: false,
},
created: {
onCreate: true,
onUpdate: false,
},
updated: {
onCreate: false,
onUpdate: true,
},
} as const
export enum EverythingSelectFieldOptions {
"optionA" = "optionA",
"OptionA" = "OptionA",
"optionB" = "optionB",
"optionC" = "optionC",
"option with space" = "option with space",
"sy?mb@!$" = "sy?mb@!$",
}
...|
@patmood thank you for your feedback, I adjusted the PR accordingly and added some tests. There is an open question left regarding the content of the EDIT: Additionally when I created the tests, typescript requested me to add the properties |
|
Hey @jackyscript, after seeing the latest version with all fields, I realise it's exposing a lot of your schema in JS. I think a better option is to fetch the collection from the API on the client (if it has permission), and use the data from that to validate. If there's no user permission, you could have a simple script in your project to fetch the collections and filter them by only the collection/fields you want. How does that sound? |
|
Hi @patmood thank you for your thoughts, I can see your concerns regarding information exposure. Given I had a very specific use case in mind, this approach here seems to be a bit too much also for the scope of this project, I will go with your script idea, that way, frontend developers can utilize the metadata for validation right away. Let us close this pull request then, again thank you for your feedback and review. |
#143
Hi @patmood, refering to the issue #143 here. This is an attempt to defer field length metadata from pocketbase to use for example input validation in the frontend. Basically I wanted to provide the possibility to validate field input data in the frontend using the metadata given in the pocketbase backend.
I am not very confident that this handles every edge case, I think this pull request could benefit from more tests.
When quickly testing this locally I did the following:
Everythingcollection in thetest/pb.schema.jsonfile locally and set themaxproperty to350(just for the sake of an example)npm run buildnode dist/index.js --json ./test/pb_schema.json --out ./pocketbase-types.ts --constraintsThe result is a file called
pocketbase-types.constraints.ts(you can adjust the filename using cli param--constraintsOut):For context: When working in the frontend with validation you could use this generated metadata to setup the
maxLengthproperty of an input field or some validation logic, that the input does not exceed a certain text length, just as an example:I hope this is somewhat useful. feel free to leave questions and comments, they are much appreciated!
EDIT: After the first review and the scope changes resulting from that, I updated the PR's title.