@augment-vir/node 30.0.1 → 30.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,3 +19,21 @@ export declare enum OperatingSystem {
19
19
  * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
20
20
  */
21
21
  export declare const currentOperatingSystem: OperatingSystem;
22
+ /**
23
+ * Checks if the current operating system is the requested one.
24
+ *
25
+ * @category Node : OS
26
+ * @category Package : @augment-vir/node
27
+ * @example
28
+ *
29
+ * ```ts
30
+ * import {isOperatingSystem, OperatingSystem} from '@augment-vir/node';
31
+ *
32
+ * if (isOperatingSystem(OperatingSystem.Mac)) {
33
+ * // do something
34
+ * }
35
+ * ```
36
+ *
37
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
38
+ */
39
+ export declare function isOperatingSystem(operatingSystem: OperatingSystem): boolean;
@@ -20,6 +20,26 @@ export var OperatingSystem;
20
20
  * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
21
21
  */
22
22
  export const currentOperatingSystem = getOperatingSystem();
23
+ /**
24
+ * Checks if the current operating system is the requested one.
25
+ *
26
+ * @category Node : OS
27
+ * @category Package : @augment-vir/node
28
+ * @example
29
+ *
30
+ * ```ts
31
+ * import {isOperatingSystem, OperatingSystem} from '@augment-vir/node';
32
+ *
33
+ * if (isOperatingSystem(OperatingSystem.Mac)) {
34
+ * // do something
35
+ * }
36
+ * ```
37
+ *
38
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
39
+ */
40
+ export function isOperatingSystem(operatingSystem) {
41
+ return currentOperatingSystem === operatingSystem;
42
+ }
23
43
  function getOperatingSystem() {
24
44
  /** We can't test all of these on a single system. */
25
45
  /* node:coverage ignore next 7 */
@@ -1,6 +1,8 @@
1
+ import { addData, dumpData, getAllPrismaModelNames } from '../prisma/model-data.js';
1
2
  import { generatePrismaClient, isGeneratedPrismaClientCurrent } from '../prisma/prisma-client.js';
2
3
  import { doesPrismaDiffExist, getPrismaDiff, resetDevPrismaDatabase } from '../prisma/prisma-database.js';
3
4
  import { applyPrismaMigrationsToDev, applyPrismaMigrationsToProd, createPrismaMigration, getMigrationStatus } from '../prisma/prisma-migrations.js';
5
+ export type { PrismaAddDataData as PrismaAddModelData, PrismaDataDumpOptions, } from '../prisma/model-data.js';
4
6
  export * from '../prisma/prisma-errors.js';
5
7
  export type { PrismaMigrationStatus } from '../prisma/prisma-migrations.js';
6
8
  /**
@@ -84,6 +86,14 @@ export declare const prisma: {
84
86
  /**
85
87
  * Runs Prisma generators included in the given Prisma schema (which usually includes the
86
88
  * Prisma JS client). This will work even if the database doesn't exist yet.
89
+ *
90
+ * @example
91
+ *
92
+ * ```ts
93
+ * import {prisma} from '@augment-vir/node';
94
+ *
95
+ * prisma.client.generate('../../prisma/schema.prisma');
96
+ * ```
87
97
  */
88
98
  generate: typeof generatePrismaClient;
89
99
  /**
@@ -91,5 +101,57 @@ export declare const prisma: {
91
101
  * schema.
92
102
  */
93
103
  isCurrent: typeof isGeneratedPrismaClientCurrent;
104
+ /**
105
+ * Adds a collection of create data to a database through a `PrismaClient` instance. This is
106
+ * particularly useful for setting up mocks in a mock PrismaClient.
107
+ *
108
+ * @example
109
+ *
110
+ * ```ts
111
+ * import {addPrismaModelData} from '@augment-vir/common';
112
+ * import {PrismaClient} from '@prisma/client';
113
+ *
114
+ * await addPrismaModelData(new PrismaClient(), [
115
+ * {
116
+ * user: {
117
+ * mockUser1: {
118
+ * first_name: 'one',
119
+ * id: 123,
120
+ * // etc.
121
+ * },
122
+ * mockUser2: {
123
+ * first_name: 'two',
124
+ * id: 124,
125
+ * authRole: 'user',
126
+ * // etc.
127
+ * },
128
+ * },
129
+ * },
130
+ * {
131
+ * region: [
132
+ * {
133
+ * id: 1,
134
+ * name: 'North America',
135
+ * // etc.
136
+ * },
137
+ * {
138
+ * id: 2,
139
+ * name: 'Europe',
140
+ * // etc.
141
+ * },
142
+ * ],
143
+ * },
144
+ * ]);
145
+ * ```
146
+ */
147
+ addData: typeof addData;
148
+ /**
149
+ * Dump data from the current database through a `PrismaClient` instance.
150
+ *
151
+ * @see {@link PrismaDataDumpOptions}
152
+ */
153
+ dumpData: typeof dumpData;
154
+ /** List all model names in the given Prisma client. */
155
+ listModelNames: typeof getAllPrismaModelNames;
94
156
  };
95
157
  };
@@ -1,3 +1,4 @@
1
+ import { addData, dumpData, getAllPrismaModelNames } from '../prisma/model-data.js';
1
2
  import { generatePrismaClient, isGeneratedPrismaClientCurrent } from '../prisma/prisma-client.js';
2
3
  import { doesPrismaDiffExist, getPrismaDiff, resetDevPrismaDatabase, } from '../prisma/prisma-database.js';
3
4
  import { applyPrismaMigrationsToDev, applyPrismaMigrationsToProd, createPrismaMigration, getMigrationStatus, } from '../prisma/prisma-migrations.js';
@@ -83,6 +84,14 @@ export const prisma = {
83
84
  /**
84
85
  * Runs Prisma generators included in the given Prisma schema (which usually includes the
85
86
  * Prisma JS client). This will work even if the database doesn't exist yet.
87
+ *
88
+ * @example
89
+ *
90
+ * ```ts
91
+ * import {prisma} from '@augment-vir/node';
92
+ *
93
+ * prisma.client.generate('../../prisma/schema.prisma');
94
+ * ```
86
95
  */
87
96
  generate: generatePrismaClient,
88
97
  /**
@@ -90,5 +99,57 @@ export const prisma = {
90
99
  * schema.
91
100
  */
92
101
  isCurrent: isGeneratedPrismaClientCurrent,
102
+ /**
103
+ * Adds a collection of create data to a database through a `PrismaClient` instance. This is
104
+ * particularly useful for setting up mocks in a mock PrismaClient.
105
+ *
106
+ * @example
107
+ *
108
+ * ```ts
109
+ * import {addPrismaModelData} from '@augment-vir/common';
110
+ * import {PrismaClient} from '@prisma/client';
111
+ *
112
+ * await addPrismaModelData(new PrismaClient(), [
113
+ * {
114
+ * user: {
115
+ * mockUser1: {
116
+ * first_name: 'one',
117
+ * id: 123,
118
+ * // etc.
119
+ * },
120
+ * mockUser2: {
121
+ * first_name: 'two',
122
+ * id: 124,
123
+ * authRole: 'user',
124
+ * // etc.
125
+ * },
126
+ * },
127
+ * },
128
+ * {
129
+ * region: [
130
+ * {
131
+ * id: 1,
132
+ * name: 'North America',
133
+ * // etc.
134
+ * },
135
+ * {
136
+ * id: 2,
137
+ * name: 'Europe',
138
+ * // etc.
139
+ * },
140
+ * ],
141
+ * },
142
+ * ]);
143
+ * ```
144
+ */
145
+ addData: addData,
146
+ /**
147
+ * Dump data from the current database through a `PrismaClient` instance.
148
+ *
149
+ * @see {@link PrismaDataDumpOptions}
150
+ */
151
+ dumpData: dumpData,
152
+ /** List all model names in the given Prisma client. */
153
+ listModelNames: getAllPrismaModelNames,
93
154
  },
94
155
  };
@@ -21,7 +21,9 @@ export async function removeImageFromLocalRegistry(
21
21
  /** @example 'alpine:3.20.2' */
22
22
  imageName) {
23
23
  try {
24
- await runShellCommand(`docker image rm '${imageName}'`, { rejectOnError: true });
24
+ await runShellCommand(`docker image rm '${imageName}'`, {
25
+ rejectOnError: true,
26
+ });
25
27
  }
26
28
  catch (caught) {
27
29
  const error = ensureError(caught);
@@ -0,0 +1,2 @@
1
+ import type { MaybePromise } from '@augment-vir/common';
2
+ export declare function dockerTest(callback: () => MaybePromise<void>): () => MaybePromise<void>;
@@ -0,0 +1,16 @@
1
+ import { isOperatingSystem, OperatingSystem } from '../augments/os/operating-system.js';
2
+ export function dockerTest(callback) {
3
+ if (isOperatingSystem(OperatingSystem.Mac) && process.env.CI) {
4
+ /**
5
+ * We cannot test Docker on macOS GitHub Actions runners.
6
+ *
7
+ * @see
8
+ * - https://github.com/actions/runner-images/issues/8104
9
+ * - https://github.com/douglascamata/setup-docker-macos-action?tab=readme-ov-file#arm64-processors-m1-m2-m3-series-used-on-macos-14-images-are-unsupported
10
+ * - https://github.com/actions/runner-images/issues/2150
11
+ * - https://github.com/actions/runner/issues/1456
12
+ */
13
+ return () => { };
14
+ }
15
+ return callback;
16
+ }
@@ -0,0 +1,2 @@
1
+ import { type MaybePromise } from '@augment-vir/common';
2
+ export declare function testWithNonCiEnv(callback: () => MaybePromise<void>): () => Promise<void>;
@@ -0,0 +1,81 @@
1
+ // cspell:disable
2
+ import { arrayToObject } from '@augment-vir/common';
3
+ /**
4
+ * These are all the env flags that Prisma reads for determining if it's being executed within a CI
5
+ * environment. This list was retrieved from
6
+ * https://github.com/prisma/prisma/blob/075d31287c90b757fd9bd8d9b36032e6349fa671/packages/internals/src/utils/isCi.ts.
7
+ */
8
+ const prismaCiFlags = [
9
+ 'CI',
10
+ 'CONTINUOUS_INTEGRATION',
11
+ 'BUILD_NUMBER',
12
+ 'RUN_ID',
13
+ 'AGOLA_GIT_REF',
14
+ 'AC_APPCIRCLE',
15
+ 'APPVEYOR',
16
+ 'CODEBUILD',
17
+ 'TF_BUILD',
18
+ 'bamboo_planKey',
19
+ 'BITBUCKET_COMMIT',
20
+ 'BITRISE_IO',
21
+ 'BUDDY_WORKSPACE_ID',
22
+ 'BUILDKITE',
23
+ 'CIRCLECI',
24
+ 'CIRRUS_CI',
25
+ 'CF_BUILD_ID',
26
+ 'CM_BUILD_ID',
27
+ 'CI_NAME',
28
+ 'DRONE',
29
+ 'DSARI',
30
+ 'EARTHLY_CI',
31
+ 'EAS_BUILD',
32
+ 'GERRIT_PROJECT',
33
+ 'GITEA_ACTIONS',
34
+ 'GITHUB_ACTIONS',
35
+ 'GITLAB_CI',
36
+ 'GOCD',
37
+ 'BUILDER_OUTPUT',
38
+ 'HARNESS_BUILD_ID',
39
+ 'JENKINS_URL',
40
+ 'BUILD_ID',
41
+ 'LAYERCI',
42
+ 'MAGNUM',
43
+ 'NETLIFY',
44
+ 'NEVERCODE',
45
+ 'PROW_JOB_ID',
46
+ 'RELEASE_BUILD_ID',
47
+ 'RENDER',
48
+ 'SAILCI',
49
+ 'HUDSON',
50
+ 'JENKINS_URL',
51
+ 'BUILD_ID',
52
+ 'SCREWDRIVER',
53
+ 'SEMAPHORE',
54
+ 'SOURCEHUT',
55
+ 'STRIDER',
56
+ 'TASK_ID',
57
+ 'RUN_ID',
58
+ 'TEAMCITY_VERSION',
59
+ 'TRAVIS',
60
+ 'VELA',
61
+ 'NOW_BUILDER',
62
+ 'APPCENTER_BUILD_ID',
63
+ 'CI_XCODE_PROJECT',
64
+ 'XCS',
65
+ ];
66
+ export function testWithNonCiEnv(callback) {
67
+ return async () => {
68
+ const usedKeys = prismaCiFlags.filter((ciFlag) => ciFlag in process.env);
69
+ /** For already non-CI environments. */
70
+ /* node:coverage ignore next 6 */
71
+ const originalEnvValues = arrayToObject(usedKeys, (key) => {
72
+ return {
73
+ key,
74
+ value: process.env[key],
75
+ };
76
+ });
77
+ usedKeys.forEach((key) => delete process.env[key]);
78
+ await callback();
79
+ usedKeys.forEach((key) => (process.env[key] = originalEnvValues[key]));
80
+ };
81
+ }
@@ -0,0 +1,73 @@
1
+ import { BasePrismaClient, PrismaAllModelsCreate, type PartialWithUndefined, type PrismaAllBasicModels, type PrismaModelName } from '@augment-vir/common';
2
+ /**
3
+ * Params for {@link addData}. This is similar to {@link PrismaAllModelsCreate} but allows an array of
4
+ * {@link PrismaAllModelsCreate} for sequential data creation.
5
+ *
6
+ * @category Prisma : Node
7
+ * @category Package : @augment-vir/node
8
+ * @example
9
+ *
10
+ * ```ts
11
+ * import {PrismaAddModelData} from '@augment-vir/common';
12
+ * import type {PrismaClient} from '@prisma/client';
13
+ *
14
+ * const mockData: PrismaAddModelData<PrismaClient> = [
15
+ * {
16
+ * user: {
17
+ * mockUser1: {
18
+ * first_name: 'one',
19
+ * id: 123,
20
+ * // etc.
21
+ * },
22
+ * mockUser2: {
23
+ * first_name: 'two',
24
+ * id: 124,
25
+ * authRole: 'user',
26
+ * // etc.
27
+ * },
28
+ * },
29
+ * },
30
+ * {
31
+ * region: [
32
+ * {
33
+ * id: 1,
34
+ * name: 'North America',
35
+ * // etc.
36
+ * },
37
+ * {
38
+ * id: 2,
39
+ * name: 'Europe',
40
+ * // etc.
41
+ * },
42
+ * ],
43
+ * },
44
+ * ];
45
+ * ```
46
+ *
47
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
48
+ */
49
+ export type PrismaAddDataData<PrismaClient extends BasePrismaClient> = Readonly<PrismaAllModelsCreate<PrismaClient>> | ReadonlyArray<Readonly<PrismaAllModelsCreate<PrismaClient>>>;
50
+ export declare function addData<const PrismaClient extends BasePrismaClient>(prismaClient: Readonly<PrismaClient>, data: PrismaAddDataData<PrismaClient>): Promise<void>;
51
+ export declare function getAllPrismaModelNames<const PrismaClient extends BasePrismaClient>(prismaClient: PrismaClient): PrismaModelName<PrismaClient>[];
52
+ /**
53
+ * Options for `prisma.client.dumpData`.
54
+ *
55
+ * @category Prisma : Node
56
+ * @category Package : @augment-vir/node
57
+ * @package [`@augment-vir/node`](https://www.npmjs.com/package/@augment-vir/node)
58
+ */
59
+ export type PrismaDataDumpOptions = {
60
+ /**
61
+ * The max number of entries to load per model. Set to `0` to remove this limit altogether
62
+ * (which could be _very_ expensive for your database).
63
+ *
64
+ * @default 100
65
+ */
66
+ limit: number;
67
+ /**
68
+ * Strings to omit from the dumped data. For testability, omitting date or UUID id fields is a
69
+ * common practice.
70
+ */
71
+ omitFields: string[];
72
+ };
73
+ export declare function dumpData<const PrismaClient extends BasePrismaClient>(prismaClient: PrismaClient, options?: Readonly<PartialWithUndefined<PrismaDataDumpOptions>>): Promise<PrismaAllBasicModels<PrismaClient>>;
@@ -0,0 +1,70 @@
1
+ import { assert, check } from '@augment-vir/assert';
2
+ import { arrayToObject, awaitedForEach, ensureErrorAndPrependMessage, filterMap, getObjectTypedEntries, getObjectTypedValues, mergeDefinedProperties, omitObjectKeys, prismaModelCreateExclude, prismaModelCreateOmitId, } from '@augment-vir/common';
3
+ export async function addData(prismaClient, data) {
4
+ const dataArray = (check.isArray(data) ? data : [data]);
5
+ await awaitedForEach(dataArray, async (dataEntry) => {
6
+ await addModelDataObject(prismaClient, dataEntry);
7
+ });
8
+ }
9
+ async function addModelDataObject(prismaClient, data) {
10
+ /** Add the mock data to the mock prisma client. */
11
+ await awaitedForEach(getObjectTypedEntries(data), async ([modelName, mockData,]) => {
12
+ /**
13
+ * This type is dumbed down to just `AnyObject[]` because the union of all possible
14
+ * model data is just way too big (and not helpful as the inputs to this function are
15
+ * already type guarded).
16
+ */
17
+ const mockModelInstances = Array.isArray(mockData)
18
+ ? mockData
19
+ : getObjectTypedValues(mockData);
20
+ const modelApi = prismaClient[modelName];
21
+ assert.isDefined(modelApi, `No PrismaClient API found for model '${modelName}'`);
22
+ try {
23
+ const allData = filterMap(mockModelInstances, (entry) => {
24
+ return entry;
25
+ }, (mapped, modelEntry) => !modelEntry[prismaModelCreateExclude]);
26
+ await awaitedForEach(allData, async (modelEntry) => {
27
+ if (modelEntry[prismaModelCreateOmitId]) {
28
+ modelEntry = omitObjectKeys(modelEntry, ['id']);
29
+ }
30
+ await modelApi.create({
31
+ data: modelEntry,
32
+ });
33
+ });
34
+ }
35
+ catch (error) {
36
+ throw ensureErrorAndPrependMessage(error, `Failed to create many '${modelName}' entries.\n\n${JSON.stringify(mockModelInstances, null, 4)}\n\n`);
37
+ }
38
+ });
39
+ }
40
+ export function getAllPrismaModelNames(prismaClient) {
41
+ return Object.keys(prismaClient)
42
+ .filter((key) => !key.startsWith('$') && !key.startsWith('_'))
43
+ .sort();
44
+ }
45
+ const defaultPrismaDumpDataOptions = {
46
+ limit: 100,
47
+ omitFields: [],
48
+ };
49
+ export async function dumpData(prismaClient, options = {}) {
50
+ const modelNames = getAllPrismaModelNames(prismaClient);
51
+ const finalOptions = mergeDefinedProperties(defaultPrismaDumpDataOptions, options);
52
+ const data = await arrayToObject(modelNames, async (modelName) => {
53
+ const entries = await prismaClient[modelName].findMany(finalOptions.limit > 0
54
+ ? {
55
+ take: finalOptions.limit,
56
+ }
57
+ : {});
58
+ if (!entries.length) {
59
+ return undefined;
60
+ }
61
+ const filteredEntries = finalOptions.omitFields.length
62
+ ? entries.map((entry) => omitObjectKeys(entry, finalOptions.omitFields))
63
+ : entries;
64
+ return {
65
+ key: modelName,
66
+ value: filteredEntries,
67
+ };
68
+ });
69
+ return data;
70
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@augment-vir/node",
3
- "version": "30.0.1",
3
+ "version": "30.0.2",
4
4
  "description": "A collection of augments, helpers types, functions, and classes only for Node.js (backend) JavaScript environments.",
5
5
  "keywords": [
6
6
  "augment",
@@ -37,27 +37,27 @@
37
37
  "test:update": "npm test"
38
38
  },
39
39
  "dependencies": {
40
- "@augment-vir/assert": "^30.0.1",
41
- "@augment-vir/common": "^30.0.1",
40
+ "@augment-vir/assert": "^30.0.2",
41
+ "@augment-vir/common": "^30.0.2",
42
42
  "@date-vir/duration": "^6.0.0",
43
43
  "ansi-styles": "^6.2.1",
44
44
  "terminate": "^2.8.0",
45
- "type-fest": "^4.25.0",
45
+ "type-fest": "^4.26.1",
46
46
  "typed-event-target": "^3.4.0"
47
47
  },
48
48
  "devDependencies": {
49
- "@augment-vir/test": "^30.0.1",
50
- "@prisma/client": "^5.19.0",
51
- "@types/node": "^22.5.0",
49
+ "@augment-vir/test": "^30.0.2",
50
+ "@prisma/client": "^5.19.1",
51
+ "@types/node": "^22.5.4",
52
52
  "@web/dev-server-esbuild": "^1.0.2",
53
- "@web/test-runner": "^0.18.3",
53
+ "@web/test-runner": "^0.19.0",
54
54
  "@web/test-runner-commands": "^0.9.0",
55
55
  "@web/test-runner-playwright": "^0.11.0",
56
- "@web/test-runner-visual-regression": "^0.9.0",
56
+ "@web/test-runner-visual-regression": "^0.10.0",
57
57
  "c8": "^10.1.2",
58
- "concurrently": "^8.2.2",
58
+ "concurrently": "^9.0.0",
59
59
  "istanbul-smart-text-reporter": "^1.1.4",
60
- "prisma": "^5.19.0"
60
+ "prisma": "^5.19.1"
61
61
  },
62
62
  "engines": {
63
63
  "node": ">=22"