Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature proposal: keep (opposite of remove) #26

Open
aboqasem opened this issue Feb 19, 2024 · 2 comments
Open

Feature proposal: keep (opposite of remove) #26

aboqasem opened this issue Feb 19, 2024 · 2 comments
Labels

Comments

@aboqasem
Copy link

aboqasem commented Feb 19, 2024

import { keep } from "@sagold/json-query";
const input = { object: { a: { id: 33, name: "a" }, b: { id: "id-b", name: "b" } } };

keep(input, "/object/*/id"); // { object: { a: { id: 33 }, b: { id: "id-b" } } };

I am also wondering whether this is achievable with the current API.

@sagold
Copy link
Owner

sagold commented Feb 25, 2024

Hi Mohammad,

we could consider adding a keep function to the api. From a logical perspective, using get and iterating the results by set over a single object should achieve the same result. Did you try this?

Cheers,
sagold

@aboqasem
Copy link
Author

aboqasem commented Feb 27, 2024

Hello @sagold,

Thanks for the suggestion!

This is what I have:

import { beforeEach, describe, expect, it } from "bun:test";
import { get, set } from "@sagold/json-query";

// biome-ignore lint/suspicious/noExplicitAny: testing
let data: any;

beforeEach(() => {
	data = {
		a: {
			id: "a",
			needle: "needle-a",
		},
		b: {
			id: "b",
			needle: "needle-b",
			d: {
				id: "d",
				needle: "needle-d",
			},
		},
		c: {
			e: {
				f: {
					id: "f",
					needle: "needle-f",
				},
			},
		},
	};
});

describe("keep", () => {
	it("should keep any matches", () => {
		const kept = keep(data, "#/**/*/needle");

		expect(kept).toEqual({
			a: { needle: "needle-a" },
			b: { needle: "needle-b", d: { needle: "needle-d" } },
			c: { e: { f: { needle: "needle-f" } } },
		});
	});

	it("should keep any matches supporting filters", () => {
		const kept = keep(data, "#/**/*?needle:{needle-.*}");

		expect(kept).toEqual({
			a: { id: "a", needle: "needle-a" },
			b: { id: "b", needle: "needle-b", d: { id: "d", needle: "needle-d" } },
			c: { e: { f: { id: "f", needle: "needle-f" } } },
		});
	});

	it("should keep array indices", () => {
		const data = { array: [1, { keep: true }, { keep: true }, 2] };
		const result = keep(data, "#/array/*?keep:true");
		// @ts-expect-error
		expect(result.array).toHaveLength(3);
		// @ts-expect-error
		expect(result.array).toEqual([null, { keep: true }, { keep: true }]);
	});
});

function keep(data: Record<string, unknown> | unknown[], queries: string | string[]): unknown {
	if (typeof queries === "string") {
		queries = [queries];
	}

	let kept: Record<string, unknown> | unknown[] = Array.isArray(data) ? [] : {};
	for (const query of queries) {
		const ptrs: Record<string, unknown> = get(data, query, get.MAP);
		for (const ptr in ptrs) {
			kept = set(kept, ptr.substring(1), ptrs[ptr]);
		}
	}

	return kept;
}

aboqasem added a commit to aboqasem/dotfiles that referenced this issue Feb 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants