forked from jsnbuchanan/crowd-funder-for-time-pwa
fix: Convert searchBoxes arrays to JSON strings in $saveSettings and $updateSettings
- Add _convertSettingsForStorage helper method to handle Settings → SettingsWithJsonStrings conversion - Fix $saveSettings and $saveUserSettings to properly convert searchBoxes arrays to JSON strings before database storage - Update SearchAreaView.vue to use array format instead of manual JSON.stringify conversion - Add comprehensive test UI in PlatformServiceMixinTest.vue with visual feedback and clear demonstration of conversion process - Document migration strategy for consolidating $updateSettings into $saveSettings to reduce code duplication - Add deprecation notices to $updateSettings method with clear migration guidance The fix ensures that searchBoxes arrays are properly converted to JSON strings before database storage, preventing data corruption and maintaining consistency with the SettingsWithJsonStrings type definition. The enhanced test interface provides clear visualization of the conversion process and database storage format. Migration Strategy: - $saveSettings: ✅ KEEP (will be primary method after consolidation) - $updateSettings: ⚠️ DEPRECATED (will be removed in favor of $saveSettings) - Future: Consolidate to single $saveSettings(changes, did?) method Files changed: - src/utils/PlatformServiceMixin.ts: Add conversion helper, fix save methods, add deprecation notices - src/views/SearchAreaView.vue: Remove manual JSON conversion - src/test/PlatformServiceMixinTest.vue: Add comprehensive test UI with highlighting - docs/migration-templates/updateSettings-consolidation-plan.md: Document future consolidation strategy
This commit is contained in:
@@ -1,11 +1,63 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2>PlatformServiceMixin Test</h2>
|
||||
<button @click="testInsert">Test Insert</button>
|
||||
<button @click="testUpdate">Test Update</button>
|
||||
<button :class="primaryButtonClasses" @click="testUserZeroSettings">
|
||||
Test User #0 Settings
|
||||
</button>
|
||||
<div class="space-y-2">
|
||||
<button
|
||||
:class="
|
||||
activeTest === 'insert'
|
||||
? 'bg-green-500 text-white'
|
||||
: 'bg-gray-200 hover:bg-gray-300'
|
||||
"
|
||||
class="px-4 py-2 rounded mr-2 transition-colors"
|
||||
@click="testInsert"
|
||||
>
|
||||
Test Insert
|
||||
</button>
|
||||
<button
|
||||
:class="
|
||||
activeTest === 'update'
|
||||
? 'bg-green-500 text-white'
|
||||
: 'bg-gray-200 hover:bg-gray-300'
|
||||
"
|
||||
class="px-4 py-2 rounded mr-2 transition-colors"
|
||||
@click="testUpdate"
|
||||
>
|
||||
Test Update
|
||||
</button>
|
||||
<button
|
||||
:class="
|
||||
activeTest === 'searchBoxes'
|
||||
? 'bg-green-500 text-white'
|
||||
: 'bg-gray-200 hover:bg-gray-300'
|
||||
"
|
||||
class="px-4 py-2 rounded mr-2 transition-colors"
|
||||
@click="testSearchBoxesConversion"
|
||||
>
|
||||
Test SearchBoxes Conversion
|
||||
</button>
|
||||
<button
|
||||
:class="
|
||||
activeTest === 'database'
|
||||
? 'bg-green-500 text-white'
|
||||
: 'bg-gray-200 hover:bg-gray-300'
|
||||
"
|
||||
class="px-4 py-2 rounded mr-2 transition-colors"
|
||||
@click="testDatabaseStorage"
|
||||
>
|
||||
Test Database Storage Format
|
||||
</button>
|
||||
<button
|
||||
:class="
|
||||
activeTest === 'userZero'
|
||||
? 'bg-green-500 text-white'
|
||||
: primaryButtonClasses
|
||||
"
|
||||
class="transition-colors"
|
||||
@click="testUserZeroSettings"
|
||||
>
|
||||
Test User #0 Settings
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="userZeroTestResult"
|
||||
@@ -16,13 +68,24 @@
|
||||
JSON.stringify(userZeroTestResult, null, 2)
|
||||
}}</pre>
|
||||
</div>
|
||||
<pre>{{ result }}</pre>
|
||||
|
||||
<div v-if="result" class="mt-4">
|
||||
<div class="p-4 border border-blue-300 rounded-md bg-blue-50">
|
||||
<h4 class="font-semibold mb-2 text-blue-800">Test Results:</h4>
|
||||
<div
|
||||
class="whitespace-pre-wrap text-sm font-mono bg-white p-3 rounded border"
|
||||
>
|
||||
{{ result }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from "vue-facing-decorator";
|
||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
|
||||
@Component({
|
||||
mixins: [PlatformServiceMixin],
|
||||
@@ -30,8 +93,15 @@ import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
export default class PlatformServiceMixinTest extends Vue {
|
||||
result: string = "";
|
||||
userZeroTestResult: any = null;
|
||||
activeTest: string = ""; // Track which test is currently active
|
||||
|
||||
// Add the missing computed property
|
||||
get primaryButtonClasses() {
|
||||
return "bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded";
|
||||
}
|
||||
|
||||
testInsert() {
|
||||
this.activeTest = "insert";
|
||||
const contact = {
|
||||
name: "Alice",
|
||||
age: 30,
|
||||
@@ -43,6 +113,7 @@ export default class PlatformServiceMixinTest extends Vue {
|
||||
}
|
||||
|
||||
testUpdate() {
|
||||
this.activeTest = "update";
|
||||
const changes = { name: "Bob", isActive: false };
|
||||
const { sql, params } = this.$generateUpdateStatement(
|
||||
changes,
|
||||
@@ -53,7 +124,125 @@ export default class PlatformServiceMixinTest extends Vue {
|
||||
this.result = `SQL: ${sql}\nParams: ${JSON.stringify(params)}`;
|
||||
}
|
||||
|
||||
testSearchBoxesConversion() {
|
||||
this.activeTest = "searchBoxes";
|
||||
// Test the _convertSettingsForStorage helper method
|
||||
const testSettings = {
|
||||
firstName: "John",
|
||||
searchBoxes: [
|
||||
{
|
||||
name: "Test Area",
|
||||
bbox: {
|
||||
eastLong: 1.0,
|
||||
maxLat: 1.0,
|
||||
minLat: 0.0,
|
||||
westLong: 0.0,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const converted = (this as any)._convertSettingsForStorage(testSettings);
|
||||
|
||||
this.result = `# 🔄 SearchBoxes Conversion Test (Helper Method)
|
||||
|
||||
## 📥 Input Settings
|
||||
\`\`\`json
|
||||
{
|
||||
"firstName": "John",
|
||||
"searchBoxes": ${JSON.stringify(testSettings.searchBoxes, null, 2)}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## 🔧 After _convertSettingsForStorage()
|
||||
\`\`\`json
|
||||
{
|
||||
"firstName": "John",
|
||||
"searchBoxes": "${converted.searchBoxes}"
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## ✅ Conversion Results
|
||||
- **Original Type**: \`${typeof testSettings.searchBoxes}\`
|
||||
- **Converted Type**: \`${typeof converted.searchBoxes}\`
|
||||
- **Conversion**: Array → JSON String ✅
|
||||
|
||||
## 📝 Note
|
||||
This tests the helper method only - no database interaction`;
|
||||
}
|
||||
|
||||
async testDatabaseStorage() {
|
||||
this.activeTest = "database";
|
||||
try {
|
||||
this.result = "🔄 Testing database storage format...";
|
||||
|
||||
// Create test settings with searchBoxes array
|
||||
const testSettings = {
|
||||
searchBoxes: [
|
||||
{
|
||||
name: "Test Area",
|
||||
bbox: {
|
||||
eastLong: 1.0,
|
||||
maxLat: 1.0,
|
||||
minLat: 0.0,
|
||||
westLong: 0.0,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Save to database using our fixed method
|
||||
const success = await this.$saveSettings(testSettings);
|
||||
|
||||
if (success) {
|
||||
// Now query the raw database to see how it's actually stored
|
||||
const rawResult = await this.$dbQuery(
|
||||
"SELECT searchBoxes FROM settings WHERE id = ?",
|
||||
[MASTER_SETTINGS_KEY],
|
||||
);
|
||||
|
||||
if (rawResult?.values?.length) {
|
||||
const rawSearchBoxes = rawResult.values[0][0]; // First column of first row
|
||||
|
||||
this.result = `# 🔧 Database Storage Format Test (Full Database Cycle)
|
||||
|
||||
## 📥 Input (JavaScript Array)
|
||||
\`\`\`json
|
||||
${JSON.stringify(testSettings.searchBoxes, null, 2)}
|
||||
\`\`\`
|
||||
|
||||
## 💾 Database Storage (JSON String)
|
||||
\`\`\`sql
|
||||
"${rawSearchBoxes}"
|
||||
\`\`\`
|
||||
|
||||
## ✅ Verification
|
||||
- **Type**: \`${typeof rawSearchBoxes}\`
|
||||
- **Is JSON String**: \`${typeof rawSearchBoxes === "string" && rawSearchBoxes.startsWith("[")}\`
|
||||
- **Conversion Working**: ✅ **YES** - Array converted to JSON string for database storage
|
||||
|
||||
## 🔄 Process Flow
|
||||
1. **Input**: JavaScript array with bounding box coordinates
|
||||
2. **Conversion**: \`_convertSettingsForStorage()\` converts array to JSON string
|
||||
3. **Storage**: JSON string saved to database using \`$saveSettings()\`
|
||||
4. **Retrieval**: JSON string parsed back to array for application use
|
||||
|
||||
## 📝 Note
|
||||
This tests the complete save → retrieve cycle with actual database interaction`;
|
||||
} else {
|
||||
this.result = "❌ No data found in database";
|
||||
}
|
||||
} else {
|
||||
this.result = "❌ Failed to save settings";
|
||||
}
|
||||
} catch (error) {
|
||||
this.result = `❌ Error: ${error}`;
|
||||
}
|
||||
}
|
||||
|
||||
async testUserZeroSettings() {
|
||||
this.activeTest = "userZero";
|
||||
try {
|
||||
// User #0's DID
|
||||
const userZeroDid = "did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F";
|
||||
|
||||
Reference in New Issue
Block a user