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

@compas/store

Package Overview
Dependencies
Maintainers
1
Versions
196
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@compas/store - npm Package Compare versions

Comparing version 0.0.137 to 0.0.138

2

index.d.ts

@@ -120,3 +120,2 @@ import * as stdlib from "@compas/stdlib";

export interface MigrateFile {
namespace: string;
number: number;

@@ -136,3 +135,2 @@ repeatable: boolean;

files: MigrateFile[];
namespaces: string[];
storedHashes: Record<string, string>;

@@ -139,0 +137,0 @@ sql: Postgres;

@@ -1,3 +0,1 @@

import { dirnameForModule } from "@compas/stdlib";
export {

@@ -53,4 +51,2 @@ newMinioClient,

export const migrations = `${dirnameForModule(import.meta)}/migrations`;
export { structure as storeStructure } from "./src/generated/common/structure.js";

@@ -57,0 +53,0 @@ export { queries as storeQueries } from "./src/generated/database/index.js";

6

package.json
{
"name": "@compas/store",
"version": "0.0.137",
"version": "0.0.138",
"description": "Postgres & S3-compatible wrappers for common things",

@@ -17,3 +17,3 @@ "main": "./index.js",

"dependencies": {
"@compas/stdlib": "0.0.137",
"@compas/stdlib": "0.0.138",
"@types/minio": "7.0.7",

@@ -45,3 +45,3 @@ "mime-types": "2.1.30",

},
"gitHead": "855cf3b108f158b3f9dd8ee0777b1ab8d7a1a5a4"
"gitHead": "3052deb49d7bf1fa6e26b8fc3375a8dd06012668"
}

@@ -951,14 +951,13 @@ // Generated by @compas/code-gen

joinQb.append(query`LEFT JOIN LATERAL (
SELECT array_remove(array_agg(to_jsonb(fg.*) || jsonb_build_object(${query([
SELECT ARRAY (SELECT to_jsonb(fg.*) || jsonb_build_object(${query([
joinedKeys.join(","),
])}) ORDER BY ${fileGroupOrderBy(
])})
${internalQueryFileGroup(builder.children, query`AND fg."parent" = fg2."id"`)}
ORDER BY ${fileGroupOrderBy(
builder.children.orderBy,
builder.children.orderBySpec,
"fg.",
)}), NULL) as "result"
${internalQueryFileGroup(builder.children, query`AND fg."parent" = fg2."id"`)}
GROUP BY fg2."id"
ORDER BY fg2."id"
)}
${offsetLimitQb}
) as "fg_fg_1" ON TRUE`);
) as result) as "fg_fg_1" ON TRUE`);
}

@@ -1185,14 +1184,13 @@ return query`

joinQb.append(query`LEFT JOIN LATERAL (
SELECT array_remove(array_agg(to_jsonb(fg2.*) || jsonb_build_object(${query([
SELECT ARRAY (SELECT to_jsonb(fg2.*) || jsonb_build_object(${query([
joinedKeys.join(","),
])}) ORDER BY ${fileGroupOrderBy(
])})
${internalQueryFileGroup2(builder.children, query`AND fg2."parent" = fg."id"`)}
ORDER BY ${fileGroupOrderBy(
builder.children.orderBy,
builder.children.orderBySpec,
"fg2.",
)}), NULL) as "result"
${internalQueryFileGroup2(builder.children, query`AND fg2."parent" = fg."id"`)}
GROUP BY fg."id"
ORDER BY fg."id"
)}
${offsetLimitQb}
) as "fg_fg_1" ON TRUE`);
) as result) as "fg_fg_1" ON TRUE`);
}

@@ -1199,0 +1197,0 @@ return query`

@@ -740,9 +740,5 @@ // Generated by @compas/code-gen

joinQb.append(query`LEFT JOIN LATERAL (
SELECT array_remove(array_agg(to_jsonb(fgv.*) || jsonb_build_object(${query([
SELECT ARRAY (SELECT to_jsonb(fgv.*) || jsonb_build_object(${query([
joinedKeys.join(","),
])}) ORDER BY ${fileGroupViewOrderBy(
builder.children.orderBy,
builder.children.orderBySpec,
"fgv.",
)}), NULL) as "result"
])})
${internalQueryFileGroupView(

@@ -752,6 +748,9 @@ builder.children,

)}
GROUP BY fgv2."id"
ORDER BY fgv2."id"
ORDER BY ${fileGroupViewOrderBy(
builder.children.orderBy,
builder.children.orderBySpec,
"fgv.",
)}
${offsetLimitQb}
) as "fgv_fgv_1" ON TRUE`);
) as result) as "fgv_fgv_1" ON TRUE`);
}

@@ -981,9 +980,5 @@ return query`

joinQb.append(query`LEFT JOIN LATERAL (
SELECT array_remove(array_agg(to_jsonb(fgv2.*) || jsonb_build_object(${query([
SELECT ARRAY (SELECT to_jsonb(fgv2.*) || jsonb_build_object(${query([
joinedKeys.join(","),
])}) ORDER BY ${fileGroupViewOrderBy(
builder.children.orderBy,
builder.children.orderBySpec,
"fgv2.",
)}), NULL) as "result"
])})
${internalQueryFileGroupView2(

@@ -993,6 +988,9 @@ builder.children,

)}
GROUP BY fgv."id"
ORDER BY fgv."id"
ORDER BY ${fileGroupViewOrderBy(
builder.children.orderBy,
builder.children.orderBySpec,
"fgv2.",
)}
${offsetLimitQb}
) as "fgv_fgv_1" ON TRUE`);
) as result) as "fgv_fgv_1" ON TRUE`);
}

@@ -999,0 +997,0 @@ return query`

import { createHash } from "crypto";
import { existsSync } from "fs";
import { readdir, readFile } from "fs/promises";
import { pathToFileURL } from "url";
import {
AppError,
dirnameForModule,
environment,
pathJoin,
} from "@compas/stdlib";
import { AppError, environment, pathJoin } from "@compas/stdlib";
/**
* @typedef {object} MigrationFile
* @property {number} number
* @property {boolean} repeatable
* @property {string} name
* @property {string} fullPath
* @property {boolean} isMigrated
* @property {string} source
* @property {string} hash
*/
/**
* Create a new migration context, resolves all migrations and collects the current

@@ -29,22 +34,6 @@ * migration state.

// Automatically add this package to the migrations,
// and make sure it is at the front
const storeMigrationIndex = migrations.namespaces.indexOf("@compas/store");
if (storeMigrationIndex === -1) {
const { migrationFiles, namespaces } = await readMigrationsDir(
`${dirnameForModule(import.meta)}/../migrations`,
"@compas/store",
[],
);
migrations.migrationFiles.push(...migrationFiles);
migrations.namespaces = [].concat(namespaces, migrations.namespaces);
} else if (storeMigrationIndex !== 0) {
migrations.namespaces.splice(storeMigrationIndex, 1);
migrations.namespaces.unshift("@compas/store");
}
const mc = {
files: sortMigrations(migrations.namespaces, migrations.migrationFiles),
namespaces: migrations.namespaces,
files: migrations.sort((a, b) => {
return a.number - b.number;
}),
sql,

@@ -64,2 +53,7 @@ storedHashes: {},

await syncWithSchemaState(mc);
mc.rebuild = () => rebuildMigrations(mc);
mc.info = () => getMigrationsToBeApplied(mc);
mc.do = () => runMigrations(mc);
return mc;

@@ -93,4 +87,11 @@ } catch (error) {

* @returns {{
* migrationQueue: ({ namespace: string, name: string, number: number, repeatable:
* boolean}[]), hashChanges: { name: string, number: number, namespace: string }[]
* migrationQueue: {
* name: string,
* number: number,
* repeatable: boolean
* }[],
* hashChanges: {
* name: string,
* number: number,
* }[]
* }}

@@ -100,3 +101,2 @@ */

const migrationQueue = filterMigrationsToBeApplied(mc).map((it) => ({
namespace: it.namespace,
name: it.name,

@@ -109,8 +109,4 @@ number: it.number,

for (const it of mc.files) {
if (
it.isMigrated &&
mc.storedHashes[`${it.namespace}-${it.number}`] !== it.hash
) {
if (it.isMigrated && mc.storedHashes[it.number] !== it.hash) {
hashChanges.push({
namespace: it.namespace,
name: it.name,

@@ -156,3 +152,2 @@ number: it.number,

message: "Could not run migration",
namespace: current?.namespace,
number: current?.number,

@@ -177,3 +172,36 @@ name: current?.name,

/**
* Rebuild migration table state based on the known migration files
*
* @since 0.1.0
*
* @param {MigrateContext} mc
* @returns {Promise<undefined>}
*/
export async function rebuildMigrations(mc) {
try {
await mc.sql.begin(async (sql) => {
await sql`DELETE FROM "migration" WHERE 1 = 1`;
for (const file of mc.files) {
await runInsert(sql, file);
}
});
} catch (e) {
if ((e.message ?? "").indexOf(`"migration" does not exist`) === -1) {
throw new AppError(
"migrate.rebuild.error",
500,
{
message: "No migrations applied yet, can't rebuild migration table.",
},
e,
);
} else {
throw e;
}
}
}
/**
* @param {MigrateContext} mc
* @returns {MigrateFile[]}

@@ -186,6 +214,3 @@ */

result.push(f);
} else if (
mc.storedHashes[`${f.namespace}-${f.number}`] !== f.hash &&
f.repeatable
) {
} else if (mc.storedHashes[f.number] !== f.hash && f.repeatable) {
result.push(f);

@@ -223,11 +248,5 @@ }

function runInsert(sql, migration) {
return sql`
INSERT INTO migration ${sql(
migration,
"namespace",
"name",
"number",
"hash",
)}
`;
return sql`INSERT INTO "migration" (namespace, number, name, hash) VALUES (${
environment.APP_NAME ?? "compas"
}, ${migration.number}, ${migration.name}, ${migration.hash});`;
}

@@ -243,7 +262,5 @@

rows = await mc.sql`
SELECT DISTINCT ON (namespace, number) namespace,
number,
hash
SELECT DISTINCT ON (number) number, hash
FROM migration
ORDER BY namespace, number, "createdAt" DESC
ORDER BY number, "createdAt" DESC
`;

@@ -264,17 +281,11 @@ } catch (e) {

const migrationData = {};
const numbers = [];
for (const row of rows) {
if (!migrationData[row.namespace]) {
migrationData[row.namespace] = [];
}
migrationData[row.namespace].push(row.number);
numbers.push(Number(row.number));
mc.storedHashes[`${row.namespace}-${row.number}`] = row.hash;
mc.storedHashes[Number(row.number)] = row.hash;
}
for (const mF of mc.files) {
if (
migrationData[mF.namespace] &&
migrationData[mF.namespace].indexOf(mF.number) !== -1
) {
if (numbers.includes(mF.number)) {
mF.isMigrated = true;

@@ -286,3 +297,3 @@ }

/**
* @param sql
* @param {Postgres} sql
*/

@@ -301,7 +312,14 @@ async function acquireLock(sql) {

async function readMigrationFilesForNamespace(
directory,
migrationFiles,
namespace,
) {
/**
*
* @param directory
* @returns {Promise<MigrationFile[]>}
*/
async function readMigrationsDir(directory) {
if (!existsSync(directory)) {
return [];
}
const migrationFiles = [];
const files = await readdir(directory);

@@ -320,3 +338,2 @@

migrationFiles.push({
namespace,
number,

@@ -331,131 +348,7 @@ repeatable,

}
}
/**
*
* @param directory
* @param {string} namespace
* @param {string[]} namespaces
* @returns {Promise<{migrationFiles: [], namespaces: [*]}>}
*/
async function readMigrationsDir(
directory,
namespace = environment.APP_NAME,
namespaces = [],
) {
if (!existsSync(directory)) {
return {
namespaces: [],
migrationFiles: [],
};
}
const migrationFiles = [];
const namespacePath = pathJoin(directory, "namespaces.txt");
if (existsSync(namespacePath)) {
const rawNamespaces = await readFile(namespacePath, "utf-8");
const subNamespaces = rawNamespaces
.split("\n")
.map((it) => it.trim())
.filter((it) => it.length > 0);
for (const ns of subNamespaces) {
// Stop recurse if we already handled it, or if the current namespace is
// fetched again
if (namespaces.includes(ns)) {
continue;
}
if (ns === namespace) {
namespaces.push(ns);
await readMigrationFilesForNamespace(directory, migrationFiles, ns);
continue;
}
// Either same level in node_modules
const directPath = pathJoin(process.cwd(), "node_modules", ns);
// Or a level deeper
const indirectPath = pathJoin(directory, "../node_modules", ns);
const subPath = !existsSync(directPath)
? existsSync(indirectPath)
? indirectPath
: new Error(
`Could not determine import path of '${ns}', while searching for migration files.`,
)
: directPath;
// Quick hack
if (typeof subPath !== "string") {
throw subPath;
}
// Use the package.json to find the package entrypoint
// Only supporting simple { exports: "file.js" }, { exports: { default:
// "file.js" } or { main: "file.js" }
const subPackageJson = JSON.parse(
await readFile(pathJoin(subPath, "package.json"), "utf8"),
);
const exportedItems = await import(
pathToFileURL(
pathJoin(
subPath,
subPackageJson?.exports?.default ??
(typeof subPackageJson?.exports === "string"
? subPackageJson?.exports
: undefined) ??
subPackageJson?.main ??
"index.js",
),
)
);
if (exportedItems && exportedItems.migrations) {
const subResult = await readMigrationsDir(
exportedItems.migrations,
ns,
namespaces,
);
migrationFiles.push(...subResult.migrationFiles);
}
}
}
// We might have loaded the migration files already
if (namespaces.includes(namespace)) {
return {
migrationFiles,
namespaces,
};
}
namespaces.push(namespace);
await readMigrationFilesForNamespace(directory, migrationFiles, namespace);
return {
migrationFiles,
namespaces,
};
return migrationFiles;
}
/**
* @param namespaces
* @param files
*/
function sortMigrations(namespaces, files) {
return files.sort((a, b) => {
const namespaceResult =
namespaces.indexOf(a.namespace) - namespaces.indexOf(b.namespace);
if (namespaceResult !== 0) {
return namespaceResult;
}
return a.number < b.number;
});
}
/**
* @param fileName

@@ -473,3 +366,2 @@ */

filePattern.lastIndex = 0;
if (!filePattern.test(fileName)) {

@@ -476,0 +368,0 @@ throw new Error(

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