This commit is contained in:
MarcioJRGodoi 2024-10-28 16:16:01 -03:00
commit 7df1b4fc3d
81 changed files with 2754 additions and 1800 deletions

View file

@ -0,0 +1,284 @@
/** Drive completo do piilão de dados */
import crossFetch from "cross-fetch"
import { nomeVariavel } from "p-comuns"
import { respostaComuns, type tipoResposta } from "p-respostas"
import type { z } from "zod"
import type { zp_enviar_registros } from "../_enviar_registros"
import { PREFIXO_PILAO, type zp_deletar_registros } from "../variaveis"
import type { visoes_pilao } from "../visoes/listaDeVisoes"
import type { tipo_pilao_api } from "./pilao-api.ts"
import type { tipoConstrutorPilao, tipoRetornoSerieconsulta } from "./tipagem"
class ClassPilao {
#produto: string
#conta: string
#emDesenvolvimento: boolean
#ver_log: boolean
#registrosParaEnvio: Record<
string,
z.infer<typeof zp_enviar_registros>["registros"]
> = {}
#codigosParaDeletar: Record<
string,
z.infer<typeof zp_deletar_registros>["codigos"]
> = {}
constructor({
conta,
produto,
emDesenvolvimento = false,
ver_log = false,
}: tipoConstrutorPilao & { ver_log?: boolean; emDesenvolvimento?: boolean }) {
this.#produto = produto
this.#conta = conta
this.#emDesenvolvimento = emDesenvolvimento
this.#ver_log = ver_log
}
#gerarUrl(acao: string, extraPath?: string): { rota: string; url: string } {
const rota = `${PREFIXO_PILAO}/api/${acao}/${this.#produto}/${this.#conta}${
extraPath ? `/${extraPath}` : ""
}`
const url = `${this.baseUrlApi}${rota}`
return { rota, url }
}
rotaEnviarRegistros() {
return this.#gerarUrl("enviar-registros")
}
rotaDeletarRegistro() {
return this.#gerarUrl("deletar-registros")
}
rotaConsultarSerie(tipoVisao: keyof typeof visoes_pilao | ":tipoVisao") {
return this.#gerarUrl("consultar-serie", tipoVisao)
}
rotaIframeSerie(tipoVisao: keyof typeof visoes_pilao | ":tipoVisao") {
const rota = `${PREFIXO_PILAO}/consultar-serie/${this.#produto}/${this.#conta}/${tipoVisao}`
const url = `${this.baseUrlSite}${rota}`
return { rota, url }
}
rotaFuncaoApi(funcao: keyof tipo_pilao_api | ":funcao") {
return this.#gerarUrl("API", funcao)
}
async consultarApi<T extends keyof tipo_pilao_api>(
funcao: T,
parametros: tipo_pilao_api[T]["pr"],
): Promise<tipoResposta<tipo_pilao_api[T]["rs"]>> {
try {
const response = await crossFetch(this.rotaFuncaoApi(funcao).url, {
body: JSON.stringify(parametros),
method: "POST",
headers: { "Content-Type": "application/json" },
})
const texto = await response.text()
try {
const json = JSON.parse(texto)
return json
} catch {
return respostaComuns.erro("Consulta não retornou json válido", [texto])
}
} catch (erro) {
console.error(erro)
return respostaComuns.erroInterno({
erro,
local: nomeVariavel({ ClassPilao }),
})
}
}
get baseUrlApi() {
return this.#emDesenvolvimento
? "http://localhost:5080"
: "https://carro-de-boi.idz.one"
}
get baseUrlSite() {
return this.#emDesenvolvimento
? "http://localhost:5081"
: "https://carro-de-boi.idz.one"
}
validarCliente(_: any): tipoResposta<tipoConstrutorPilao> {
if (!_?.conta) return respostaComuns.erro("Conta não informada")
if (!_?.produto) return respostaComuns.erro("Produto não informado")
return respostaComuns.valor(_)
}
adicionarRegistroParaEnviar(
tabela: string,
...registros: z.infer<typeof zp_enviar_registros>["registros"]
) {
this.#registrosParaEnvio[tabela] = [
...(this.#registrosParaEnvio[tabela] || []),
...registros,
]
return this
}
adicionarCodigoParaDeletar(
tabela: string,
...codigos: z.infer<typeof zp_deletar_registros>["codigos"]
) {
this.#codigosParaDeletar[tabela] = [
...(this.#codigosParaDeletar[tabela] || []),
...codigos,
]
return this
}
private async processarRegistros(
url: string,
registros: any[],
tabela: string,
acao: string,
): Promise<tipoResposta<true>> {
const tamanhoBlocos = 1000
while (registros.length > 0) {
const bloco = registros
.splice(0, tamanhoBlocos)
.map((r) =>
Object.fromEntries(
Object.entries(r).map(([k, v]) => [k, v === undefined ? null : v]),
),
)
const resp = await crossFetch(url, {
method: "POST",
body: JSON.stringify({ tabela, registros: bloco }),
headers: { "Content-Type": "application/json" },
})
.then(async (r) => {
const texto = await r.text()
try {
const json = JSON.parse(texto)
return json
} catch {
return respostaComuns.erro("Consulta não retornou json válido", [
texto,
])
}
})
.catch((e) =>
respostaComuns.erro(`Erro ao ${acao} registros`, [e.message]),
)
if (resp.eErro) return resp
}
return respostaComuns.valor(true)
}
async #salvarEnviarRegistros(): Promise<tipoResposta<true>> {
for (const tabela of Object.keys(this.#registrosParaEnvio)) {
const registros = this.#registrosParaEnvio[tabela] || []
const url = this.rotaEnviarRegistros().url
if (this.#ver_log)
console.log(
`[PILÃO]: Enviando ${registros.length} registros na tabela "${tabela}" para "${url}".`,
)
const resp = await this.processarRegistros(
url,
registros,
tabela,
"enviar",
)
if (resp.eErro) return resp
this.#registrosParaEnvio[tabela] = []
}
return respostaComuns.valor(true)
}
async #salvarDeletarRegistros(): Promise<tipoResposta<true>> {
for (const tabela of Object.keys(this.#codigosParaDeletar)) {
const codigos = [...(this.#codigosParaDeletar[tabela] || [])]
const url = this.rotaDeletarRegistro().url
const resp = await this.processarRegistros(
url,
codigos,
tabela,
"deletar",
)
if (resp.eErro) return resp
}
return respostaComuns.valor(true)
}
async salvarRegistros(): Promise<tipoResposta<true>> {
const re = await this.#salvarEnviarRegistros()
if (re.eErro) return re
const rd = await this.#salvarDeletarRegistros()
if (rd.eErro) return rd
return respostaComuns.valor(true)
}
serieConsultar<T extends keyof typeof visoes_pilao>(
tipoVisao: T,
parametros: z.infer<(typeof visoes_pilao)[T]>,
) {
const dados = async (): Promise<
tipoResposta<tipoRetornoSerieconsulta<T>>
> => {
const url = this.rotaConsultarSerie(tipoVisao).url
const resp = await crossFetch(url.toString(), {
method: "POST",
body: JSON.stringify(parametros),
headers: { "Content-Type": "application/json" },
})
.then(async (r) => {
const texto = await r.text()
try {
const json = JSON.parse(texto)
return json
} catch {
return respostaComuns.erro("Consulta não retornou json válido", [
texto,
])
}
})
.catch((e) =>
respostaComuns.erro("Erro ao enviar registros", [e.message]),
)
if (this.#ver_log)
console.log(
`[PILÃO]: buscar dados de "${JSON.stringify(parametros)}" para "${url}".`,
)
return resp
}
const url = (): string => {
const vUrl = this.rotaIframeSerie(tipoVisao).url
const serie = encodeURIComponent(JSON.stringify(parametros, null, 2))
if (this.#ver_log)
console.log(
`[PILÃO]: Serie Consultar url de "${JSON.stringify(serie)}" para "${vUrl}".`,
)
return `${vUrl}?serie=${serie}`
}
return {
dados,
url,
}
}
urlLaboratorio() {
const rota = `${PREFIXO_PILAO}/laboratório/${this.#produto}/${this.#conta}`
const url = `${this.baseUrlSite}${rota}`
return { rota, url }
}
}
export const Pilao = (
_: tipoConstrutorPilao & { ver_log?: boolean; emDesenvolvimento?: boolean },
) => new ClassPilao(_)

View file

@ -0,0 +1,32 @@
import type { z } from "zod"
import type { zp_registrar_base_dados } from "../_enviar_registros"
/**
* {
* 'rota':{
* pr:{}// paramentros de entrada
* rs:{}// resposta
* }
* }
*/
export type tipo_pilao_api = {
/** retorna da data e hora do servido em formato iso */
estado_servidor: {
pr: {}
rs: {
data_hora: string
}
}
tabelas: {
pr: {}
rs: z.infer<typeof zp_registrar_base_dados>[]
}
unicos: {
pr: {
tabela: string
coluna: string
}
rs: any[]
}
}

View file

@ -0,0 +1,10 @@
import type { z } from "zod"
import type { visoes_pilao } from "../visoes/listaDeVisoes"
export type tipoConstrutorPilao = { produto: string; conta: string }
export type tipoRetornoSerieconsulta<T extends keyof typeof visoes_pilao> = {
registros: any[]
legenda: string
serie: z.infer<(typeof visoes_pilao)[T]>
}

View file

@ -1,47 +0,0 @@
import node_fetch from "cross-fetch"
import type { tipoResposta } from "p-respostas"
import { respostaComuns } from "p-respostas"
import { z } from "zod"
import { urlPilao, type zp_produto_conta } from "./variaveis"
//enviar registros para base de dados
export const zp_deletar_registros = z.object({
tabela: z.string(),
codigos: z.array(z.string()),
})
export const deletar_registros =
({ conta, produto, emDesenvolvimento }: z.infer<typeof zp_produto_conta>) =>
async ({
codigos: codigos_entrada,
tabela,
}: z.infer<typeof zp_deletar_registros>): Promise<tipoResposta<true>> => {
const codigos = [...codigos_entrada]
const url = new URL(
`${
urlPilao(emDesenvolvimento).api
}/${Object.keys({ deletar_registros })[0]}/${produto}/${conta}`,
)
const tamanhoBlocos = 1000
while (codigos.length > 0) {
const bloco = codigos.splice(0, tamanhoBlocos)
const resp = await node_fetch(url.toString(), {
method: "POST",
body: JSON.stringify({ tabela, codigos: bloco }),
headers: { "Content-Type": "application/json" },
})
.then((r) => r.json())
.catch((e) =>
respostaComuns.erro("Erro ao enviar registros", [e.message]),
)
.then((r) => r as tipoResposta<true>)
if (resp.eErro) {
return resp
}
}
return respostaComuns.valor(true)
}

View file

@ -1,19 +1,12 @@
import node_fetch from "cross-fetch"
import type { tipoResposta } from "p-respostas"
import { respostaComuns } from "p-respostas"
import { z } from "zod"
import {
urlPilao,
z_tipo_coluna_base_dados,
type zp_produto_conta,
} from "./variaveis"
import { z_tipos_dados_registro } from "./variaveis"
export const zp_registrar_base_dados = z.object({
tabela: z.string(),
colunas: z.array(
z.object({
coluna: z.string(),
tipo: z_tipo_coluna_base_dados,
tipo: z_tipos_dados_registro,
}),
),
})
@ -26,62 +19,8 @@ export const zp_enviar_registros = z.object({
z.string(),
z.object({
valor: z.any(),
tipo: z_tipo_coluna_base_dados.optional().nullable(),
tipo: z_tipos_dados_registro.optional().nullable(),
}),
),
),
})
export const enviar_registros =
({
conta,
produto,
emDesenvolvimento,
ver_log,
}: z.infer<typeof zp_produto_conta>) =>
async ({
registros: registros_entrada,
tabela,
}: z.infer<typeof zp_enviar_registros>): Promise<tipoResposta<true>> => {
const registros = [...registros_entrada]
const url = new URL(
`${
urlPilao(emDesenvolvimento).api
}/${Object.keys({ enviar_registros })[0]}/${produto}/${conta}`,
)
if (ver_log)
console.log(
`[PILÃO]: Enviando "${registros.length}" registros na tabela "${tabela}" para "${url}".`,
)
const tamanhoBlocos = 1000
while (registros.length > 0) {
const bloco = registros
.splice(0, tamanhoBlocos)
.map((r) =>
Object.fromEntries(
Object.entries(r).map(([k, v]) => [k, v === undefined ? null : v]),
),
)
const resp = await node_fetch(url.toString(), {
method: "POST",
body: JSON.stringify({ tabela, registros: bloco }),
headers: { "Content-Type": "application/json" },
})
.then((r) => r.json())
.catch((e) =>
respostaComuns.erro("Erro ao enviar registros", [e.message]),
)
.then((r) => r as tipoResposta<true>)
if (resp.eErro) {
return resp
}
}
return respostaComuns.valor(true)
}

View file

@ -1,67 +1,8 @@
import node_fetch from "cross-fetch"
import type { tipoResposta } from "p-respostas"
import { respostaComuns } from "p-respostas"
import { z } from "zod"
import { operadores_pilao, urlPilao, type zp_produto_conta } from "./variaveis"
import type { visoes } from "./visoes"
import { operadores_pilao } from "./variaveis"
export const z_filtro = z.object({
coluna: z.string(),
valor: z.any(),
operador: operadores_pilao,
})
export const serie_consultar =
(cliente: z.infer<typeof zp_produto_conta>) =>
<T extends keyof typeof visoes>(
tipoVisao: T,
parametros: z.infer<(typeof visoes)[T]>,
) => {
const dados = async (): Promise<
tipoResposta<{
registros: any[]
legenda: string
serie: z.infer<(typeof visoes)[T]>
}>
> => {
const url = new URL(
`${urlPilao(cliente.emDesenvolvimento).api}/${
tipoVisao
}/${cliente.produto}/${cliente.conta}`,
)
const resp = await node_fetch(url.toString(), {
method: "POST",
body: JSON.stringify(parametros),
headers: { "Content-Type": "application/json" },
})
.then((r) => r.json())
.catch((e) =>
respostaComuns.erro("Erro ao enviar registros", [e.message]),
)
.then((r) => r as tipoResposta<any>)
if (cliente.ver_log)
console.log(
`[PILÃO]: buscar dados de "${JSON.stringify(parametros)}" para "${url.href}".`,
)
return resp
}
const url = (): string => {
const vUrl = new URL(
`${urlPilao(cliente.emDesenvolvimento).site}/${tipoVisao}/${cliente.produto}/${cliente.conta}`,
)
const serie = encodeURIComponent(JSON.stringify(parametros, null, 2))
if (cliente.ver_log)
console.log(
`[PILÃO]: Serie Consultar url de "${JSON.stringify(serie)}" para "${vUrl.href}".`,
)
return `${vUrl.href}?serie=${serie}`
}
return {
dados,
url,
}
}

View file

@ -1,7 +1,5 @@
import { deletar_registros, zp_deletar_registros } from "./_deletar_registros"
export { PREFIXO_PILAO, urlPilao } from "./variaveis"
import {
enviar_registros,
zp_enviar_registros,
zp_registrar_base_dados,
} from "./_enviar_registros"
@ -9,25 +7,32 @@ import {
operadores_permitidos_por_tipo,
operadores_pilao,
validarZ,
z_tipos_dados_registro,
zp_deletar_registros,
zp_produto_conta,
} from "./variaveis"
import { serie_consultar, z_filtro } from "./_serie_consultar"
import { extruturas_de_campos, visoes } from "./visoes"
export * from "./Pilao"
export * from "./Pilao/pilao-api"
export * from "./Pilao/tipagem"
import { z_filtro } from "./_serie_consultar"
import { extruturas_de_campos } from "./visoes"
import { visoes_pilao } from "./visoes/listaDeVisoes"
export const pPilao = {
zp_deletar_registros,
zp_registrar_base_dados,
enviar_registros,
z_tipos_dados_registro,
zp_enviar_registros,
serie_consultar,
zp_produto_conta,
validarZ,
deletar_registros,
zp_deletar_registros,
operadores_pilao,
operadores_permitidos_por_tipo,
z_filtro,
visoes,
...visoes,
visoes_pilao,
...visoes_pilao,
extruturas_de_campos,
}

View file

@ -1,6 +1,11 @@
import { respostaComuns } from "p-respostas"
import { z } from "zod"
export const zp_deletar_registros = z.object({
tabela: z.string(),
codigos: z.array(z.string()),
})
export const zAmbiente = z.enum(["desenvolvimento", "producao"])
export const PREFIXO_PILAO = "/pilao-de-dados"
@ -27,7 +32,7 @@ export const zp_produto_conta = z.object({
ver_log: z.boolean().optional(),
})
export const z_tipo_coluna_base_dados = z.enum([
export const z_tipos_dados_registro = z.enum([
"texto",
"numero",
"confirmacao",
@ -42,7 +47,7 @@ export const z_tipo_coluna_base_dados = z.enum([
export const operadores_pilao = z.enum(["=", "!=", ">", "<", ">=", "<=", "∩"])
export const operadores_permitidos_por_tipo: {
[key in z.infer<typeof z_tipo_coluna_base_dados>]: z.infer<
[key in z.infer<typeof z_tipos_dados_registro>]: z.infer<
typeof operadores_pilao
>[]
} = {

View file

@ -0,0 +1,16 @@
import type { visoes_pilao } from "../listaDeVisoes"
import type { tipo_estrutura_visao_grafico } from "../tipagem"
import { z_contagem_em_barra_vertical } from "./z_contagem_em_barra_vertical"
import { z_contagem_em_pizza } from "./z_contagem_em_pizza"
import { z_soma_em_barra_vertical } from "./z_soma_em_barra_vertical"
import { z_tabela } from "./z_tabela"
/** Cria a estrutura de campos para insersão de dados */
export const extruturas_de_campos: {
[T in keyof typeof visoes_pilao]: tipo_estrutura_visao_grafico<T>
} = {
z_contagem_em_barra_vertical,
z_contagem_em_pizza,
z_soma_em_barra_vertical,
z_tabela,
}

View file

@ -0,0 +1,56 @@
// usar describe para definir o tipo de campo para render do componente
import type { tipo_estrutura_visao_grafico } from "../tipagem"
/** Cria a estrutura de campos para insersão de dados */
export const z_contagem_em_barra_vertical: tipo_estrutura_visao_grafico<"z_contagem_em_barra_vertical"> =
{
visao: "z_contagem_em_barra_vertical",
rotulo: "Contagem em Barra Vertical",
tabela: ({ tabela }) => tabela,
descricao: ({
tabela,
descricao_pelo_usuario,
colanuEixoX,
filtros,
colunaAgrupamento,
}) => {
if (String(descricao_pelo_usuario || "").trim())
return String(descricao_pelo_usuario || "").trim()
return `Contagem de ${tabela} por ${colanuEixoX}${
!filtros?.length
? ""
: `, quando ${filtros
.map(
({ coluna, operador, valor }) =>
`${coluna} ${operador} ${valor}`,
)
.join(", ")}`
}${
!colunaAgrupamento?.length
? ""
: `, agrupado por ${colunaAgrupamento.join(", ")}`
}.`
},
campos: {
tabela: { rotulo: "Tabela", tipo_campo: "tabela", order: 1 },
colanuEixoX: {
rotulo: "Coluna do Eixo X",
tipo_campo: "coluna",
order: 2,
},
colunaAgrupamento: {
rotulo: "Colunas de Agrupamento",
tipo_campo: "lista_colunas",
order: 3,
},
descricao_pelo_usuario: {
rotulo: "Descrição (opcional)",
tipo_campo: "texto",
order: 4,
},
filtros: { rotulo: "Filtros", tipo_campo: "lista_filtros", order: 5 },
},
}

View file

@ -0,0 +1,36 @@
// usar describe para definir o tipo de campo para render do componente
import type { tipo_estrutura_visao_grafico } from "../tipagem"
/** Cria a estrutura de campos para insersão de dados */
export const z_contagem_em_pizza: tipo_estrutura_visao_grafico<"z_contagem_em_pizza"> =
{
visao: "z_contagem_em_pizza",
rotulo: "Contagem em Pizza",
tabela: ({ tabela }) => tabela,
descricao: ({ tabela, descricao_pelo_usuario, classes, filtros }) => {
if (String(descricao_pelo_usuario || "").trim())
return String(descricao_pelo_usuario || "").trim()
return `Contagem de ${tabela} por ${classes}${
!filtros?.length
? ""
: `, quando ${filtros
.map(
({ coluna, operador, valor }) =>
`${coluna} ${operador} ${valor}`,
)
.join(", ")}`
}.`
},
campos: {
tabela: { rotulo: "Tabela", tipo_campo: "tabela", order: 1 },
classes: { rotulo: "Classes", tipo_campo: "coluna", order: 2 },
descricao_pelo_usuario: {
rotulo: "Descrição (opcional)",
tipo_campo: "texto",
order: 3,
},
filtros: { rotulo: "Filtros", tipo_campo: "lista_filtros", order: 4 },
},
}

View file

@ -0,0 +1,68 @@
// usar describe para definir o tipo de campo para render do componente
import type { tipo_estrutura_visao_grafico } from "../tipagem"
/** Cria a estrutura de campos para insersão de dados */
export const z_soma_em_barra_vertical: tipo_estrutura_visao_grafico<"z_soma_em_barra_vertical"> =
{
visao: "z_soma_em_barra_vertical",
rotulo: "Soma em Barra Vertical",
tabela: ({ tabela }) => tabela,
descricao: ({
descricao_pelo_usuario,
colanuEixoX,
filtros,
colunaAgrupamento,
colunaSoma,
}) => {
if (String(descricao_pelo_usuario || "").trim())
return String(descricao_pelo_usuario || "").trim()
return `Soma de ${colunaSoma} por ${colanuEixoX}${
!filtros?.length
? ""
: `, quando ${filtros
.map(
({ coluna, operador, valor }) =>
`${coluna} ${operador} ${valor}`,
)
.join(", ")}`
}${
!colunaAgrupamento?.length
? ""
: `, agrupado por ${colunaAgrupamento.join(", ")}`
}.`
},
campos: {
tabela: { rotulo: "Tabela", tipo_campo: "tabela", order: 1 },
colunaSoma: {
rotulo: "Coluna de Somatória",
tipo_campo: "coluna",
order: 2,
},
unidadeSoma: {
rotulo: "Unidade de Somatória",
tipo_campo: "texto",
order: 3,
},
colanuEixoX: {
rotulo: "Coluna do Eixo X",
tipo_campo: "coluna",
order: 4,
},
colunaAgrupamento: {
rotulo: "Colunas de Agrupamento",
tipo_campo: "lista_colunas",
order: 5,
},
descricao_pelo_usuario: {
rotulo: "Descrição (opcional)",
tipo_campo: "texto",
order: 6,
},
filtros: { rotulo: "Filtros", tipo_campo: "lista_filtros", order: 5 },
},
}

View file

@ -0,0 +1,45 @@
// usar describe para definir o tipo de campo para render do componente
import type { tipo_estrutura_visao_grafico } from "../tipagem"
/** Cria a estrutura de campos para insersão de dados */
export const z_tabela: tipo_estrutura_visao_grafico<"z_tabela"> = {
visao: "z_tabela",
rotulo: "Tabela",
tabela: ({ tabela }) => tabela,
descricao: ({ tabela, descricao_pelo_usuario, filtros }) => {
if (String(descricao_pelo_usuario || "").trim())
return String(descricao_pelo_usuario || "").trim()
return `Consulta na ${tabela} ${
!filtros?.length
? ""
: `, quando ${filtros
.map(
({ coluna, operador, valor }) => `${coluna} ${operador} ${valor}`,
)
.join(", ")}`
}.`
},
campos: {
tabela: { rotulo: "Tabela", tipo_campo: "tabela", order: 1 },
colunas: { rotulo: "Colunas", tipo_campo: "lista_colunas", order: 2 },
descricao_pelo_usuario: {
rotulo: "Descrição (opcional)",
tipo_campo: "texto",
order: 3,
},
coluna_ordem: {
rotulo: "Coluna de Ordem",
tipo_campo: "coluna",
order: 4,
},
direcao_ordem: {
rotulo: "Direção de Ordem",
tipo_campo: "ordem",
order: 5,
},
filtros: { rotulo: "Filtros", tipo_campo: "lista_filtros", order: 6 },
},
}

View file

@ -1,187 +1 @@
import { z } from "zod"
import { z_filtro } from "../_serie_consultar"
// usar describe para definir o tipo de campo para render do componente
const z_tipos_campos = z.enum([
"tabela",
"coluna",
"texto",
"lista_colunas",
"lista_filtros",
"ordem",
])
export const z_contagem_em_barra_vertical = z.object({
tabela: z.string(),
colanuEixoX: z.string(),
colunaAgrupamento: z.string().array().optional(),
filtros: z_filtro.array().optional(),
descricao_pelo_usuario: z.string().optional(),
})
export const z_contagem_em_pizza = z.object({
tabela: z.string(),
classes: z.string(),
filtros: z_filtro.array().optional(),
descricao_pelo_usuario: z.string().optional(),
})
export const z_tabela = z.object({
tabela: z.string(),
colunas: z.string().array(),
coluna_ordem: z.string().optional(),
direcao_ordem: z.enum(["asc", "desc", "1", "-1"]).optional(),
filtros: z_filtro.array().optional(),
descricao_pelo_usuario: z.string().optional(),
})
export const visoes = {
z_contagem_em_barra_vertical,
z_contagem_em_pizza,
z_tabela,
}
/** Cria a estrutura de campos para insersão de dados */
export const extruturas_de_campos: {
[z in keyof typeof visoes]: {
/** Nome da Visão */
visao: z
/** Rotulo */
rotulo: string
/** Retorna a tabela Referente ao Registro */
tabela: (_: z.infer<(typeof visoes)[z]>) => string
/** Descrição */
descricao: (_: z.infer<(typeof visoes)[z]>) => string
/** Lista os campos e suas configurações */
campos: {
[c in keyof Required<z.infer<(typeof visoes)[z]>>]: {
rotulo: string
tipo_campo: z.infer<typeof z_tipos_campos>
order: number
}
}
}
} = {
z_contagem_em_barra_vertical: {
visao: "z_contagem_em_barra_vertical",
rotulo: "Contagem em Barra Vertical",
tabela: ({ tabela }) => tabela,
descricao: ({
tabela,
descricao_pelo_usuario,
colanuEixoX,
filtros,
colunaAgrupamento,
}) => {
if (String(descricao_pelo_usuario || "").trim())
return String(descricao_pelo_usuario || "").trim()
return `Contagem de ${tabela} por ${colanuEixoX}${
!filtros?.length
? ""
: `, quando ${filtros
.map(
({ coluna, operador, valor }) =>
`${coluna} ${operador} ${valor}`,
)
.join(", ")}`
}${
!colunaAgrupamento?.length
? ""
: `, agrupado por ${colunaAgrupamento.join(", ")}`
}.`
},
campos: {
tabela: { rotulo: "Tabela", tipo_campo: "tabela", order: 1 },
colanuEixoX: {
rotulo: "Coluna do Eixo X",
tipo_campo: "coluna",
order: 2,
},
colunaAgrupamento: {
rotulo: "Colunas de Agrupamento",
tipo_campo: "lista_colunas",
order: 3,
},
descricao_pelo_usuario: {
rotulo: "Descrição (opcional)",
tipo_campo: "texto",
order: 4,
},
filtros: { rotulo: "Filtros", tipo_campo: "lista_filtros", order: 5 },
},
},
z_contagem_em_pizza: {
visao: "z_contagem_em_pizza",
rotulo: "Contagem em Pizza",
tabela: ({ tabela }) => tabela,
descricao: ({ tabela, descricao_pelo_usuario, classes, filtros }) => {
if (String(descricao_pelo_usuario || "").trim())
return String(descricao_pelo_usuario || "").trim()
return `Contagem de ${tabela} por ${classes}${
!filtros?.length
? ""
: `, quando ${filtros
.map(
({ coluna, operador, valor }) =>
`${coluna} ${operador} ${valor}`,
)
.join(", ")}`
}.`
},
campos: {
tabela: { rotulo: "Tabela", tipo_campo: "tabela", order: 1 },
classes: { rotulo: "Classes", tipo_campo: "coluna", order: 2 },
descricao_pelo_usuario: {
rotulo: "Descrição (opcional)",
tipo_campo: "texto",
order: 3,
},
filtros: { rotulo: "Filtros", tipo_campo: "lista_filtros", order: 4 },
},
},
z_tabela: {
visao: "z_tabela",
rotulo: "Tabela",
tabela: ({ tabela }) => tabela,
descricao: ({ tabela, descricao_pelo_usuario, filtros }) => {
if (String(descricao_pelo_usuario || "").trim())
return String(descricao_pelo_usuario || "").trim()
return `Consulta na ${tabela} ${
!filtros?.length
? ""
: `, quando ${filtros
.map(
({ coluna, operador, valor }) =>
`${coluna} ${operador} ${valor}`,
)
.join(", ")}`
}.`
},
campos: {
tabela: { rotulo: "Tabela", tipo_campo: "tabela", order: 1 },
colunas: { rotulo: "Colunas", tipo_campo: "lista_colunas", order: 2 },
descricao_pelo_usuario: {
rotulo: "Descrição (opcional)",
tipo_campo: "texto",
order: 3,
},
coluna_ordem: {
rotulo: "Coluna de Ordem",
tipo_campo: "coluna",
order: 4,
},
direcao_ordem: {
rotulo: "Direção de Ordem",
tipo_campo: "ordem",
order: 5,
},
filtros: { rotulo: "Filtros", tipo_campo: "lista_filtros", order: 6 },
},
},
}
export * from "./estrutura_de_campos"

View file

@ -0,0 +1,43 @@
import { z } from "zod"
import { z_filtro } from "../_serie_consultar"
export const z_contagem_em_barra_vertical = z.object({
tabela: z.string(),
colanuEixoX: z.string(),
colunaAgrupamento: z.string().array().optional(),
filtros: z_filtro.array().optional(),
descricao_pelo_usuario: z.string().optional(),
})
export const z_soma_em_barra_vertical = z.object({
tabela: z.string(),
colanuEixoX: z.string(),
colunaSoma: z.string(),
unidadeSoma: z.string().optional(),
colunaAgrupamento: z.string().array().optional(),
filtros: z_filtro.array().optional(),
descricao_pelo_usuario: z.string().optional(),
})
export const z_contagem_em_pizza = z.object({
tabela: z.string(),
classes: z.string(),
filtros: z_filtro.array().optional(),
descricao_pelo_usuario: z.string().optional(),
})
export const z_tabela = z.object({
tabela: z.string(),
colunas: z.string().array(),
coluna_ordem: z.string().optional(),
direcao_ordem: z.enum(["asc", "desc", "1", "-1"]).optional(),
filtros: z_filtro.array().optional(),
descricao_pelo_usuario: z.string().optional(),
})
export const visoes_pilao = {
z_contagem_em_barra_vertical,
z_contagem_em_pizza,
z_tabela,
z_soma_em_barra_vertical,
}

View file

@ -0,0 +1,31 @@
import { z } from "zod"
import type { visoes_pilao } from "./listaDeVisoes"
export const z_tipos_campos_reg_grafico = z.enum([
"tabela",
"coluna",
"texto",
"lista_colunas",
"lista_filtros",
"ordem",
])
export type tipo_estrutura_visao_grafico<T extends keyof typeof visoes_pilao> =
{
/** Nome da Visão */
visao: T
/** Rotulo */
rotulo: string
/** Retorna a tabela Referente ao Registro */
tabela: (_: z.infer<(typeof visoes_pilao)[T]>) => string
/** Descrição */
descricao: (_: z.infer<(typeof visoes_pilao)[T]>) => string
/** Lista os campos e suas configurações */
campos: {
[c in keyof Required<z.infer<(typeof visoes_pilao)[T]>>]: {
rotulo: string
tipo_campo: z.infer<typeof z_tipos_campos_reg_grafico>
order: number
}
}
}