api-sdk-ts icon indicating copy to clipboard operation
api-sdk-ts copied to clipboard

jsonParameter parser works counterintuitive

Open souljorje opened this issue 3 years ago • 10 comments

  • I'm submitting a ...

  • [x] feature request

  • Summary

I wish it works like this:

contractsGetBigMapByNameKeys(
    address,
    'name',
    {
      value: {
        token_id: {
           in: ['0', '1'],
        },
       /*  instead of
       in: {
          jsonPath: 'token_id',
          jsonValue: ['0', '1'],
        },
       */
      },
    },
  )
  • Other information

I suggest to recursively create that.kind.of.path from object with last nested property as value. And also I suggest to use reduce for declarativeness.

souljorje avatar Feb 23 '22 10:02 souljorje

@Groxan @m-kus what do u think dudes

souljorje avatar Feb 23 '22 15:02 souljorje

@souljorje how would you specify this path: ?value.field.array.[*].field2=...?

Groxan avatar Feb 23 '22 16:02 Groxan

@Groxan

{
  value: {
  	field: {
      array: {
        '[*]': {
        	field2: {
        		eq: 'foo',
				// also I could specify at one place i.e.
				ne: 'bar',
				// etc
        	}
        }
      }
    }
  }
}

souljorje avatar Feb 23 '22 16:02 souljorje

Actually, would be cool to use proxy instead, and just write it like value.toke_id.in = [0, 1] and then build path in proxy handler, but it's still not clear what to do with [*] (value.array['*'].field=123 is not really elegant).

Groxan avatar Feb 23 '22 16:02 Groxan

@Groxan my suggestion is kinda mongodb query syntax: nested & intuitive imho 🤷‍♂️

proxy for what?

souljorje avatar Feb 23 '22 16:02 souljorje

Proxy is used for creating dynamic object, so that you can "access" fields that are not defined. Nesting is good because you can merge multiple parameters (paths) into a single object, but it's less handy to write, especially in case of long and complex paths.

Anyway, I don't object. Just my thoughts.

Groxan avatar Feb 23 '22 16:02 Groxan

Another issue that I see is constructing a query for a response object, that has in | ne | etc. in its fields. Such objects might not YET exist, but they might be there in the future. For the current proposal, the parameter would look something like this

value: {
  someField: {
    in: {
      in: string[]
    }
  }
}

No sure if it improves readability, not mentioning the complexity of creating a QS parser for such parameter.

mv-go avatar Feb 23 '22 16:02 mv-go

Another issue is creating a type for this parameter. The difficulty would be describing a Record of Records of unknown depth with the deepest level always being strongly typed to available eq, ne, in, etc. types.

mv-go avatar Feb 23 '22 16:02 mv-go

@souljorje this can be done only knowing the particular contract storage type. We will definitely implement that in TzKT wrappers

m-kus avatar Feb 23 '22 17:02 m-kus

Here's a parser for suggested syntax.

const isPlainObject = (v) => {
  if (Object.prototype.toString.call(v) !== '[object Object]') return false;
  const prototype = Object.getPrototypeOf(v);
  return prototype === null || prototype === Object.prototype;
};

const objectToQueryObject = (obj, path) => {
  return Object.entries(obj).reduce((acc, [key, value]) => {
    const newPath = path ? `${path}.${key}` : key;
    if (isPlainObject(value)) {
      return {
        ...acc,
        ...objectToQueryObject(value, newPath)
      };
    }
    acc[newPath] = value;
    return acc;
  }, {})
};

const queryObjectRaw = {
  value: {
    field: {
      array: {
        '[*]': {
          field2: {
            eq: 'foo',
            ne: 'bar',
          }
        }
      },
      someOtherProp: { 
		in: [1, 2, 3],
        ne: 'baz',
      }
    },
    someOtherField: {
      gt: 123
    },
  },
  otherValue: {
    eq: 2
  },
};

const result = objectToQueryObject(queryObjectRaw);

console.log('result', result);

const queryString = new URLSearchParams(result).toString();

console.log('queryString', queryString);

souljorje avatar Feb 24 '22 04:02 souljorje