webspresso 0.0.33 → 0.0.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,6 +15,68 @@ const {
15
15
  } = require('./scopes');
16
16
  const { ensureArray } = require('./utils');
17
17
 
18
+ /**
19
+ * Get JSON column names from model
20
+ * @param {import('./types').ModelDefinition} model - Model definition
21
+ * @returns {Set<string>} Set of JSON column names
22
+ */
23
+ function getJsonColumns(model) {
24
+ const jsonCols = new Set();
25
+ if (model.columns) {
26
+ for (const [name, meta] of model.columns) {
27
+ if (meta.type === 'json') {
28
+ jsonCols.add(name);
29
+ }
30
+ }
31
+ }
32
+ return jsonCols;
33
+ }
34
+
35
+ /**
36
+ * Serialize JSON fields for database storage
37
+ * @param {Object} data - Data to serialize
38
+ * @param {Set<string>} jsonColumns - JSON column names
39
+ * @returns {Object} Serialized data
40
+ */
41
+ function serializeJsonFields(data, jsonColumns) {
42
+ if (jsonColumns.size === 0) return data;
43
+
44
+ const serialized = { ...data };
45
+ for (const col of jsonColumns) {
46
+ if (col in serialized && serialized[col] !== null && serialized[col] !== undefined) {
47
+ // Only stringify if it's not already a string
48
+ if (typeof serialized[col] !== 'string') {
49
+ serialized[col] = JSON.stringify(serialized[col]);
50
+ }
51
+ }
52
+ }
53
+ return serialized;
54
+ }
55
+
56
+ /**
57
+ * Deserialize JSON fields from database
58
+ * @param {Object} record - Record from database
59
+ * @param {Set<string>} jsonColumns - JSON column names
60
+ * @returns {Object} Deserialized record
61
+ */
62
+ function deserializeJsonFields(record, jsonColumns) {
63
+ if (!record || jsonColumns.size === 0) return record;
64
+
65
+ for (const col of jsonColumns) {
66
+ if (col in record && record[col] !== null && record[col] !== undefined) {
67
+ // Only parse if it's a string
68
+ if (typeof record[col] === 'string') {
69
+ try {
70
+ record[col] = JSON.parse(record[col]);
71
+ } catch {
72
+ // If parsing fails, keep the original string value
73
+ }
74
+ }
75
+ }
76
+ }
77
+ return record;
78
+ }
79
+
18
80
  /**
19
81
  * Create a repository for a model
20
82
  * @param {import('./types').ModelDefinition} model - Model definition
@@ -24,6 +86,7 @@ const { ensureArray } = require('./utils');
24
86
  */
25
87
  function createRepository(model, knex, initialContext) {
26
88
  const scopeContext = initialContext || createScopeContext();
89
+ const jsonColumns = getJsonColumns(model);
27
90
 
28
91
  /**
29
92
  * Get base query builder
@@ -55,6 +118,9 @@ function createRepository(model, knex, initialContext) {
55
118
  return null;
56
119
  }
57
120
 
121
+ // Deserialize JSON fields
122
+ deserializeJsonFields(record, jsonColumns);
123
+
58
124
  // Load relations if requested
59
125
  if (withs.length > 0) {
60
126
  await loadRelations([record], ensureArray(withs), model, knex, scopeContext);
@@ -88,6 +154,9 @@ function createRepository(model, knex, initialContext) {
88
154
  return null;
89
155
  }
90
156
 
157
+ // Deserialize JSON fields
158
+ deserializeJsonFields(record, jsonColumns);
159
+
91
160
  // Load relations if requested
92
161
  if (withs.length > 0) {
93
162
  await loadRelations([record], ensureArray(withs), model, knex, scopeContext);
@@ -112,6 +181,11 @@ function createRepository(model, knex, initialContext) {
112
181
 
113
182
  const records = await qb;
114
183
 
184
+ // Deserialize JSON fields
185
+ for (const record of records) {
186
+ deserializeJsonFields(record, jsonColumns);
187
+ }
188
+
115
189
  // Load relations if requested
116
190
  if (withs.length > 0 && records.length > 0) {
117
191
  await loadRelations(records, ensureArray(withs), model, knex, scopeContext);
@@ -130,7 +204,10 @@ function createRepository(model, knex, initialContext) {
130
204
  const validated = model.schema.partial().parse(data);
131
205
 
132
206
  // Apply insert modifiers (timestamps, tenant)
133
- const insertData = applyInsertModifiers(validated, scopeContext, model);
207
+ let insertData = applyInsertModifiers(validated, scopeContext, model);
208
+
209
+ // Serialize JSON fields
210
+ insertData = serializeJsonFields(insertData, jsonColumns);
134
211
 
135
212
  // Insert and return the record
136
213
  const [id] = await knex(model.table).insert(insertData).returning(model.primaryKey);
@@ -169,7 +246,10 @@ function createRepository(model, knex, initialContext) {
169
246
  const validated = model.schema.partial().parse(data);
170
247
 
171
248
  // Apply update modifiers (timestamps)
172
- const updateData = applyUpdateModifiers(validated, model);
249
+ let updateData = applyUpdateModifiers(validated, model);
250
+
251
+ // Serialize JSON fields
252
+ updateData = serializeJsonFields(updateData, jsonColumns);
173
253
 
174
254
  // Update the record
175
255
  const updated = await baseQuery()
@@ -195,7 +275,10 @@ function createRepository(model, knex, initialContext) {
195
275
  const validated = model.schema.partial().parse(data);
196
276
 
197
277
  // Apply update modifiers (timestamps)
198
- const updateData = applyUpdateModifiers(validated, model);
278
+ let updateData = applyUpdateModifiers(validated, model);
279
+
280
+ // Serialize JSON fields
281
+ updateData = serializeJsonFields(updateData, jsonColumns);
199
282
 
200
283
  let qb = baseQuery();
201
284
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webspresso",
3
- "version": "0.0.33",
3
+ "version": "0.0.34",
4
4
  "description": "Minimal, production-ready SSR framework for Node.js with file-based routing, Nunjucks templating, built-in i18n, and CLI tooling",
5
5
  "main": "index.js",
6
6
  "bin": {