tzkt / api-sdk-ts

Typed SDK for TzKT API
https://sdk.tzkt.io
MIT License
16 stars 0 forks source link

jsonParameter parser works counterintuitive #1

Open souljorje opened 2 years ago

souljorje commented 2 years ago

I wish it works like this:

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

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 commented 2 years ago

@Groxan @m-kus what do u think dudes

Groxan commented 2 years ago

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

souljorje commented 2 years ago

@Groxan

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

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).

souljorje commented 2 years ago

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

proxy for what?

Groxan commented 2 years ago

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.

mv-go commented 2 years ago

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 commented 2 years ago

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.

m-kus commented 2 years ago

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

souljorje commented 2 years ago

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);