@laboratoria/sdk-js 5.3.1 → 6.0.0-beta.0

Sign up to get free protection for your applications and to get access to all the features.
package/lib/model.js DELETED
@@ -1,343 +0,0 @@
1
- import { createClient } from './client.js';
2
-
3
-
4
- const createValidator = (schema) => {
5
- const properties = schema.properties || {};
6
- const inputProps = schema.inputProps || Object.keys(properties);
7
-
8
- const validateAttr = (key, value) => {
9
- const propSchema = properties[key] || {};
10
- const isNullVal = [null, undefined].includes(value);
11
-
12
- if (isNullVal) {
13
- if (!propSchema.isRequired) {
14
- return;
15
- }
16
-
17
- return { id: 'value-missing-validation-error' };
18
- }
19
-
20
- if (propSchema.enum) {
21
- if (propSchema.enum.includes(value)) {
22
- return;
23
- }
24
- return {
25
- id: 'enum-validation-error',
26
- values: { enum: propSchema.enum, value },
27
- };
28
- }
29
-
30
- switch (propSchema.type) {
31
- case 'integer':
32
- if (propSchema.isScalar && (typeof value !== 'number' || Number.isNaN(value))) {
33
- return { id: 'invalid-number-validation-error' };
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
- // }
42
- break;
43
- case 'date':
44
- break;
45
- case 'boolean':
46
- break;
47
- case 'json':
48
- case 'string':
49
- default:
50
- if (propSchema.isRequired && !value) {
51
- return { id: 'value-missing-validation-error' };
52
- }
53
- break;
54
- }
55
- };
56
-
57
- return {
58
- validate: attrs => inputProps.reduce(
59
- (memo, key) => {
60
- const err = validateAttr(key, attrs[key]);
61
- if (err) {
62
- return { ...memo, [key]: err };
63
- }
64
- return memo;
65
- },
66
- {},
67
- ),
68
- validateAttr,
69
- };
70
- };
71
-
72
-
73
- const qToQs = (q = {}) => Object.keys(q).length ? `?q=${JSON.stringify(q)}` : '';
74
-
75
-
76
- const toKebabCase = (str) => [...str].reduce(
77
- (memo, char) => (
78
- char === char.toUpperCase()
79
- ? `${memo}-${char.toLowerCase()}`
80
- : `${memo}${char}`
81
- ),
82
- '',
83
- );
84
-
85
- const lcFirst = str => `${str[0].toLowerCase()}${str.slice(1)}`;
86
-
87
-
88
- const createBuildURL = (collectionName) => {
89
- const base = toKebabCase(collectionName);
90
- return (id, q) => {
91
- return `/${base}${id ? `/${encodeURIComponent(id)}` : ''}${qToQs(q)}`;
92
- };
93
- };
94
-
95
-
96
- const serializeData = (data, schema) => {
97
- const hasInputProps = Array.isArray(schema.inputProps);
98
- return Object.keys(data).reduce(
99
- (memo, key) => {
100
- if (hasInputProps && !schema.inputProps.includes(key)) {
101
- return memo;
102
- }
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) {
106
- return memo;
107
- }
108
- return {
109
- ...memo,
110
- [key]: data[key],
111
- };
112
- },
113
- {},
114
- );
115
- };
116
-
117
-
118
- const parseSchema = ({ primaryKey, properties, ...rest }) => {
119
- return {
120
- primaryKey: primaryKey || 'id',
121
- properties: Object.keys(properties || {}).reduce(
122
- (memo, key) => {
123
- const propSchema = properties[key] || {};
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 }
140
- );
141
-
142
- const inputType = propSchema.inputType || (
143
- type === 'integer'
144
- ? 'number'
145
- : type
146
- );
147
-
148
- return {
149
- ...memo,
150
- [key]: {
151
- ...properties[key],
152
- type,
153
- isScalar,
154
- isRequired: (
155
- typeof propSchema.isRequired === 'boolean'
156
- ? propSchema.isRequired
157
- : isRequired
158
- ),
159
- isRef,
160
- inputType,
161
- },
162
- };
163
- },
164
- {},
165
- ),
166
- ...rest,
167
- };
168
- };
169
-
170
-
171
- export const createModel = (
172
- baseUrl,
173
- state,
174
- collectionName,
175
- schema = {},
176
- models = {},
177
- ) => {
178
- const parsedSchema = parseSchema(schema);
179
- const { primaryKey, properties } = parsedSchema;
180
- const validator = createValidator(parsedSchema);
181
- const buildURL = createBuildURL(collectionName);
182
- const req = (...args) => createClient(baseUrl, state.authUser)(...args);
183
- const create = ({ data, ...q }) => req(buildURL(null, q), {
184
- method: 'POST',
185
- body: serializeData(data, parsedSchema),
186
- });
187
- const put = ({ data, ...q }) => {
188
- const { where, ...rest } = q;
189
- return req(buildURL(where[primaryKey], rest), {
190
- method: 'PUT',
191
- body: serializeData(data, parsedSchema),
192
- });
193
- };
194
-
195
- const parse = (data) => {
196
- if (!data) {
197
- return data;
198
- }
199
-
200
- const parsed = Object.keys(data).reduce(
201
- (memo, key) => {
202
- const propSchema = properties[key] || {};
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
- }
217
- return {
218
- ...memo,
219
- [key]: models[relationModelName].parse(data[key]),
220
- };
221
- }
222
-
223
- return {
224
- ...memo,
225
- [key]: (
226
- type === 'date' && data[key]
227
- ? new Date(data[key])
228
- : data[key]
229
- ),
230
- };
231
- },
232
- {},
233
- );
234
-
235
- return (
236
- typeof parsedSchema.parse === 'function'
237
- ? parsedSchema.parse(parsed)
238
- : parsed
239
- );
240
- };
241
-
242
- const relations = Object.keys(properties || {}).reduce(
243
- (memo, key) => (
244
- properties[key].isRef && properties[key].isScalar && properties[key].isRequired
245
- ? Object.assign(memo, {
246
- all: memo.all.concat(key),
247
- oneToOne: memo.oneToOne.concat(key),
248
- requiredOneToOne: memo.requiredOneToOne.concat(key),
249
- })
250
- : properties[key].isRef && properties[key].isScalar
251
- ? Object.assign(memo, {
252
- all: memo.all.concat(key),
253
- oneToOne: memo.oneToOne.concat(key),
254
- optionalOneToOne: memo.optionalOneToOne.concat(key),
255
- })
256
- : properties[key].isRef
257
- ? Object.assign(memo, {
258
- all: memo.all.concat(key),
259
- oneToMany: memo.oneToMany.concat(key),
260
- })
261
- : memo
262
- ),
263
- {
264
- all: [],
265
- oneToOne: [],
266
- requiredOneToOne: [],
267
- optionalOneToOne: [],
268
- oneToMany: [],
269
- },
270
- );
271
-
272
- return {
273
- get schema() {
274
- return parsedSchema;
275
- },
276
- get relations() {
277
- return relations;
278
- },
279
- parse,
280
- validateAttr: validator.validateAttr,
281
- validate: validator.validate,
282
- findMany: q => req(buildURL(null, q))
283
- .then(results => results.map(parse)),
284
- findById: (id, q) => req(buildURL(id, q))
285
- .then(parse),
286
- create,
287
- update: put,
288
- upsert: opts => (
289
- !opts.where[primaryKey]
290
- ? create({ data: opts.create })
291
- : put({ where: opts.where, data: opts.update })
292
- ),
293
- delete: id => req(buildURL(id), { method: 'DELETE' }),
294
- stats: () => req(buildURL('_stats')),
295
- };
296
- };
297
-
298
-
299
- export const createModels = (url, state, schema) => {
300
- return Object.keys(schema.properties).reduce(
301
- (prev, key) => {
302
- const name = schema.properties[key].$ref.split('/').pop();
303
- return Object.assign(prev, {
304
- [key]: createModel(
305
- url,
306
- state,
307
- schema.definitions[name].plural || `${key}s`,
308
- schema.definitions[name],
309
- prev,
310
- ),
311
- });
312
- },
313
- {},
314
- );
315
- };
316
-
317
-
318
- export const extendSchemaDefinitions = (schema, extended) => {
319
- return Object.keys(schema.definitions).reduce(
320
- (memo, key) => ({
321
- ...memo,
322
- [key]: (
323
- !extended[key]
324
- ? schema.definitions[key]
325
- : {
326
- ...schema.definitions[key],
327
- ...extended[key],
328
- properties: Object.keys(schema.definitions[key].properties).reduce(
329
- (prev, propName) => ({
330
- ...prev,
331
- [propName]: {
332
- ...schema.definitions[key].properties[propName],
333
- ...(extended[key].properties || {})[propName],
334
- },
335
- }),
336
- extended[key].properties || {},
337
- ),
338
- }
339
- ),
340
- }),
341
- {},
342
- );
343
- };
package/lib/roles.js DELETED
@@ -1,10 +0,0 @@
1
- const roles = ['bm', 'pdc', 'js', 'ux'];
2
-
3
- roles.colors = {
4
- bm: 'black',
5
- pdc: 'magenta',
6
- js: 'primary',
7
- ux: 'mint',
8
- };
9
-
10
- export default roles;
package/lib/util.js DELETED
@@ -1,68 +0,0 @@
1
- const pad = n => n > 9 ? `${n}` : `0${n}`;
2
-
3
- export const formatDate = date => (
4
- `${pad(date.getUTCDate())}/${pad(date.getUTCMonth() + 1)}/${date.getUTCFullYear()}`
5
- );
6
-
7
- export const formatTime = date => (
8
- `${pad(date.getUTCHours())}:${pad(date.getUTCMinutes())}:${date.getUTCSeconds()} UTC`
9
- );
10
-
11
- export const formatDateTime = date => `${formatDate(date)} ${formatTime(date)}`;
12
-
13
- const locales = {
14
- es: 'es-ES',
15
- pt: 'pt-BR',
16
- };
17
-
18
- export const formatMonth = (date, lang = 'es', showYear = false) => {
19
- return new Intl.DateTimeFormat(locales[lang], {
20
- ...(showYear && {
21
- year: 'numeric',
22
- }),
23
- month: 'long',
24
- day: 'numeric',
25
- timeZone: 'UTC',
26
- }).format(new Date(date));
27
- };
28
-
29
- export const getAgeAt = (dateOfBirth, at) => {
30
- let age = at.getFullYear() - dateOfBirth.getFullYear();
31
- const m = at.getMonth() - dateOfBirth.getMonth();
32
-
33
- if (m < 0 || (m === 0 && at.getDate() < dateOfBirth.getDate())) {
34
- age--;
35
- }
36
-
37
- return age;
38
- };
39
-
40
- const createCurrencyFormatter = (
41
- lang,
42
- countryCode,
43
- currencyCode,
44
- ) => new Intl.NumberFormat(
45
- `${lang}-${countryCode}`,
46
- { currency: currencyCode },
47
- );
48
-
49
- export const formatCurrency = (
50
- val,
51
- lang,
52
- countryCode,
53
- currencyCode,
54
- ) => createCurrencyFormatter(
55
- lang,
56
- countryCode,
57
- currencyCode,
58
- ).format(val);
59
-
60
- export const parseCurrency = val => parseInt(val.replace(/[,\.]/g, ''), 10);
61
-
62
- export const loadFromLocalStorage = (path) => {
63
- try {
64
- return JSON.parse(window.localStorage.getItem(path));
65
- } catch (_) {
66
- return null;
67
- }
68
- };