Releases: drizzle-team/tento
Releases · drizzle-team/tento
0.1.4
Support Metafields
Tento now supports Metafields
- 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(),
});
- 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
- 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;
}
- 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;
}
- The
bulkDelete
API has been updated to return ajob
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
products.list
is actuallyproducts
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;
};
}
- The
products.update
function corresponds to theproductUpdate
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...