@laboratoria/sdk-js 3.4.1 → 4.0.0-alpha.0

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -45,6 +45,63 @@ app.auth.signIn(email, password);
45
45
  app.auth.signOut();
46
46
  ```
47
47
 
48
+ ### Models
49
+
50
+ The `app` object exposes data models used to access data. Each model represents
51
+ a _type_ of object, which is stored in a database table.
52
+
53
+ All models have the following methods and properties.
54
+
55
+ #### CRUD methods
56
+
57
+ * `create`
58
+ * `delete`
59
+ * `findById`
60
+ * `findMany`
61
+ * `update`
62
+ * `upsert`
63
+
64
+ #### Other methods
65
+
66
+ * `parse`
67
+ * `stats`
68
+ * `validate`
69
+ * `validateAttr`
70
+
71
+ #### Properties
72
+
73
+ * `relations`
74
+ * `schema`
75
+
76
+ ### Model Schema
77
+
78
+ Each _model_ has a _schema_ (`model.schema`) that describes the _shape_ of the
79
+ data, what properties (columns) it has, what data types these columns are,
80
+ whether they are _required_ or not, etc.
81
+
82
+ The `model.schema` is an object with the following properties:
83
+
84
+ * `inputProps`: An array listing properties to be taken into account when
85
+ building input UI or sending data (via `model.create`, `model.update`, etc).
86
+ * `primaryKey`: Primary key in the underlying table.
87
+ * `properties`: An object with the model properties. Each property is described
88
+ by an object having the following keys:
89
+ - `type`: It can be: `boolean`, `integer`, `string`, `date` o una referncia a
90
+ un modelo, en cuyo caso el string será el nombre del modelo de prisma.
91
+ - `default`
92
+ - `enum`
93
+ - `format`: `date-time`
94
+ - `$ref`
95
+ - `anyOf`
96
+ - `items`
97
+ - `inputType`
98
+ - `isRequired`
99
+ - `isScalar`
100
+ - `isRef`
101
+ * `type`: The schema for the whole model will always be of type `object`.
102
+
103
+ ***
104
+
48
105
  ### Users
49
106
 
50
107
  ```js
package/lib/core.js CHANGED
@@ -177,16 +177,19 @@ const extended = {
177
177
  'locality',
178
178
  'nationality',
179
179
  'isAllowedToWork',
180
+ 'hasValidIdDocument',
180
181
  'householdSize',
181
182
  'children',
182
183
  'householdIncome',
183
184
  'educationLevel',
185
+ 'schoolType',
184
186
  'educationSubject',
185
187
  'university',
186
188
  'isStudying',
187
189
  'workStatus',
188
190
  'isLookingForWork',
189
191
  'monthsLookingForWork',
192
+ 'monthsUnemployed',
190
193
  'workRole',
191
194
  'freelance',
192
195
  'workFormal',
@@ -196,7 +199,13 @@ const extended = {
196
199
  ],
197
200
  properties: {
198
201
  locality: {
199
- required: true,
202
+ isRequired: true,
203
+ },
204
+ isReady: {
205
+ isRequired: false,
206
+ },
207
+ bypassFilters: {
208
+ isRequired: false,
200
209
  },
201
210
  },
202
211
  },
package/lib/model.js CHANGED
@@ -1,63 +1,44 @@
1
1
  import { createClient } from './client.js';
2
2
 
3
3
 
4
- const isRequiredOneToOneRelation = (schema, key) => (
5
- !!schema.properties
6
- && !!schema.properties[key]
7
- && !!schema.properties[key].$ref
8
- );
9
-
10
- const isOptionalOneToOneRelation = (schema, key) => (
11
- !!schema.properties
12
- && !!schema.properties[key]
13
- && Array.isArray(schema.properties[key].anyOf)
14
- && !!schema.properties[key].anyOf[0]?.$ref
15
- && schema.properties[key].anyOf[1]?.type === 'null'
16
- );
17
-
18
- // const isOneToOneRelation = (schema, key) => (
19
- // isRequiredOneToOneRelation(schema, key)
20
- // || isOptionalOneToOneRelation(schema, key)
21
- // );
22
-
23
- const isOneToManyRelation = (schema, key) => (
24
- schema.properties
25
- && schema.properties[key]
26
- && schema.properties[key].type === 'array'
27
- && !!schema.properties[key].items?.$ref
28
- );
29
-
30
- // const isRelation = (schema, key) => (
31
- // isOneToOneRelation(schema, key)
32
- // || isOneToManyRelation(schema, key)
33
- // );
34
-
35
-
36
4
  const createValidator = (schema) => {
37
5
  const properties = schema.properties || {};
38
6
  const inputProps = schema.inputProps || Object.keys(properties);
39
7
 
40
8
  const validateAttr = (key, value) => {
41
- const attrSchema = properties[key] || {};
9
+ const propSchema = properties[key] || {};
10
+ const isNullVal = [null, undefined].includes(value);
42
11
 
43
- if (attrSchema.enum) {
44
- if (!attrSchema.required && !value) {
12
+ if (isNullVal) {
13
+ if (!propSchema.isRequired) {
45
14
  return;
46
15
  }
47
- if (!attrSchema.enum.includes(value)) {
48
- return {
49
- id: 'enum-validation-error',
50
- values: { enum: attrSchema.enum, value },
51
- };
16
+
17
+ return { id: 'required-validation-error' };
18
+ }
19
+
20
+ if (propSchema.enum) {
21
+ if (propSchema.enum.includes(value)) {
22
+ return;
52
23
  }
24
+ return {
25
+ id: 'enum-validation-error',
26
+ values: { enum: propSchema.enum, value },
27
+ };
53
28
  }
54
29
 
55
- switch (attrSchema.$type) {
30
+ switch (propSchema.type) {
56
31
  case 'integer':
57
- const parsedValue = parseInt(value, 10);
58
- if (attrSchema.required && Number.isNaN(parsedValue)) {
32
+ if (propSchema.isScalar && (typeof value !== 'number' || Number.isNaN(value))) {
59
33
  return { id: 'invalid-number-validation-error' };
60
34
  }
35
+ // if (propSchema.isRequired && Number.isNaN(parsedValue)) {
36
+ // return { id: 'invalid-number-validation-error' };
37
+ // }
38
+ // const parsedValue = parseInt(value, 10);
39
+ // if (propSchema.isRequired && Number.isNaN(parsedValue)) {
40
+ // return { id: 'invalid-number-validation-error' };
41
+ // }
61
42
  break;
62
43
  case 'date':
63
44
  break;
@@ -65,9 +46,8 @@ const createValidator = (schema) => {
65
46
  break;
66
47
  case 'json':
67
48
  case 'string':
68
- case 'ref':
69
49
  default:
70
- if (attrSchema.required && !value) {
50
+ if (propSchema.isRequired && !value) {
71
51
  return { id: 'required-validation-error' };
72
52
  }
73
53
  break;
@@ -120,7 +100,9 @@ const serializeData = (data, schema) => {
120
100
  if (hasInputProps && !schema.inputProps.includes(key)) {
121
101
  return memo;
122
102
  }
123
- if (isOptionalOneToOneRelation(schema, key) && data[key] === null) {
103
+ // TODO: Deberíamos incluir props que no aparecen en el schema??
104
+ const { isRef, isScalar, isRequired } = schema.properties[key] || {};
105
+ if (isRef && isScalar && !isRequired && data[key] === null) {
124
106
  return memo;
125
107
  }
126
108
  return {
@@ -139,38 +121,43 @@ const parseSchema = ({ primaryKey, properties, ...rest }) => {
139
121
  properties: Object.keys(properties || {}).reduce(
140
122
  (memo, key) => {
141
123
  const propSchema = properties[key] || {};
142
- const $type = (
143
- !propSchema.type
144
- ? propSchema.$ref
145
- ? 'ref'
146
- : undefined
147
- : !Array.isArray(propSchema.type)
148
- ? propSchema.type
149
- : propSchema.type.length < 3
150
- ? propSchema.type[0]
151
- : 'json'
124
+ const { type, isScalar, isRequired, isRef = false } = (
125
+ typeof propSchema.type === 'string'
126
+ ? propSchema.type === 'array'
127
+ ? !!propSchema.enum
128
+ ? { type: 'string', isScalar: false, isRequired: false }
129
+ : !!propSchema.items?.$ref
130
+ ? { type: propSchema.items.$ref.split('/').pop(), isScalar: false, isRequired: false, isRef: true }
131
+ : { type: propSchema.items?.type, isScalar: false, isRequired: false }
132
+ : { type: propSchema.format === 'date-time' ? 'date' : propSchema.type, isScalar: true, isRequired: true }
133
+ : Array.isArray(propSchema.type)
134
+ ? propSchema.type.length === 2
135
+ ? { type: propSchema.format === 'date-time' ? 'date' : propSchema.type[0], isScalar: true, isRequired: false }
136
+ : { type: 'json', isScalar: true, isRequired: propSchema.type.includes('null') }
137
+ : !!propSchema.$ref
138
+ ? { type: propSchema.$ref.split('/').pop(), isScalar: true, isRequired: true, isRef: true }
139
+ : { type: propSchema.anyOf[0].$ref.split('/').pop(), isScalar: true, isRequired: false, isRef: true }
152
140
  );
141
+
153
142
  const inputType = propSchema.inputType || (
154
- $type === 'integer'
143
+ type === 'integer'
155
144
  ? 'number'
156
- : $type === 'string' && propSchema.format === 'date-time'
157
- ? 'date'
158
- : $type
145
+ : type
159
146
  );
147
+
160
148
  return {
161
149
  ...memo,
162
150
  [key]: {
163
151
  ...properties[key],
164
- $type,
165
- inputType,
166
- required: (
167
- typeof propSchema.required === 'boolean'
168
- ? propSchema.required
169
- : (
170
- !Array.isArray(propSchema.type)
171
- || !propSchema.type.includes('null')
172
- )
152
+ type,
153
+ isScalar,
154
+ isRequired: (
155
+ typeof propSchema.isRequired === 'boolean'
156
+ ? propSchema.isRequired
157
+ : isRequired
173
158
  ),
159
+ isRef,
160
+ inputType,
174
161
  },
175
162
  };
176
163
  },
@@ -205,7 +192,7 @@ export const createModel = (
205
192
  });
206
193
  };
207
194
 
208
- const parse = data => {
195
+ const parse = (data) => {
209
196
  if (!data) {
210
197
  return data;
211
198
  }
@@ -213,37 +200,30 @@ export const createModel = (
213
200
  const parsed = Object.keys(data).reduce(
214
201
  (memo, key) => {
215
202
  const propSchema = properties[key] || {};
216
- const { type, format, items } = propSchema;
217
- if (items && isOneToManyRelation(parsedSchema, key)) {
218
- const relationModelName = lcFirst(items.$ref.split('/').pop());
219
- return {
220
- ...memo,
221
- [key]: (
222
- typeof models[relationModelName]?.parse === 'function'
223
- ? data[key].map(obj => models[relationModelName].parse(obj))
224
- : data[key]
225
- ),
226
- };
227
- }
228
- const ref = (
229
- isRequiredOneToOneRelation(parsedSchema, key)
230
- ? propSchema.$ref
231
- : isOptionalOneToOneRelation(parsedSchema, key)
232
- ? propSchema.anyOf[0]?.$ref
233
- : null
234
- );
235
-
236
- if (ref) {
237
- const relationModelName = lcFirst(ref.split('/').pop());
203
+ const { type, isScalar, isRef, format, items } = propSchema;
204
+
205
+ if (isRef) {
206
+ const relationModelName = lcFirst(type);
207
+ if (!isScalar) {
208
+ return {
209
+ ...memo,
210
+ [key]: (
211
+ typeof models[relationModelName]?.parse === 'function'
212
+ ? data[key].map(obj => models[relationModelName].parse(obj))
213
+ : data[key]
214
+ ),
215
+ };
216
+ }
238
217
  return {
239
218
  ...memo,
240
219
  [key]: models[relationModelName].parse(data[key]),
241
220
  };
242
221
  }
222
+
243
223
  return {
244
224
  ...memo,
245
225
  [key]: (
246
- format === 'date-time' && data[key]
226
+ type === 'date' && data[key]
247
227
  ? new Date(data[key])
248
228
  : data[key]
249
229
  ),
@@ -251,6 +231,7 @@ export const createModel = (
251
231
  },
252
232
  {},
253
233
  );
234
+
254
235
  return (
255
236
  typeof parsedSchema.parse === 'function'
256
237
  ? parsedSchema.parse(parsed)
@@ -260,19 +241,22 @@ export const createModel = (
260
241
 
261
242
  const relations = Object.keys(properties || {}).reduce(
262
243
  (memo, key) => (
263
- isRequiredOneToOneRelation(parsedSchema, key)
244
+ properties[key].isRef && properties[key].isScalar && properties[key].isRequired
245
+ // isRequiredOneToOneRelation(parsedSchema, key)
264
246
  ? Object.assign(memo, {
265
247
  all: memo.all.concat(key),
266
248
  oneToOne: memo.oneToOne.concat(key),
267
249
  requiredOneToOne: memo.requiredOneToOne.concat(key),
268
250
  })
269
- : isOptionalOneToOneRelation(parsedSchema, key)
251
+ // : isOptionalOneToOneRelation(parsedSchema, key)
252
+ : properties[key].isRef && properties[key].isScalar
270
253
  ? Object.assign(memo, {
271
254
  all: memo.all.concat(key),
272
255
  oneToOne: memo.oneToOne.concat(key),
273
256
  optionalOneToOne: memo.optionalOneToOne.concat(key),
274
257
  })
275
- : isOneToManyRelation(parsedSchema, key)
258
+ // : isOneToManyRelation(parsedSchema, key)
259
+ : properties[key].isRef
276
260
  ? Object.assign(memo, {
277
261
  all: memo.all.concat(key),
278
262
  oneToMany: memo.oneToMany.concat(key),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@laboratoria/sdk-js",
3
- "version": "3.4.1",
3
+ "version": "4.0.0-alpha.0",
4
4
  "description": "Laboratoria JavaScript (browser) SDK",
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -33,4 +33,4 @@
33
33
  }
34
34
  }
35
35
  }
36
- }
36
+ }
package/schemas/core.json CHANGED
@@ -711,6 +711,9 @@
711
711
  "isAllowedToWork": {
712
712
  "type": "boolean"
713
713
  },
714
+ "hasValidIdDocument": {
715
+ "type": "boolean"
716
+ },
714
717
  "locality": {
715
718
  "type": [
716
719
  "number",
@@ -730,6 +733,17 @@
730
733
  "householdIncome": {
731
734
  "type": "integer"
732
735
  },
736
+ "schoolType": {
737
+ "type": [
738
+ "string",
739
+ "null"
740
+ ],
741
+ "enum": [
742
+ "private",
743
+ "public",
744
+ "other"
745
+ ]
746
+ },
733
747
  "educationSubject": {
734
748
  "type": [
735
749
  "string",
@@ -777,6 +791,12 @@
777
791
  "null"
778
792
  ]
779
793
  },
794
+ "monthsUnemployed": {
795
+ "type": [
796
+ "integer",
797
+ "null"
798
+ ]
799
+ },
780
800
  "workRole": {
781
801
  "type": [
782
802
  "string",