Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@embracesql/postgres

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@embracesql/postgres - npm Package Compare versions

Comparing version 0.0.14 to 0.1.0

src/generator/pgoperator/index.ts

6

package.json
{
"name": "@embracesql/postgres",
"version": "0.0.14",
"version": "0.1.0",
"description": "EmbraceSQL shared library for talking to postgres. Used in Node.",

@@ -13,3 +13,3 @@ "type": "module",

"dependencies": {
"@embracesql/shared": "^0.0.14",
"@embracesql/shared": "^0.1.0",
"glob": "^10.3.10",

@@ -23,3 +23,3 @@ "object-hash": "^3.0.0",

},
"gitHead": "4f59f194e44a54194d5f8d1344a1c0adadfd4958"
"gitHead": "6f0191319a0be4f5ebddc92fe81fb0b729521e87"
}

@@ -7,2 +7,4 @@ import { Context } from "../context";

export { generateSchemaDefinitions } from "./typescript/generateSchemaDefinitions";
export { registerOperatorOverride } from "./pgoperator";
export { registerOverride } from "./pgtype/overrides/_overrides";

@@ -9,0 +11,0 @@ /**

@@ -75,3 +75,2 @@ import { Context, PostgresTypecast } from "../../context";

// default is just 'a string of it'
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
if (x === null) return null;

@@ -86,6 +85,4 @@ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions

*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
parseFromPostgres(context: Context, x: unknown) {
// default is just to echo it -- which is almost never correct
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return x;

@@ -103,3 +100,2 @@ }

serialize: (x) => this.serializeToPostgres(context, x),
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
parse: (x) => this.parseFromPostgres(context, x),

@@ -106,0 +102,0 @@ };

import { groupBy } from "../../util";
import { operatorFor } from "../pgoperator";
import { PGTypes } from "./pgtype";

@@ -16,2 +17,3 @@ import { GenerationContext, IndexNode, TableNode } from "@embracesql/shared";

name: string;
operators: string[];
};

@@ -29,11 +31,11 @@

)) as unknown as IndexRow[];
return new PGIndexes(context, indexRows);
return new PGIndexes(indexRows);
}
indexesByTableTypeOid: Record<number, PGIndex[]>;
private constructor(context: PGIndexesContext, indexRows: IndexRow[]) {
private constructor(indexRows: IndexRow[]) {
this.indexesByTableTypeOid = groupBy(
indexRows,
(r) => r.tabletypeoid,
(r) => new PGIndex(context, r),
(r) => new PGIndex(r),
);

@@ -49,6 +51,3 @@ }

export class PGIndex {
constructor(
context: PGIndexesContext,
public index: IndexRow,
) {}
constructor(public index: IndexRow) {}

@@ -62,4 +61,5 @@ loadAST(context: GenerationContext, table: TableNode) {

context.database.resolveType(this.index.indexrelid),
this.index.operators.map(operatorFor),
);
}
}

@@ -103,30 +103,32 @@ import { Context, PostgresProcTypecast } from "../../../context";

// inputs -- which may have no attributes
// this type won't exist in the database catalog - we're treating
// all the parameters which are in a flat argument list style
// as a structured object single 'parameter'
const parametersType = new CompositeTypeNode(
PARAMETERS,
node,
"", // no identifier, this is not a type in the database
);
if (proc.proc.proargtypes.length > 0) {
// inputs -- which are not required because of no-arg functions
// this type won't exist in the database catalog - we're treating
// all the parameters which are in a flat argument list style
// as a structured object single 'parameter'
const parametersType = new CompositeTypeNode(
PARAMETERS,
node,
"", // no identifier, this is not a type in the database
);
proc.proc.proargtypes
.flatMap((t) => t)
.forEach((oid, i) => {
const type = context.database.resolveType(oid)!;
new AttributeNode(
parametersType,
proc.proc.proargnames[i]
? proc.proc.proargnames[i]
: `argument_${i}`,
i,
type,
i > proc.proc.proargtypes.length - proc.proc.pronargdefaults,
true,
proc.proc.proargnames[i] !== undefined,
);
});
// inputs
new ParametersNode(node, parametersType);
proc.proc.proargtypes
.flatMap((t) => t)
.forEach((oid, i) => {
const type = context.database.resolveType(oid)!;
new AttributeNode(
parametersType,
proc.proc.proargnames[i]
? proc.proc.proargnames[i]
: `argument_${i}`,
i,
type,
i > proc.proc.proargtypes.length - proc.proc.pronargdefaults,
true,
proc.proc.proargnames[i] !== undefined,
);
});
// inputs
new ParametersNode(node, parametersType);
}
}

@@ -133,0 +135,0 @@ }

@@ -10,3 +10,2 @@ import { Context } from "../../context";

GenerationContext,
cleanIdentifierForTypescript,
compositeAttribute,

@@ -75,20 +74,2 @@ escapeCompositeValue,

typescriptTypeDefinition(context: GenerationContext) {
// all the fields -- and a partial type to allow filling out with
// various sub selects
const nameAndType = this.attributes.map((a) => {
const attributeType = context.database.resolveType(a.attribute.atttypid)!;
const attributeName = `${camelCase(
cleanIdentifierForTypescript(a.attribute.attname),
)}`;
const attributeTypeName = a.notNull
? attributeType.typescriptNamespacedName
: `Nullable<${attributeType.typescriptNamespacedName}>`;
return `${attributeName}${
a.isOptional ? "?" : ""
}: ${attributeTypeName};`;
});
return `{${nameAndType.join(" ")}}`;
}
get sqlColumns() {

@@ -95,0 +76,0 @@ return this.attributes.map((a) => a.postgresName).join(",");

@@ -11,6 +11,6 @@ import { postgresToTypescript } from "./shared";

const parameters = ``;
const options = `options?: ${node.table.typescriptNamespacedName}.Options`;
const returns = `Promise<${node.table.type.typescriptNamespacedName}[]>`;
// query using postgres driver bindings to the index
const sql = `
--
SELECT

@@ -20,8 +20,12 @@ ${node.table.allColumns.map((c) => c.name).join(",")}

${node.table.databaseName}
\${sql.unsafe(\`\${orderBy}\`)}
LIMIT \${options?.limitNumberOfRows ?? Number.MAX_SAFE_INTEGER}
OFFSET \${options?.offsetNumberOfRows ?? 0}
`;
return [
`async ${node.typescriptPropertyName}(${parameters}) : ${returns}{`,
`async ${node.typescriptPropertyName}(${parameters}${options}) : ${returns}{`,
`
const sql = this.database.context.sql;
const typed = sql.typed as unknown as PostgresTypecasts;
const orderBy = options?.sort ? \`ORDER BY \${options.sort.join(",")}\` : "";
`,

@@ -28,0 +32,0 @@ `const response = await sql\`${sql}\``,

@@ -16,4 +16,4 @@ import { postgresToTypescript, sqlPredicate } from "./shared";

async before(context: GenerationContext, node: ReadOperationNode) {
const generationBuffer = [""];
const parameters = `${PARAMETERS}: ${node.index.type.typescriptNamespacedName}`;
const options = `options?: ${node.index.table.typescriptNamespacedName}.Options`;
const returns = node.index.unique

@@ -23,12 +23,2 @@ ? `Promise<${node.index.table.type.typescriptNamespacedName}>`

generationBuffer.push(
`async ${node.typescriptPropertyName}(${parameters}) : ${returns}{`,
);
generationBuffer.push(
`
console.assert(parameters);
const sql = this.database.context.sql;
const typed = sql.typed as unknown as PostgresTypecasts;
`,
);
// query using postgres driver bindings to the index

@@ -43,15 +33,23 @@ const sql = `

${sqlPredicate(context, node.index, PARAMETERS)}
\${sql.unsafe(\`\${orderBy}\`)}
LIMIT \${options?.limitNumberOfRows ?? Number.MAX_SAFE_INTEGER}
OFFSET \${options?.offsetNumberOfRows ?? 0}
`;
generationBuffer.push(`const response = await sql\`${sql}\``);
return [
`async ${node.typescriptPropertyName}(${parameters}, ${options}) : ${returns}{`,
`
console.assert(parameters);
const sql = this.database.context.sql;
const typed = sql.typed as unknown as PostgresTypecasts;
const orderBy = options?.sort ? \`ORDER BY \${options.sort.join(",")}\` : "";
`,
`const response = await sql\`${sql}\``,
generationBuffer.push(
`return ${postgresToTypescript(context, node.index.table.type)}${
node.index.unique ? "[0]" : ""
}`,
);
generationBuffer.push(`}`);
return generationBuffer.join("\n");
`}`,
].join("\n");
},
};

@@ -99,4 +99,13 @@ /**

) {
// looking up the operator from the index - default needs to be =
// but can be different for % say in pg_trgm
return node.type.attributes
.map((a) => `${a.name} = ${postgresValueExpression(context, a, holder)}`)
.map(
(a, i) =>
`${a.name} ${node.operators[i]} ${postgresValueExpression(
context,
a,
holder,
)}`,
)
.join(" AND ");

@@ -103,0 +112,0 @@ }

@@ -167,6 +167,8 @@ import { AllOperation } from "./autocrud/all";

// function call start, passing in parameters
const parameters = node.parametersType
? `parameters : ${node.parametersType?.typescriptNamespacedName}`
: ``;
return [
await NestedNamedClassVisitor.before(context, node),
`async call(parameters : ${node.parametersType?.typescriptNamespacedName}) {`,
` console.assert(parameters);`,
`async call(${parameters}) {`,
` ${parseResult}`,

@@ -173,0 +175,0 @@ ` const sql = this.database.context.sql;`,

@@ -23,3 +23,3 @@ import {

node.typescriptNamespacedName
}.call": async (request: EmbraceSQLRequest<object, object>) => database.${
}.call": async (request: EmbraceSQLRequest<object, object, object>) => database.${
node.typescriptNamespacedName

@@ -57,3 +57,3 @@ }.call(${callee.join(",")}),`;

`
async dispatch(request: EmbraceSQLRequest<object, object>) {
async dispatch(request: EmbraceSQLRequest<object, object, object>) {
if (!this.dispatchMap[request.operation]) {

@@ -79,3 +79,3 @@ throw new Error(\`\${request.operation} not available\`);

node.typescriptNamespacedPropertyName
}": async (request: EmbraceSQLRequest<object, object>) => database.${
}": async (request: EmbraceSQLRequest<object, object, object>) => database.${
node.typescriptNamespacedPropertyName

@@ -87,6 +87,14 @@ }(${callee.join(",")}),`;

before: async (_: GenerationContext, node: AllOperationNode) => {
const callee: string[] = [];
callee.push(
`request.options as ${node.table.typescriptNamespacedName}.Options`,
);
return [
`
"${node.typescriptNamespacedPropertyName}": async (request: EmbraceSQLRequest<object, object>) =>
database.${node.typescriptNamespacedPropertyName}(),
"${
node.typescriptNamespacedPropertyName
}": async (request: EmbraceSQLRequest<object, object, object>) =>
database.${node.typescriptNamespacedPropertyName}(${callee.join(
",",
)}),
`,

@@ -101,6 +109,7 @@ ].join("\n");

`request.parameters as ${node.index.type.typescriptNamespacedName}`,
`request.options as ${node.index.table.typescriptNamespacedName}.Options`,
);
return `"${
node.typescriptNamespacedPropertyName
}": async (request: EmbraceSQLRequest<object, object>) => database.${
}": async (request: EmbraceSQLRequest<object, object, object>) => database.${
node.typescriptNamespacedPropertyName

@@ -121,3 +130,3 @@ }(${callee.join(",")}),`;

node.typescriptNamespacedPropertyName
}": async (request: EmbraceSQLRequest<object, object>) => database.${
}": async (request: EmbraceSQLRequest<object, object, object>) => database.${
node.typescriptNamespacedPropertyName

@@ -135,3 +144,3 @@ }(${callee.join(",")}),`;

node.typescriptNamespacedPropertyName
}": async (request: EmbraceSQLRequest<object, object>) => database.${
}": async (request: EmbraceSQLRequest<object, object, object>) => database.${
node.typescriptNamespacedPropertyName

@@ -138,0 +147,0 @@ }(${callee.join(",")}),`;

@@ -5,2 +5,3 @@ import { GenerationContext } from "..";

import { generatePrimaryKeyPickers } from "./generatePrimaryKeyPickers";
import { generateTypeComparison } from "./generateTypeComparison";
import { generateTypeGuards } from "./generateTypeGuards";

@@ -11,5 +12,8 @@ import { generateTypeParsers } from "./generateTypeParsers";

AbstractTypeNode,
ColumnNode,
CompositeTypeNode,
NamespaceVisitor,
VALUES,
cleanIdentifierForTypescript,
isNodeType,
} from "@embracesql/shared";

@@ -20,2 +24,57 @@ import { GenerationContext as GC } from "@embracesql/shared";

/**
* All available columns -- generate the sort option permumtations
* as an enum.
*/
function sortOptions(columns: ColumnNode[]) {
return [
`enum SortOptions {`,
`${columns
.map((c) => `${c.typescriptPropertyName}Ascending = "${c.name} ASC",`)
.join("\n")}`,
`${columns
.map((c) => `${c.typescriptPropertyName}Descending = "${c.name} DESC",`)
.join("\n")}`,
`}`,
].join("\n");
}
/**
* All available columns -- generate column metadata.
*/
async function columnMetadata(context: GC, type: CompositeTypeNode) {
return await type.visit({
...context,
handlers: {
[ASTKind.CompositeType]: {
before: async () => `export const Columns = {`,
after: async (_, node) => {
return [
`}`, // close columns
// convenience iterable column names
`export const ColumnNames = [${node.attributes
.map((c) => `"${c.typescriptName}"`)
.join(",")}] as const;`,
`export const FieldNames = [${node.attributes
.map((c) => `"${c.typescriptPropertyName}"`)
.join(",")}] as const;`,
`type FieldNamesType = typeof FieldNames[number];`,
].join("\n");
},
},
[ASTKind.Attribute]: {
before: async (_, node) => {
// each column worth of metadata including a type constant
return [
`${node.typescriptName}: {`,
` typeName: "${node.type.typescriptNamespacedName}",`,
` fieldName: "${node.typescriptPropertyName}" as FieldNamesType,`,
`},`,
].join("\n");
},
},
},
});
}
/**
* Generate TypeScript type definitions for all types available

@@ -44,3 +103,3 @@ * in the database schema catalog along with request/response message

import {UUID, JsDate, JSONValue, JSONObject, Empty, Nullable, NullableMembers, undefinedIsNull, nullIsUndefined, NEVER} from "@embracesql/shared";
import type { PartiallyOptional } from "@embracesql/shared";
import type { PartiallyOptional, PossiblyEmpty, ReadOptions, Sort } from "@embracesql/shared";

@@ -68,2 +127,9 @@ `,

handlers: {
[ASTKind.Database]: {
before: async () => {
return [
// schema wide shared
].join("\n");
},
},
[ASTKind.Schema]: NamespaceVisitor,

@@ -93,9 +159,5 @@ [ASTKind.Types]: NamespaceVisitor,

// empty placeholder row used in UI adding
`export function emptyRow() {`,
`export function emptyRow() : PossiblyEmpty<${node.type.typescriptNamespacedName}> {`,
` return ${emptyTypescriptRow(context, node.type)};`,
`}`,
].join("\n");
},
after: async (context, node) => {
return [
// exhaustive -- if there is no primary key, say so explicitly

@@ -116,5 +178,12 @@ node.primaryKey ? "" : `export type PrimaryKey = never;`,

}, Optional & PrimaryKey>`,
await NamespaceVisitor.after(context, node),
// read options exist per table
`export ${sortOptions(node.allColumns)};`,
`export type Options = ReadOptions & {`,
` sort?: SortOptions[],`,
`};`,
// a convenient metadata constant for all columns
await columnMetadata(context, node.type),
].join("\n");
},
after: NamespaceVisitor.after,
},

@@ -131,3 +200,28 @@ [ASTKind.Index]: {

[ASTKind.Procedures]: NamespaceVisitor,
[ASTKind.Procedure]: NamespaceVisitor,
[ASTKind.Procedure]: {
before: async (context, node) => {
return [
await NamespaceVisitor.before(context, node),
isNodeType(node.resultsType, ASTKind.CompositeType)
? await columnMetadata(context, node.resultsType)
: "",
].join("\n");
},
after: NamespaceVisitor.after,
},
[ASTKind.DomainType]: TypeDefiner,
[ASTKind.ArrayType]: TypeDefiner,
[ASTKind.Scripts]: NamespaceVisitor,
[ASTKind.ScriptFolder]: NamespaceVisitor,
[ASTKind.Script]: {
before: async (context, node) => {
return [
await NamespaceVisitor.before(context, node),
isNodeType(node.resultsType, ASTKind.CompositeType)
? await columnMetadata(context, node.resultsType)
: "",
].join("\n");
},
after: NamespaceVisitor.after,
},
[ASTKind.CompositeType]: {

@@ -143,7 +237,2 @@ // composite types are a name and AttributeNode(s) will fill the body

},
[ASTKind.DomainType]: TypeDefiner,
[ASTKind.ArrayType]: TypeDefiner,
[ASTKind.Scripts]: NamespaceVisitor,
[ASTKind.ScriptFolder]: NamespaceVisitor,
[ASTKind.Script]: NamespaceVisitor,
[ASTKind.Attribute]: {

@@ -170,4 +259,5 @@ before: async (_, node) => {

generationBuffer.push(await generateTypeGuards(context));
generationBuffer.push(await generateTypeComparison(context));
return generationBuffer.join("\n");
};

@@ -20,7 +20,2 @@ import {

handlers: {
[ASTKind.Database]: {
before: async () => {
return `// begin type guards`;
},
},
[ASTKind.Schema]: NamespaceVisitor,

@@ -27,0 +22,0 @@ [ASTKind.Tables]: NamespaceVisitor,

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc