Instalando o deco records no seu site
Para iniciar o processo de instalação, crie um ambiente novo, no admin deco do seu site, ou resete o ambiente que esteja utilizando, por que será feito um publish ao fim desta etapa.
Siga o passo a passo abaixo para realizar a instalação no seu site ou siga o vídeo.
- Entre no admin do seu site na deco
- Na barra lateral clique no menu records
- Em seguida clique em
Setup Deco Records
, aguarde o processo de instalação da app e criação do banco de dados. Nesta etapa, será criado e editado alguns arquivos do seu site (deno.json, .gitignore, manifest.gen.ts, apps/deco/records.ts, drizzle.config.ts, db/schema.ts, .deco/blocks/deco-records.json) - Após a instalação, clique em
Show diff and publish
para publicar a instalação da sua app e criação do banco de dados. - Revise os arquivos alterados, edite a descrição e, por fim, clique em
Publish now
.
Após o processo de publicação finalizar, ao acessar o menu de records, terá a visualização do seu banco de dados.
Criando tabelas
Será necessário ter os arquivos que foram criados durante a instalação do deco records no computador. Caso seja necessário realize um git pull do seu projeto remoto.
Siga o passo a passo abaixo para criar novas tabelas no seu banco de dados ou
siga o vídeo. Neste processo será utilizado o
drizzle-orm e
drizzle-kit para criação das tabelas e
gerenciamento delas no seu banco de dados, através de
schema migrations.
No exemplo a seguir, será criado uma tabela com nome profiles, com as colunas:
id
, name
e email
.
1. Edite o arquivo db/schema.ts
para criar tabelas.
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
export const profiles = sqliteTable("profiles", {
id: integer("id").primaryKey({ autoIncrement: true }),
name: text("name").notNull(),
email: text("email"),
});
2. Entre no admin do seu site, clique no menu de Settings
, em
seguida, na seção Database credentials, clique em Generate now
. Por fim,
clique no icone de copiar as credenciais.
3. Adicione as credenciais, nas variáveis de ambiente do sistema operacional do seu computador.
4. Execute a deno task db:setup:deps
no seu terminal para
instalar as dependências necessárias para realizar o schema migration. É
necessário versão do deno maior ou igual a 1.43.0 e utilizar a variável de
ambiente DENO_FUTURE=1
para habilitar a instalação de módulos npm.
5. Execute a deno task db:schema:update
, para criar os arquivos
sql responsáveis pela schema migration e aplica-los ao banco de dados. Execute
este comando sempre que realizar uma alteração nas suas tabelas para gerar novas
schema migrations.
deno task db:setup:deps
6. No menu de records do seu site, no admin da deco, terá as
tabelas de profiles
e __drizzle__migrations
. A tabela drizzle__migrations é
auto gerada e utilizada pelo drizzle-kit para gerenciar os schema migrations.
Adicione os arquivos auto gerados em um git commit e realize um push para o git remoto.
Lendo e escrevendo dados
Com a tabela de profiles criada, agora podemos criar uma section de gerenciar perfis, onde lista, remove e cria um perfil.
Crie uma section que será o gerenciador de perfis.
import { eq } from "drizzle-orm";
import { SectionProps } from "deco/types.ts";
import type { AppContext } from "site/apps/deco/records.ts";
import { profiles } from "site/db/schema.ts";
import { useSection } from "deco/hooks/useSection.ts";
import Icon from "site/components/ui/Icon.tsx";
type ProfileInsert = typeof profiles.$inferInsert;
type ProfilesKeys = keyof ProfileInsert;
type ProfileValue<K extends keyof ProfileInsert> = ProfileInsert[K];
/**
* Checa se `key` é uma chave válida do tipo profile.
*/
const isProfilePropKey = (
key: string,
): key is ProfilesKeys => key in profiles.$inferInsert;
/**
* Checa se `value` é do mesmo tipo de profiles[key]
*/
const isProfilePropType = (
key: ProfilesKeys,
value: unknown,
): value is ProfileValue<typeof key> =>
typeof value === typeof profiles.$inferInsert[key];
interface Props {
mode?: "create" | "delete";
email?: string;
}
export async function loader(
{ mode, email }: Props,
req: Request,
{ invoke }: AppContext,
) {
// Client do ORM drizzle
const drizzle = await invoke.records.loaders.drizzle();
// Se o mode for create e o request possuir body, então cria um profile novo
if (mode === "create" && req.body) {
const newProfile: Partial<typeof profiles.$inferInsert> = {};
const formData = await req.formData();
formData.forEach((value, key) =>
isProfilePropKey(key) &&
isProfilePropType(key, value) &&
(newProfile[key] = value as any)
);
// Insere newProfile no banco de dados.
await drizzle.insert(profiles).values(
newProfile as typeof profiles.$inferInsert,
);
} // Se mode for delete e email for definido e não vazio, então remova todos or perfis com este email.
else if (mode === "delete" && email) {
await drizzle.delete(profiles).where(eq(profiles.email, email));
}
// Seleciona todos os perfils do banco de dados, trazendo somenente email e nome.
const profilesData = await drizzle.select({
email: profiles.email,
name: profiles.name,
}).from(profiles);
return { profiles: profilesData };
}
export default function ManageProfiles(
{ profiles = [] }: SectionProps<typeof loader>,
) {
// Url da section, com a propriedade mode = create, será utilizada para submit do form e criação de novo perfil.
const createUrl = useSection<Props>({
props: { mode: "create" },
});
return (
<>
<div>
<form
hx-post={createUrl}
hx-trigger="click"
hx-target="closest section"
hx-swap="outerHTML"
class="p-2 flex flex-col gap-2"
>
<div class="flex gap-2">
<label for="name">Name</label>
<input
// propriedade name do profiles
name="name"
id="name"
required
class="border border-gray-300 rounded"
/>
</div>
<div class="flex gap-2">
<label for="description">email</label>
<input
// propriedade email do profiles
name="email"
id="email"
required
class="border border-gray-300 rounded"
/>
</div>
<div>
<button type="submit">Create</button>
</div>
</form>
</div>
<div class="divide-y divide-gray-300 p-2 w-fit">
<h3>Members List</h3>
{profiles.map((profile) => {
// Url da section, com a propriedade mode = delete e email do perfil a ser removido, será utilizada para submit do form e remoção do perfil.
const profileDeleteUrl = useSection<Props>({
props: { mode: "delete", email: profile.email ?? "" },
});
return (
<div class="flex gap-2 items-center">
<span>{profile.name}</span>
<span>{profile.email}</span>
<form
hx-post={profileDeleteUrl}
hx-trigger="click"
hx-target="closest section"
hx-swap="outerHTML"
class="w-4 h-4"
>
<button type="submit" class="w-4 h-4">
<Icon id="Trash" size={16} />
</button>
</form>
</div>
);
})}
</div>
</>
);
}
No exemplo anterior, o inline loader que faz utiliza o cliente drizzle
, que é
fornecido pela app do records, e faz uma consulta no banco de dados, insere e
remove perfis.
Desenvolvendo localmente
Para desenvolver localmente é necessário ter as credenciais de acesso ao banco
de dados, que pode ser criada no admin do seu site na deco. Após ter adicionado
as variáveis de ambiente fornecidas pelo admin, execute a deno task
db:pull:prod
para fazer um dump do seu banco de dados e em seguida, inserir no
banco de dados localmente no arquivo sqlite.db
.
deno task db:pull:prod
Para acessar o banco do deco records durante o desenvolvimento, é necessário ter
as credenciais nas variáveis de ambiente, que podem ser criadas no admin da
deco. Além das credenciais, precisa de uma nova variável de ambiente, chamada
USE_PRODUCTION_DB
com valor 1
.