Skip to content

Releases: drizzle-team/tento

0.1.4

25 Oct 13:09
632a318
Compare
Choose a tag to compare
0.1.4 Pre-release
Pre-release

Support Metafields

Tento now supports Metafields

  1. Metafields have the same number of field definitions and validations as Metaobjects.

Note

We currently support only the 'PRODUCT' owner type.

import { metafield } from '@drizzle-team/tento';

export const name = metafield({
  name: "Name",
  ownerType: "PRODUCT",
  pin: true,
  description: "",
  key: "name",
  namespace: "custom",
  visibleToStorefrontApi: true,
  fieldDefinition: (f) =>
    f.singleLineTextField({
      validations: (v) => [v.min(1), v.max(50)],
    }),
});

export const description = metafield({
  name: "Description",
  ownerType: "PRODUCT",
  fieldDefinition: (f) => f.multiLineTextField(),
});
  1. Additionally, Metafields can now include a Metaobject reference field definition.
import { metafield, metaobject } from '@drizzle-team/tento';

export const designer = metaobject({
  name: "Designer",
  type: "designer",
  fieldDefinitions: (f) => ({
    name: f.singleLineTextField({
      name: "Title",
      required: true,
      validations: (v) => [v.min(1), v.max(50)],
    }),
    description: f.multiLineTextField({
      name: "Description",
    }),
    website: f.url({
      name: "Website",
    }),
  }),
});

export const designer_reference = metafield({
  name: "Designer",
  ownerType: "PRODUCT",
  fieldDefinition: (f) =>
    f.metaobjectReference({
      validations: (v) => [v.metaobjectDefinitionType(() => designer.type)],
    }),
});

Updated Metaobjects

  1. Previously, we had simple $inferInsert and $inferSelect type definitions based on the Metaobject schema model, which allowed for straightforward types with all required fields. With this release, we are introducing new $inferInsert and $inferSelect type definitions. Now, Tento will specify exactly which fields are required for insertion and which fields can be nullable in the response.
import { metaobject } from '@drizzle-team/tento';

export const designer = metaobject({
  name: "Designer",
  type: "designer",
  fieldDefinitions: (f) => ({
    name: f.singleLineTextField({
      name: "Title",
      required: true,
      validations: (v) => [v.min(1), v.max(50)],
    }),
    description: f.multiLineTextField({
      name: "Description",
    }),
    website: f.url({
      name: "Website",
    }),
  }),
});

type InsertModel = typeof designer.$inferInsert;
type SelectModel = typeof designer.$inferSelect;

Before

type InsertModel = {
    name: string;
    description: string;
    website: string;
}

type SelectModel = {
    _id: string;
    _handle: string;
    _updatedAt: Date;
    name: string;
    description: string;
    website: string;
}

After

type InsertModel = {
    name: string;
    description?: string | undefined;
    website?: string | undefined;
}

type SelectModel = {
    _id: string;
    _handle: string;
    _displayName: string;
    _updatedAt: Date;
    name: string;
    description: string | null;
    website: string | null;
}
  1. Added new API for upsert
import { tento, metaobject } from "@drizzle-team/tento";

export const designer = metaobject({
  name: "Designer",
  type: "designer",
  fieldDefinitions: (f) => ({
    name: f.singleLineTextField({
      name: "Title",
      required: true,
      validations: (v) => [v.min(1), v.max(50)],
    }),
    description: f.multiLineTextField({
      name: "Description",
    }),
    website: f.url({
      name: "Website",
    }),
  }),
});

const result = await client.metaobjects.designer.upsert("gid://shopify/Metaobject/1", {
    fields: {
      name: "Alex",
    },
});
const result: {
    _id: string;
    _handle: string;
    _displayName: string;
    _updatedAt: Date;
    name: string;
    description: string | null;
    website: string | null;
}
  1. The bulkDelete API has been updated to return a job instance in the response. This instance includes one field and one asynchronous function:
  • job.done: This field contains the actual result and resolves only once the job is complete.
  • job.checkDone(): This asynchronous function calls Shopify to retrieve an updated result for the job.
import { tento, metaobject } from "@drizzle-team/tento";

export const designer = metaobject({
  name: "Designer",
  type: "designer",
  fieldDefinitions: (f) => ({
    name: f.singleLineTextField({
      name: "Title",
      required: true,
      validations: (v) => [v.min(1), v.max(50)],
    }),
    description: f.multiLineTextField({
      name: "Description",
    }),
    website: f.url({
      name: "Website",
    }),
  }),
});

/**
* job.done -> boolean
* job.chekDone() -> Promise<boolean>
*/
const job: ShopifyJobOperation = await client.metaobjects.designer.bulkDelete(['gid://shopify/Metaobject/1']);
const isDone = await job.checkDone();
const isDone: boolean

Support Products

Starting with this release, we are introducing new Products API's. We will gradually improve and add all shopify Product API's

  1. products.list is actually products shopify query
import { tento } from "@drizzle-team/tento";

const products = await client.products.list();
const products: {
    items: {
        id: string;
        createdAt: Date;
        updatedAt: Date;
        isGiftCard: boolean;
        category?: {
            fullName: string;
            id: string;
            isLeaf: boolean;
            isRoot: boolean;
            name: string;
            ancestorIds: number[];
            childrenIds: number[];
            isArchived: boolean;
            level: number;
            parentId?: number | undefined;
        } | undefined;
        ... 30 more ...;
        vendor: string;
    }[];
    pageInfo: {
        startCursor: string;
        endCursor: string;
        hasNextPage: boolean;
        hasPreviousPage: boolean;
    };
}

By default, all fields are included in the response. However, you can specify which fields to include or exclude as needed. You can query all available fields in the 2024-10 Shopify API version with these filters

Using include in your query will return only the specified fields:

import { tento } from "@drizzle-team/tento";

const products = await client.products.list({
    first: 10,
    fields: {
      id: true,
      title: true,
      handle: true,
      productType: true,
      tags: true,
    },
    query: {
      title: "product",
      $or: [
        {
          tag: "tento",
        },
        {
          tag: "custom",
        },
      ],
    },
  });
const products: {
    items: {
        id: string;
        title: string;
        handle: string;
        productType: string;
        tags: string[];
    }[];
    pageInfo: {
        startCursor: string;
        endCursor: string;
        hasNextPage: boolean;
        hasPreviousPage: boolean;
    };
}

Using exclude in your query will return all fields except the specified ones:

const products = await client.products.list({
    first: 10,
    fields: {
      id: false,
      title: false,
      handle: false,
      productType: false,
      tags: false,
    },
    query: {
      title: "product",
      $or: [
        {
          tag: "tento",
        },
        {
          tag: "custom",
        },
      ],
    },
  });
const products: {
    items: {
        description: string;
        createdAt: Date;
        updatedAt: Date;
        isGiftCard: boolean;
        category: {
            fullName: string;
            id: string;
            isLeaf: boolean;
            isRoot: boolean;
            name: string;
            ... 4 more ...;
            parentId?: number | undefined;
        } | undefined;
        ... 25 more ...;
        vendor: string;
    }[];
    pageInfo: {
        startCursor: string;
        endCursor: string;
        hasNextPage: boolean;
        hasPreviousPage: boolean;
    };
}
  1. The products.update function corresponds to the productUpdate mutation in Shopify.
import { tento, metaobject, metafield } from "@drizzle-team/tento";

export const designer = metaobject({
  name: "Designer",
  type: "designer",
  fieldDefinitions: (f) => ({
    name: f.singleLineTextField({
      name: "Title",
      required: true,
      validations: (v) => [v.min(1), v.max(50)],
    }),
    description: f.multiLineTextField({
      name: "Description",
    }),
    website: f.url({
      name: "Website",
    }),
  }),
});

export const designer_reference = metafield({
  name: "Designer",
  ownerType: "PRODUCT",
  fieldDefinition: (f) =>
    f.metaobjectReference({
      validations: (v) => [v.metaobjectDefinitionType(() => designer.type)],
    }),
});

const gqlClient = new shopify.clients.Graphql({
  session,
});

const client = tento({
  client: gqlClient,
  schema: { designer, designer_reference },
});

/**
* Designer key field is accessed as designer_reference.name, which will be autocompleted by TypeScript
*/
const products = await client.products.update("gid://shopify/Product/1", {
    fields: {
      title: "product title",
      metafields: {
        Designer: "metaobject ID",
      },
    },
  });
const products: {
    title: string;
    metafields: {
        key: string;
        type: MetafieldFieldType;
        value: string;
        id: string;
        namespace: string;
        ownerType: 'PRODUCT';
    }[];
}

Common

We’ve added comm...

Read more