@expo/entity-database-adapter-knex 0.44.0 → 0.45.0
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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expo/entity-database-adapter-knex",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.45.0",
|
|
4
4
|
"description": "Knex database adapter for @expo/entity",
|
|
5
5
|
"files": [
|
|
6
6
|
"build",
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
"author": "Expo",
|
|
29
29
|
"license": "MIT",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@expo/entity": "^0.
|
|
31
|
+
"@expo/entity": "^0.45.0",
|
|
32
32
|
"knex": "^3.1.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@expo/entity-testing-utils": "^0.
|
|
35
|
+
"@expo/entity-testing-utils": "^0.45.0",
|
|
36
36
|
"@types/jest": "^29.5.14",
|
|
37
37
|
"@types/node": "^20.14.1",
|
|
38
38
|
"ctix": "^2.7.0",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"ts-mockito": "^2.6.1",
|
|
48
48
|
"typescript": "^5.8.3"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "fe2d246f87adc98a13cc7c1ae57f3628769560c9"
|
|
51
51
|
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { createWithUniqueConstraintRecoveryAsync, ViewerContext } from '@expo/entity';
|
|
2
|
+
import knex, { Knex } from 'knex';
|
|
3
|
+
import nullthrows from 'nullthrows';
|
|
4
|
+
|
|
5
|
+
import PostgresUniqueTestEntity from '../__testfixtures__/PostgresUniqueTestEntity';
|
|
6
|
+
import { createKnexIntegrationTestEntityCompanionProvider } from '../__testfixtures__/createKnexIntegrationTestEntityCompanionProvider';
|
|
7
|
+
|
|
8
|
+
describe(createWithUniqueConstraintRecoveryAsync, () => {
|
|
9
|
+
let knexInstance: Knex;
|
|
10
|
+
|
|
11
|
+
beforeAll(() => {
|
|
12
|
+
knexInstance = knex({
|
|
13
|
+
client: 'pg',
|
|
14
|
+
connection: {
|
|
15
|
+
user: nullthrows(process.env['PGUSER']),
|
|
16
|
+
password: nullthrows(process.env['PGPASSWORD']),
|
|
17
|
+
host: 'localhost',
|
|
18
|
+
port: parseInt(nullthrows(process.env['PGPORT']), 10),
|
|
19
|
+
database: nullthrows(process.env['PGDATABASE']),
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
beforeEach(async () => {
|
|
25
|
+
await PostgresUniqueTestEntity.createOrTruncatePostgresTableAsync(knexInstance);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
afterAll(async () => {
|
|
29
|
+
await PostgresUniqueTestEntity.dropPostgresTableAsync(knexInstance);
|
|
30
|
+
await knexInstance.destroy();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe.each([true, false])('is parallel creations %p', (parallel) => {
|
|
34
|
+
it('recovers when the same entity is created twice outside of transaction', async () => {
|
|
35
|
+
const vc1 = new ViewerContext(createKnexIntegrationTestEntityCompanionProvider(knexInstance));
|
|
36
|
+
|
|
37
|
+
const args = {
|
|
38
|
+
name: 'unique',
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
let createdEntities: [PostgresUniqueTestEntity, PostgresUniqueTestEntity];
|
|
42
|
+
if (parallel) {
|
|
43
|
+
createdEntities = await Promise.all([
|
|
44
|
+
createWithUniqueConstraintRecoveryAsync(
|
|
45
|
+
vc1,
|
|
46
|
+
PostgresUniqueTestEntity,
|
|
47
|
+
PostgresUniqueTestEntity.getByNameAsync,
|
|
48
|
+
args,
|
|
49
|
+
PostgresUniqueTestEntity.createWithNameAsync,
|
|
50
|
+
args,
|
|
51
|
+
),
|
|
52
|
+
createWithUniqueConstraintRecoveryAsync(
|
|
53
|
+
vc1,
|
|
54
|
+
PostgresUniqueTestEntity,
|
|
55
|
+
PostgresUniqueTestEntity.getByNameAsync,
|
|
56
|
+
args,
|
|
57
|
+
PostgresUniqueTestEntity.createWithNameAsync,
|
|
58
|
+
args,
|
|
59
|
+
),
|
|
60
|
+
]);
|
|
61
|
+
} else {
|
|
62
|
+
createdEntities = [
|
|
63
|
+
await createWithUniqueConstraintRecoveryAsync(
|
|
64
|
+
vc1,
|
|
65
|
+
PostgresUniqueTestEntity,
|
|
66
|
+
PostgresUniqueTestEntity.getByNameAsync,
|
|
67
|
+
args,
|
|
68
|
+
PostgresUniqueTestEntity.createWithNameAsync,
|
|
69
|
+
args,
|
|
70
|
+
),
|
|
71
|
+
await createWithUniqueConstraintRecoveryAsync(
|
|
72
|
+
vc1,
|
|
73
|
+
PostgresUniqueTestEntity,
|
|
74
|
+
PostgresUniqueTestEntity.getByNameAsync,
|
|
75
|
+
args,
|
|
76
|
+
PostgresUniqueTestEntity.createWithNameAsync,
|
|
77
|
+
args,
|
|
78
|
+
),
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
expect(createdEntities[0].getID()).toEqual(createdEntities[1].getID());
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('recovers when the same entity is created twice within same transaction', async () => {
|
|
86
|
+
const vc1 = new ViewerContext(createKnexIntegrationTestEntityCompanionProvider(knexInstance));
|
|
87
|
+
|
|
88
|
+
const args = {
|
|
89
|
+
name: 'unique',
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const createdEntities = await vc1.runInTransactionForDatabaseAdaptorFlavorAsync(
|
|
93
|
+
'postgres',
|
|
94
|
+
async (queryContext) => {
|
|
95
|
+
if (parallel) {
|
|
96
|
+
return await Promise.all([
|
|
97
|
+
createWithUniqueConstraintRecoveryAsync(
|
|
98
|
+
vc1,
|
|
99
|
+
PostgresUniqueTestEntity,
|
|
100
|
+
PostgresUniqueTestEntity.getByNameAsync,
|
|
101
|
+
args,
|
|
102
|
+
PostgresUniqueTestEntity.createWithNameAsync,
|
|
103
|
+
args,
|
|
104
|
+
queryContext,
|
|
105
|
+
),
|
|
106
|
+
createWithUniqueConstraintRecoveryAsync(
|
|
107
|
+
vc1,
|
|
108
|
+
PostgresUniqueTestEntity,
|
|
109
|
+
PostgresUniqueTestEntity.getByNameAsync,
|
|
110
|
+
args,
|
|
111
|
+
PostgresUniqueTestEntity.createWithNameAsync,
|
|
112
|
+
args,
|
|
113
|
+
queryContext,
|
|
114
|
+
),
|
|
115
|
+
]);
|
|
116
|
+
} else {
|
|
117
|
+
return [
|
|
118
|
+
await createWithUniqueConstraintRecoveryAsync(
|
|
119
|
+
vc1,
|
|
120
|
+
PostgresUniqueTestEntity,
|
|
121
|
+
PostgresUniqueTestEntity.getByNameAsync,
|
|
122
|
+
args,
|
|
123
|
+
PostgresUniqueTestEntity.createWithNameAsync,
|
|
124
|
+
args,
|
|
125
|
+
queryContext,
|
|
126
|
+
),
|
|
127
|
+
await createWithUniqueConstraintRecoveryAsync(
|
|
128
|
+
vc1,
|
|
129
|
+
PostgresUniqueTestEntity,
|
|
130
|
+
PostgresUniqueTestEntity.getByNameAsync,
|
|
131
|
+
args,
|
|
132
|
+
PostgresUniqueTestEntity.createWithNameAsync,
|
|
133
|
+
args,
|
|
134
|
+
queryContext,
|
|
135
|
+
),
|
|
136
|
+
];
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
expect(nullthrows(createdEntities[0]).getID()).toEqual(
|
|
142
|
+
nullthrows(createdEntities[1]).getID(),
|
|
143
|
+
);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('recovers when the same entity is created twice within two transactions', async () => {
|
|
147
|
+
const vc1 = new ViewerContext(createKnexIntegrationTestEntityCompanionProvider(knexInstance));
|
|
148
|
+
|
|
149
|
+
const args = {
|
|
150
|
+
name: 'unique',
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
let createdEntities: [PostgresUniqueTestEntity, PostgresUniqueTestEntity];
|
|
154
|
+
if (parallel) {
|
|
155
|
+
createdEntities = await Promise.all([
|
|
156
|
+
await vc1.runInTransactionForDatabaseAdaptorFlavorAsync(
|
|
157
|
+
'postgres',
|
|
158
|
+
async (queryContext) => {
|
|
159
|
+
return await createWithUniqueConstraintRecoveryAsync(
|
|
160
|
+
vc1,
|
|
161
|
+
PostgresUniqueTestEntity,
|
|
162
|
+
PostgresUniqueTestEntity.getByNameAsync,
|
|
163
|
+
args,
|
|
164
|
+
PostgresUniqueTestEntity.createWithNameAsync,
|
|
165
|
+
args,
|
|
166
|
+
queryContext,
|
|
167
|
+
);
|
|
168
|
+
},
|
|
169
|
+
),
|
|
170
|
+
await vc1.runInTransactionForDatabaseAdaptorFlavorAsync(
|
|
171
|
+
'postgres',
|
|
172
|
+
async (queryContext) => {
|
|
173
|
+
return await createWithUniqueConstraintRecoveryAsync(
|
|
174
|
+
vc1,
|
|
175
|
+
PostgresUniqueTestEntity,
|
|
176
|
+
PostgresUniqueTestEntity.getByNameAsync,
|
|
177
|
+
args,
|
|
178
|
+
PostgresUniqueTestEntity.createWithNameAsync,
|
|
179
|
+
args,
|
|
180
|
+
queryContext,
|
|
181
|
+
);
|
|
182
|
+
},
|
|
183
|
+
),
|
|
184
|
+
]);
|
|
185
|
+
} else {
|
|
186
|
+
createdEntities = [
|
|
187
|
+
await vc1.runInTransactionForDatabaseAdaptorFlavorAsync(
|
|
188
|
+
'postgres',
|
|
189
|
+
async (queryContext) => {
|
|
190
|
+
return await createWithUniqueConstraintRecoveryAsync(
|
|
191
|
+
vc1,
|
|
192
|
+
PostgresUniqueTestEntity,
|
|
193
|
+
PostgresUniqueTestEntity.getByNameAsync,
|
|
194
|
+
args,
|
|
195
|
+
PostgresUniqueTestEntity.createWithNameAsync,
|
|
196
|
+
args,
|
|
197
|
+
queryContext,
|
|
198
|
+
);
|
|
199
|
+
},
|
|
200
|
+
),
|
|
201
|
+
await vc1.runInTransactionForDatabaseAdaptorFlavorAsync(
|
|
202
|
+
'postgres',
|
|
203
|
+
async (queryContext) => {
|
|
204
|
+
return await createWithUniqueConstraintRecoveryAsync(
|
|
205
|
+
vc1,
|
|
206
|
+
PostgresUniqueTestEntity,
|
|
207
|
+
PostgresUniqueTestEntity.getByNameAsync,
|
|
208
|
+
args,
|
|
209
|
+
PostgresUniqueTestEntity.createWithNameAsync,
|
|
210
|
+
args,
|
|
211
|
+
queryContext,
|
|
212
|
+
);
|
|
213
|
+
},
|
|
214
|
+
),
|
|
215
|
+
];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
expect(nullthrows(createdEntities[0]).getID()).toEqual(
|
|
219
|
+
nullthrows(createdEntities[1]).getID(),
|
|
220
|
+
);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
});
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
EntityCompanionDefinition,
|
|
8
8
|
Entity,
|
|
9
9
|
UUIDField,
|
|
10
|
+
EntityTransactionalQueryContext,
|
|
10
11
|
} from '@expo/entity';
|
|
11
12
|
import { Knex } from 'knex';
|
|
12
13
|
|
|
@@ -53,6 +54,27 @@ export default class PostgresUniqueTestEntity extends Entity<
|
|
|
53
54
|
await knex.schema.dropTable(tableName);
|
|
54
55
|
}
|
|
55
56
|
}
|
|
57
|
+
|
|
58
|
+
public static async getByNameAsync(
|
|
59
|
+
viewerContext: ViewerContext,
|
|
60
|
+
args: { name: string },
|
|
61
|
+
queryContext?: EntityTransactionalQueryContext,
|
|
62
|
+
): Promise<PostgresUniqueTestEntity | null> {
|
|
63
|
+
return await PostgresUniqueTestEntity.loader(
|
|
64
|
+
viewerContext,
|
|
65
|
+
queryContext,
|
|
66
|
+
).loadByFieldEqualingAsync('name', args.name);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public static async createWithNameAsync(
|
|
70
|
+
viewerContext: ViewerContext,
|
|
71
|
+
args: { name: string },
|
|
72
|
+
queryContext?: EntityTransactionalQueryContext,
|
|
73
|
+
): Promise<PostgresUniqueTestEntity> {
|
|
74
|
+
return await PostgresUniqueTestEntity.creator(viewerContext, queryContext)
|
|
75
|
+
.setField('name', args.name)
|
|
76
|
+
.createAsync();
|
|
77
|
+
}
|
|
56
78
|
}
|
|
57
79
|
|
|
58
80
|
class PostgresUniqueTestEntityPrivacyPolicy extends EntityPrivacyPolicy<
|
|
@@ -108,6 +130,7 @@ export const postgresTestEntityConfiguration = new EntityConfiguration<
|
|
|
108
130
|
}),
|
|
109
131
|
name: new StringField({
|
|
110
132
|
columnName: 'name',
|
|
133
|
+
cache: true,
|
|
111
134
|
}),
|
|
112
135
|
},
|
|
113
136
|
databaseAdapterFlavor: 'postgres',
|