diff --git a/frontend/src/components/grid-items.svelte b/frontend/src/components/grid-items.svelte index 5effd17..3279417 100644 --- a/frontend/src/components/grid-items.svelte +++ b/frontend/src/components/grid-items.svelte @@ -3,7 +3,7 @@ import Icon from './icon.svelte'; import FormInput from './forminput.svelte'; import contextMenu from '$lib/stores/contextmenu'; - import { resolveKeypath, setValue } from '$lib/keypaths'; + import { resolveKeypath, setValue } from '$lib/objects'; export let items = []; export let columns = []; diff --git a/frontend/src/components/objectviewer.svelte b/frontend/src/components/objectviewer.svelte index 315cf0a..3e1e312 100644 --- a/frontend/src/components/objectviewer.svelte +++ b/frontend/src/components/objectviewer.svelte @@ -3,6 +3,7 @@ import Modal from './modal.svelte'; import ObjectTree from './objecttree.svelte'; import { onDestroy } from 'svelte'; + import { deepClone } from '$lib/objects'; export let data; @@ -11,7 +12,7 @@ let _data; $: if (data) { - _data = JSON.parse(JSON.stringify(data)); + _data = deepClone(data); for (const key of Object.keys(_data)) { if (typeof _data[key] === 'undefined') { delete _data[key]; diff --git a/frontend/src/lib/actions/input.js b/frontend/src/lib/actions/input.js index bfd974a..5cb119a 100644 --- a/frontend/src/lib/actions/input.js +++ b/frontend/src/lib/actions/input.js @@ -1,5 +1,6 @@ import { isInt } from '$lib/math'; import { canBeObjectId, int32, int64, uint64 } from '$lib/mongo'; +import { jsonLooseParse } from '$lib/strings'; export default function input(node, { autofocus, type, onValid, onInvalid, mandatory } = { autofocus: false, @@ -26,7 +27,7 @@ export default function input(node, { autofocus, type, onValid, onInvalid, manda switch (type) { case 'json': try { - JSON.parse(node.value); + jsonLooseParse(node.value); return false; } catch { diff --git a/frontend/src/lib/mongo/atomic-update-operators.json b/frontend/src/lib/mongo/atomic-update-operators.json new file mode 100644 index 0000000..e7e8e56 --- /dev/null +++ b/frontend/src/lib/mongo/atomic-update-operators.json @@ -0,0 +1,29 @@ +{ + "Fields": { + "$currentDate": "Current Date", + "$inc": "Increment", + "$min": "Min", + "$max": "Max", + "$mul": "Multiply", + "$rename": "Rename", + "$set": "Set", + "$setOnInsert": "Set on Insert", + "$unset": "Unset" + }, + "Array": { + "$addToSet": "Add to Set", + "$pop": "Pop", + "$pull": "Pull", + "$push": "Push", + "$pullAll": "Push All" + }, + "Modifiers": { + "$each": "Each", + "$position": "Position", + "$slice": "Slice", + "$sort": "Sort" + }, + "Bitwise": { + "$bit": "Bit" + } +} diff --git a/frontend/src/lib/mongo/index.js b/frontend/src/lib/mongo/index.js index 4d47039..10ecdbe 100644 --- a/frontend/src/lib/mongo/index.js +++ b/frontend/src/lib/mongo/index.js @@ -1,8 +1,9 @@ import { ObjectId } from 'bson'; import aggregationStages from './aggregation-stages.json'; +import atomicUpdateOperators from './atomic-update-operators.json'; import locales from './locales.json'; -export { aggregationStages, locales }; +export { aggregationStages, atomicUpdateOperators, locales }; // Calculate the min and max values of (un)signed integers with n bits export const intMin = bits => Math.pow(2, bits - 1) * -1; diff --git a/frontend/src/lib/keypaths.js b/frontend/src/lib/objects.js similarity index 94% rename from frontend/src/lib/keypaths.js rename to frontend/src/lib/objects.js index b597d77..d960109 100644 --- a/frontend/src/lib/keypaths.js +++ b/frontend/src/lib/objects.js @@ -56,3 +56,8 @@ export function setValue(object, path, value) { return object; } + +export function deepClone(obj) { + // Room for improvement below + return JSON.parse(JSON.stringify(obj)); +} diff --git a/frontend/src/lib/strings.js b/frontend/src/lib/strings.js index 8e47075..c0050f4 100644 --- a/frontend/src/lib/strings.js +++ b/frontend/src/lib/strings.js @@ -2,3 +2,23 @@ export function capitalise(string = '') { const capitalised = string.charAt(0).toUpperCase() + string.slice(1); return capitalised; } + +export function jsonLooseParse(json) { + const obj = new Function(`return (${json})`)(); + return obj; +} + +export function convertLooseJson(json) { + const j = JSON.stringify(jsonLooseParse(json)); + return j; +} + +export function looseJsonIsValid(json) { + try { + jsonLooseParse(json); + return true; + } + catch { + return false; + } +} diff --git a/frontend/src/organisms/connection/collection/aggregate.svelte b/frontend/src/organisms/connection/collection/aggregate.svelte index 3a7dcbf..cee90b4 100644 --- a/frontend/src/organisms/connection/collection/aggregate.svelte +++ b/frontend/src/organisms/connection/collection/aggregate.svelte @@ -5,6 +5,7 @@ import MongoCollation from '$components/mongo-collation.svelte'; import input from '$lib/actions/input'; import { aggregationStageDocumentationURL, aggregationStages } from '$lib/mongo'; + import { jsonLooseParse, looseJsonIsValid } from '$lib/strings'; import { Aggregate } from '$wails/go/app/App'; import { BrowserOpenURL } from '$wails/runtime/runtime'; import { onMount } from 'svelte'; @@ -14,15 +15,7 @@ const options = {}; let stages = []; let settingsModalOpen = false; - $: invalid = !stages.length || stages.some(stage => { - try { - JSON.parse(stage.data); - return false; - } - catch { - return true; - } - }); + $: invalid = !stages.length || stages.some(stage => !stage.data || !looseJsonIsValid(stage.data)); function addStage() { stages = [ ...stages, { type: '$match' } ]; @@ -38,7 +31,7 @@ } async function run() { - const pipeline = stages.map(stage => ({ [stage.type]: JSON.parse(stage.data) })); + const pipeline = stages.map(stage => ({ [stage.type]: jsonLooseParse(stage.data) })); await Aggregate(collection.hostKey, collection.dbKey, collection.key, JSON.stringify(pipeline), JSON.stringify(options)); } @@ -84,11 +77,10 @@ Settings - - +
diff --git a/frontend/src/organisms/connection/collection/components/form.svelte b/frontend/src/organisms/connection/collection/components/form.svelte index 698950d..70c37b5 100644 --- a/frontend/src/organisms/connection/collection/components/form.svelte +++ b/frontend/src/organisms/connection/collection/components/form.svelte @@ -2,7 +2,7 @@ import FormInput from '$components/forminput.svelte'; import Icon from '$components/icon.svelte'; import { inputTypes } from '$lib/mongo'; - import { resolveKeypath, setValue } from '$lib/keypaths'; + import { resolveKeypath, setValue } from '$lib/objects'; import Hint from '$components/hint.svelte'; export let item = {}; diff --git a/frontend/src/organisms/connection/collection/find.svelte b/frontend/src/organisms/connection/collection/find.svelte index 8305efd..04f1e50 100644 --- a/frontend/src/organisms/connection/collection/find.svelte +++ b/frontend/src/organisms/connection/collection/find.svelte @@ -1,9 +1,10 @@
+
+ [ { label: 'Drop this index', fn: () => drop(idx.name) } ]} + bind:activePath + on:trigger={e => openJson(e.detail.itemKey)} + /> +
+
- -
- [ { label: 'Drop this index', fn: () => drop(idx.name) } ]} - bind:activePath - on:trigger={e => openJson(e.detail.itemKey)} - /> -
@@ -73,7 +73,7 @@ .indexes { display: grid; gap: 0.5rem; - grid-template: auto 1fr / 1fr; + grid-template: 1fr auto / 1fr; } .indexes .grid { diff --git a/frontend/src/organisms/connection/collection/insert.svelte b/frontend/src/organisms/connection/collection/insert.svelte index a172b50..f730382 100644 --- a/frontend/src/organisms/connection/collection/insert.svelte +++ b/frontend/src/organisms/connection/collection/insert.svelte @@ -7,7 +7,7 @@ import { randomString } from '$lib/math'; import { inputTypes } from '$lib/mongo'; import views from '$lib/stores/views'; - import { capitalise } from '$lib/strings'; + import { capitalise, convertLooseJson, jsonLooseParse } from '$lib/strings'; import { InsertItems } from '$wails/go/app/App'; import { EJSON } from 'bson'; import { createEventDispatcher } from 'svelte'; @@ -32,7 +32,7 @@ $: { if (collection.viewKey === 'list') { try { - newItems = EJSON.parse(json, { relaxed: false }); + newItems = EJSON.deserialize(jsonLooseParse(json), { relaxed: false }); } catch { /* ok */ } } @@ -46,7 +46,7 @@ } async function insert() { - insertedIds = await InsertItems(collection.hostKey, collection.dbKey, collection.key, json); + insertedIds = await InsertItems(collection.hostKey, collection.dbKey, collection.key, convertLooseJson(json)); if ((collection.viewKey === 'list') && insertedIds) { newItems = []; } @@ -95,15 +95,8 @@
{#if collection.viewKey === 'list'} -